kpilot

pilotDateEntry.cc

Go to the documentation of this file.
00001 /* KPilot
00002 **
00003 ** Copyright (C) 1998-2001 by Dan Pilone
00004 ** Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 **
00006 ** This is a C++ wrapper for the Pilot's datebook structures.
00007 */
00008 
00009 /*
00010 ** This program is free software; you can redistribute it and/or modify
00011 ** it under the terms of the GNU Lesser General Public License as published by
00012 ** the Free Software Foundation; either version 2.1 of the License, or
00013 ** (at your option) any later version.
00014 **
00015 ** This program is distributed in the hope that it will be useful,
00016 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 ** GNU Lesser General Public License for more details.
00019 **
00020 ** You should have received a copy of the GNU Lesser General Public License
00021 ** along with this program in a file called COPYING; if not, write to
00022 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00023 ** MA 02110-1301, USA.
00024 */
00025 
00026 /*
00027 ** Bug reports and questions can be sent to kde-pim@kde.org
00028 */
00029 
00030 #include "options.h"
00031 
00032 #include <stdlib.h>
00033 
00034 #include <qdatetime.h>
00035 #include <qnamespace.h>
00036 #include <qregexp.h>
00037 
00038 #include <kglobal.h>
00039 
00040 #include "pilotDateEntry.h"
00041 
00042 static const char *default_date_category_names[] = {
00043     "Unfiled",
00044     "Business",
00045     "Personal",
00046     0L
00047 } ;
00048 
00049 void PilotDateInfo::resetToDefault()
00050 {
00051     FUNCTIONSETUP;
00052     // Reset to all 0s
00053     memset(&fInfo,0,sizeof(fInfo));
00054     // Fill up default categories
00055     for (unsigned int i=0; (i<4) && default_date_category_names[i]; ++i)
00056     {
00057         strncpy(fInfo.category.name[i],default_date_category_names[i],sizeof(fInfo.category.name[0]));
00058     }
00059 
00060     fInfo.startOfWeek = 0;
00061 
00062 }
00063 
00064 
00065 PilotDateEntry::PilotDateEntry():PilotRecordBase()
00066 {
00067     ::memset(&fAppointmentInfo, 0, sizeof(struct Appointment));
00068 }
00069 
00070 /* initialize the entry from another one. If rec==NULL, this constructor does the same as PilotDateEntry()
00071 */
00072 PilotDateEntry::PilotDateEntry(PilotRecord * rec) :
00073     PilotRecordBase(rec)
00074 {
00075     ::memset(&fAppointmentInfo, 0, sizeof(fAppointmentInfo));
00076     if (rec)
00077     {
00078         // Construct a fake pi_buffer for unpack_Appointment.
00079         // No ownership changes occur here.
00080         pi_buffer_t b = { (unsigned char *) rec->data(), rec->size(), rec->size() } ;
00081         unpack_Appointment(&fAppointmentInfo, &b, datebook_v1);
00082     }
00083     return;
00084 
00085 }
00086 
00087 void PilotDateEntry::_copyExceptions(const PilotDateEntry & e)
00088 {
00089     if (e.fAppointmentInfo.exceptions > 0)
00090     {
00091         size_t blocksize = e.fAppointmentInfo.exceptions *
00092             sizeof(struct tm);
00093 
00094         fAppointmentInfo.exception = (struct tm *)::malloc(blocksize);
00095 
00096         if (fAppointmentInfo.exception)
00097         {
00098             fAppointmentInfo.exceptions =
00099                 e.fAppointmentInfo.exceptions;
00100             ::memcpy(fAppointmentInfo.exception,
00101                 e.fAppointmentInfo.exception, blocksize);
00102         }
00103         else
00104         {
00105             WARNINGKPILOT << "malloc() failed, exceptions not copied" << endl;
00106             fAppointmentInfo.exceptions = 0;
00107         }
00108     }
00109     else
00110     {
00111         fAppointmentInfo.exceptions = 0;
00112         fAppointmentInfo.exception = 0L;
00113     }
00114 }
00115 
00116 
00117 PilotDateEntry::PilotDateEntry(const PilotDateEntry & e) :
00118     PilotRecordBase(e)
00119 {
00120     ::memcpy(&fAppointmentInfo, &e.fAppointmentInfo,
00121         sizeof(struct Appointment));
00122     // See operator = for explanation
00123     fAppointmentInfo.exception = 0L;
00124     fAppointmentInfo.description = 0L;
00125     fAppointmentInfo.note = 0L;
00126 
00127     _copyExceptions(e);
00128     setDescriptionP(e.fAppointmentInfo.description);
00129     setNoteP(e.fAppointmentInfo.note);
00130 }
00131 
00132 
00133 PilotDateEntry & PilotDateEntry::operator = (const PilotDateEntry & e)
00134 {
00135     if (this != &e)     // Pointer equality!
00136     {
00137         KPILOT_FREE(fAppointmentInfo.exception);
00138         KPILOT_FREE(fAppointmentInfo.description);
00139         KPILOT_FREE(fAppointmentInfo.note);
00140         ::memcpy(&fAppointmentInfo, &e.fAppointmentInfo,
00141             sizeof(fAppointmentInfo));
00142 
00143         // The original pointers were already freed; since we're now
00144         // got the pointers from the new structure and we're going
00145         // to use the standard set functions make sure that
00146         // we don't free() the copies-of-pointers from e, which
00147         // would be disastrous.
00148         //
00149         //
00150         fAppointmentInfo.exception = 0L;
00151         fAppointmentInfo.description = 0L;
00152         fAppointmentInfo.note = 0L;
00153 
00154         _copyExceptions(e);
00155         setDescriptionP(e.fAppointmentInfo.description);
00156         setNoteP(e.fAppointmentInfo.note);
00157     }
00158 
00159     return *this;
00160 }               // end of assignment operator
00161 
00162 
00163 QString PilotDateEntry::getTextRepresentation(Qt::TextFormat richText)
00164 {
00165     QString text, tmp;
00166     QString par = (richText==Qt::RichText) ?CSL1("<p>"):QString::null;
00167     QString ps = (richText==Qt::RichText) ?CSL1("</p>"):CSL1("\n");
00168     QString br = (richText==Qt::RichText) ?CSL1("<br/>"):CSL1("\n");
00169 
00170     // title + name
00171     text += par;
00172     tmp=richText?CSL1("<b><big>%1</big></b>"):CSL1("%1");
00173     text += tmp.arg(rtExpand(getDescription(), richText));
00174     text += ps;
00175 
00176     QDateTime dt(readTm(getEventStart()));
00177     QString startDate(dt.toString(Qt::LocalDate));
00178     text+=par;
00179     text+=i18n("Start date: %1").arg(startDate);
00180     text+=ps;
00181 
00182     if (isEvent())
00183     {
00184         text+=par;
00185         text+=i18n("Whole-day event");
00186         text+=ps;
00187     }
00188     else
00189     {
00190         dt=readTm(getEventEnd());
00191         QString endDate(dt.toString(Qt::LocalDate));
00192         text+=par;
00193         text+=i18n("End date: %1").arg(endDate);
00194         text+=ps;
00195     }
00196 
00197     if ( isAlarmEnabled() )
00198     {
00199         text+=par;
00200         tmp=i18n("%1 is the duration, %2 is the time unit", "Alarm: %1 %2 before event starts").
00201             arg(getAdvance());
00202         switch (getAdvanceUnits())
00203         {
00204             case advMinutes: tmp=tmp.arg(i18n("minutes")); break;
00205             case advHours: tmp=tmp.arg(i18n("hours")); break;
00206             case advDays: tmp=tmp.arg(i18n("days")); break;
00207             default: tmp=tmp.arg(QString::null); break;;
00208         }
00209         text+=tmp;
00210         text+=ps;
00211     }
00212 
00213     if (getRepeatType() != repeatNone)
00214     {
00215         text+=par;
00216         tmp=i18n("Recurrence: every %1 %2");
00217         int freq = getRepeatFrequency();
00218         tmp=tmp.arg(freq);
00219 
00220         switch(getRepeatType())
00221         {
00222             case repeatDaily: tmp=tmp.arg(i18n("day(s)")); break;
00223             case repeatWeekly: tmp=tmp.arg(i18n("week(s)")); break;
00224             case repeatMonthlyByDay:
00225             case repeatMonthlyByDate: tmp=tmp.arg(i18n("month(s)")); break;
00226             case repeatYearly: tmp=tmp.arg(i18n("year(s)")); break;
00227             default: tmp=tmp.arg(QString::null); break;
00228         }
00229         text+=tmp;
00230         text+=br;
00231 
00232         bool repeatsForever = getRepeatForever();
00233         if (repeatsForever)
00234         {
00235             text+=i18n("Repeats indefinitely");
00236         }
00237         else
00238         {
00239             dt = readTm(getRepeatEnd()).date();
00240             text+=i18n("Until %1").arg(dt.toString(Qt::LocalDate));
00241         }
00242         text+=br;
00243 
00244         if (getRepeatType()==repeatMonthlyByDay) text+=i18n("Repeating on the i-th day of week j")+br;
00245         if (getRepeatType()==repeatMonthlyByDate) text+=i18n("Repeating on the n-th day of the month")+br;
00246         // TODO: show the dayArray when repeating weekly
00247         /*QBitArray dayArray(7);
00248         if (getRepeatType()==repeatWeekly) text+=i18n("Repeat day flags: %1").arg(getRepeatDays
00249         const int *days = dateEntry->getRepeatDays();
00250         // Rotate the days of the week, since day numbers on the Pilot and
00251         // in vCal / Events are different.
00252         if (days[0]) dayArray.setBit(6);
00253         for (int i = 1; i < 7; i++)
00254         {
00255             if (days[i]) dayArray.setBit(i-1);
00256         }*/
00257         text+=ps;
00258     }
00259 
00260     if (getExceptionCount()>0 )
00261     {
00262         text+=par;
00263         text+=i18n("Exceptions:")+br;
00264         for (int i = 0; i < getExceptionCount(); i++)
00265         {
00266             QDate exdt=readTm(getExceptions()[i]).date();
00267             text+=exdt.toString(Qt::LocalDate);
00268             text+=br;
00269         }
00270         text+=ps;
00271     }
00272 
00273     if (!getNote().isEmpty())
00274     {
00275         text += richText?CSL1("<hr/>"):CSL1("-------------------------\n");
00276         text+=par;
00277         text+=richText?i18n("<b><em>Note:</em></b><br>"):i18n("Note:\n");
00278         text+=rtExpand(getNote(), richText);
00279         text+=ps;
00280     }
00281 
00282     return text;
00283 }
00284 
00285 QDateTime PilotDateEntry::dtStart() const
00286 {
00287     FUNCTIONSETUP;
00288     return readTm( getEventStart() );
00289 }
00290 
00291 QDateTime PilotDateEntry::dtEnd() const
00292 {
00293     FUNCTIONSETUP;
00294     return readTm( getEventEnd() );
00295 }
00296 
00297 QDateTime PilotDateEntry::dtRepeatEnd() const
00298 {
00299     FUNCTIONSETUP;
00300     return readTm( getRepeatEnd() );
00301 }
00302 
00303 unsigned int PilotDateEntry::alarmLeadTime() const
00304 {
00305     FUNCTIONSETUP;
00306     if (!isAlarmEnabled()) return 0;
00307 
00308     int adv = getAdvance();
00309     if ( adv < 0 )
00310     {
00311         return 0; // Not possible to enter on the pilot
00312     }
00313     unsigned int t = adv;
00314     int u = getAdvanceUnits();
00315 
00316 
00317     switch(u)
00318     {
00319     case advMinutes : t *= 60; break;
00320     case advHours : t *= 3600; break;
00321     case advDays : t *= 3600 * 24; break;
00322     default: t = 0;
00323     }
00324 
00325     return t;
00326 }
00327 
00328 PilotRecord *PilotDateEntry::pack() const
00329 {
00330     int i;
00331 
00332     pi_buffer_t *b = pi_buffer_new( sizeof(fAppointmentInfo) );
00333     i = pack_Appointment(const_cast<Appointment_t *>(&fAppointmentInfo), b, datebook_v1);
00334     if (i<0)
00335     {
00336         // Generic error from the pack_*() functions.
00337         return 0;
00338     }
00339 
00340     // pack_Appointment sets b->used
00341     return new PilotRecord( b, this );
00342 }
00343 
00344 /* setExceptions sets a new set of exceptions. Note that
00345     PilotDateEntry assumes ownership of the array and will
00346     delete the old one. */
00347 void PilotDateEntry::setExceptions(struct tm *e) {
00348     if (fAppointmentInfo.exception != e)
00349     {
00350         KPILOT_FREE(fAppointmentInfo.exception);
00351     }
00352     fAppointmentInfo.exception=e;
00353 }
00354 
00355 
00356 void PilotDateEntry::setDescriptionP(const char *desc, int l)
00357 {
00358     FUNCTIONSETUP;
00359     KPILOT_FREE(fAppointmentInfo.description);
00360 
00361     if (desc && *desc)
00362     {
00363         if (-1 == l) l=::strlen(desc);
00364         fAppointmentInfo.description =
00365             (char *) ::malloc(l + 1);
00366         if (fAppointmentInfo.description)
00367         {
00368             strlcpy(fAppointmentInfo.description, desc, l+1);
00369         }
00370         else
00371         {
00372             WARNINGKPILOT << "malloc() failed, description not set" << endl;
00373         }
00374     }
00375     else
00376     {
00377         fAppointmentInfo.description = 0L;
00378     }
00379 }
00380 
00381 void PilotDateEntry::setNoteP(const char *note, int l)
00382 {
00383     FUNCTIONSETUP;
00384     KPILOT_FREE(fAppointmentInfo.note);
00385 
00386     if (note && *note)
00387     {
00388         if (-1 == l) l=::strlen(note);
00389         fAppointmentInfo.note = (char *)::malloc(l + 1);
00390         if (fAppointmentInfo.note)
00391         {
00392             strlcpy(fAppointmentInfo.note, note,l+1);
00393         }
00394         else
00395         {
00396             WARNINGKPILOT << "malloc() failed, note not set" << endl;
00397         }
00398     }
00399     else
00400     {
00401         fAppointmentInfo.note = 0L;
00402     }
00403 }
00404 
00405 void PilotDateEntry::setNote(const QString &s)
00406 {
00407     QCString t = Pilot::toPilot(s);
00408     setNoteP( t.data(),t.length() );
00409 }
00410 
00411 void PilotDateEntry::setLocation(const QString &s)
00412 {
00413     QString note = Pilot::fromPilot(getNoteP());
00414     QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
00415 
00416     // per QString docs, this covers null and 0 length
00417     if( s.isEmpty() )
00418     {
00419         note.replace(rxp,"");
00420     }
00421     else
00422     {
00423         QString location = "Location: " + s + "\n";
00424         int pos = note.find(rxp);
00425 
00426         if(pos >= 0)
00427         {
00428             note.replace( rxp, location );
00429         }
00430         else
00431         {
00432             note = location + note;
00433             setNote( note );
00434         }
00435     }
00436 }
00437 
00438 QString PilotDateEntry::getLocation() const
00439 {
00440     // Read the complete note here and not the filtered
00441     // one from PilotDateEntry::getNote();
00442     QString note = Pilot::fromPilot(getNoteP());
00443     QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
00444     int pos = note.find(rxp, 0);
00445 
00446     if(pos >= 0)
00447     {
00448         QString location = rxp.capturedTexts().first();
00449         rxp = QRegExp("^[Ll]ocation:[\\s|\t]*");
00450         location.replace(rxp,"");
00451         location.replace("\n", "");
00452         return location;
00453     }
00454     else
00455     {
00456         return "";
00457     }
00458 }
00459 
00460 void PilotDateEntry::setDescription(const QString &s)
00461 {
00462     QCString t = Pilot::toPilot(s);
00463     setDescriptionP( t.data(),t.length() );
00464 }
00465 
00466 QString PilotDateEntry::getNote() const
00467 {
00468     QString note = Pilot::fromPilot(getNoteP());
00469     QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
00470     note.replace(rxp, "" );
00471     return note;
00472 }
00473 
00474 QString PilotDateEntry::getDescription() const
00475 {
00476     return Pilot::fromPilot(getDescriptionP());
00477 }
00478