summaryrefslogtreecommitdiffstats
path: root/kpilot/memoWidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kpilot/memoWidget.cpp')
-rw-r--r--kpilot/memoWidget.cpp803
1 files changed, 803 insertions, 0 deletions
diff --git a/kpilot/memoWidget.cpp b/kpilot/memoWidget.cpp
new file mode 100644
index 0000000..951a422
--- /dev/null
+++ b/kpilot/memoWidget.cpp
@@ -0,0 +1,803 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2001 by David Bishop (XML stuff)
+** Copyright (C) 2004 by Adriaan de Groot
+**
+** This is the memo-viewing widget (internal conduit) used by KPilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-pim@kde.org
+*/
+
+#include "options.h"
+
+#include <time.h>
+
+#include <pi-macros.h>
+#include <pi-dlp.h>
+
+#include <tqdir.h>
+#include <tqptrlist.h>
+#include <tqlistbox.h>
+#include <tqfile.h>
+#include <tqpushbutton.h>
+#include <tqlayout.h>
+#include <tqdom.h>
+#include <tqtextstream.h>
+#include <tqwhatsthis.h>
+#include <tqlabel.h>
+#include <tqdatetime.h>
+#include <tqptrlist.h>
+
+#include <tdeapplication.h>
+#include <tdemessagebox.h>
+#include <tdefiledialog.h>
+#include <tdeversion.h>
+#include <ktextedit.h>
+
+#include "kpilot.h"
+#include "kpilotConfig.h"
+#include "listItems.h"
+#include "pilotLocalDatabase.h"
+#include "pilotMemo.h"
+
+#include "memoWidget.moc"
+
+
+class MemoWidget::Private
+{
+public:
+ Private() : fMemoAppInfo(0L) { } ;
+ ~Private() { KPILOT_DELETE(fMemoAppInfo); } ;
+
+ PilotMemoInfo *fMemoAppInfo;
+ TQPtrList<PilotMemo> fMemoList;
+} ;
+
+
+MemoWidget::MemoWidget(TQWidget * parent,
+ const TQString & path) :
+ PilotComponent(parent, "component_memo", path),
+ fTextWidget(0L),
+ d(new Private()),
+ lastSelectedMemo(-1)
+{
+ FUNCTIONSETUP;
+
+ setGeometry(0, 0,
+ parent->geometry().width(), parent->geometry().height());
+ setupWidget();
+ d->fMemoList.setAutoDelete(true);
+ slotUpdateButtons();
+}
+
+MemoWidget::~MemoWidget()
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ KPILOT_DELETE(d);
+}
+
+
+// void MemoWidget::initializeMemos(PilotDatabase *memoDB)
+//
+// Reads all the memos from the local database and places them
+// in the selection screen.
+//
+
+void MemoWidget::initializeMemos(PilotDatabase * memoDB)
+{
+ FUNCTIONSETUP;
+
+
+ // ShowSecrets tells us to also list memos with an attribute of "Secret"
+ // or "Private"
+ //
+ bool showSecrets = KPilotSettings::showSecrets();
+
+ d->fMemoList.clear();
+
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotMemo *memo;
+
+ while ((pilotRec = memoDB->readRecordByIndex(currentRecord)) != NULL)
+ {
+ if (!pilotRec->isDeleted())
+ {
+ if ((!pilotRec->isSecret()) || showSecrets)
+ {
+ memo = new PilotMemo(pilotRec);
+ d->fMemoList.append(memo);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Added memo "
+ << currentRecord << endl;
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Skipped secret record " <<
+ currentRecord << endl;
+#endif
+ }
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Skipped deleted record " <<
+ currentRecord << endl;
+#endif
+ }
+
+ delete pilotRec;
+
+ currentRecord++;
+ }
+}
+
+
+void MemoWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ // Get the local database - assume the call may fail and return
+ // NULL, or the database object may be returned but unopened.
+ //
+ //
+ PilotLocalDatabase *memoDB =
+ new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ if (memoDB == NULL || !memoDB->isOpen())
+ {
+ WARNINGKPILOT << "Can't open local database MemoDB\n";
+
+ populateCategories(fCatList, 0L);
+ updateWidget();
+ return;
+ }
+
+ KPILOT_DELETE(d->fMemoAppInfo);
+ d->fMemoAppInfo = new PilotMemoInfo(memoDB);
+
+ d->fMemoAppInfo->dump();
+ populateCategories(fCatList, d->fMemoAppInfo->categoryInfo());
+ initializeMemos(memoDB);
+
+ KPILOT_DELETE( memoDB );
+
+ updateWidget();
+}
+
+void MemoWidget::hideComponent()
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ fCatList->clear();
+ fTextWidget->clear();
+ d->fMemoList.clear();
+ fListBox->clear();
+ lastSelectedMemo = -1;
+}
+
+void MemoWidget::postHotSync()
+{
+ FUNCTIONSETUP;
+ d->fMemoList.clear();
+ showComponent();
+}
+
+
+// void MemoWidget::setupWidget()
+//
+// Setup all the GUI components by allocating them.
+//
+//
+void MemoWidget::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ TQLabel *label = NULL;
+ TQPushButton *button = NULL;
+ TQGridLayout *grid = new TQGridLayout(this, 5, 4, SPACING);
+ TQString wt;
+
+ fCatList = new TQComboBox(this);
+ grid->addWidget(fCatList, 0, 1);
+ connect(fCatList, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotSetCategory(int)));
+ TQWhatsThis::add(fCatList,
+ i18n("Select the category of addresses\n"
+ "to display here."));
+
+ (void) i18n("Memos:");
+ label = new TQLabel(i18n("Category:"), this);
+ label->setBuddy(fCatList);
+ grid->addWidget(label, 0, 0);
+
+ fListBox = new TQListBox(this);
+ grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
+ connect(fListBox, TQT_SIGNAL(highlighted(int)),
+ this, TQT_SLOT(slotShowMemo(int)));
+ connect(fListBox, TQT_SIGNAL(selectionChanged()),
+ this,TQT_SLOT(slotUpdateButtons()));
+ TQWhatsThis::add(fListBox,
+ i18n("This list displays all the memos\n"
+ "in the selected category. Click on\n"
+ "one to display it to the right."));
+
+ label = new TQLabel(i18n("Memo text:"), this);
+ grid->addWidget(label, 0, 2);
+
+ fTextWidget = new KTextEdit(this, "textArea");
+ fTextWidget->setWordWrap(KTextEdit::WidgetWidth);
+ fTextWidget->setTextFormat(TQt::PlainText);
+ grid->addMultiCellWidget(fTextWidget, 1, 4, 2, 2);
+ TQWhatsThis::add(fTextWidget,
+ i18n("The text of the selected memo appears here."));
+ fTextWidget->setReadOnly(!KPilotSettings::internalEditors());
+
+ button = new TQPushButton(i18n("Import Memo..."), this);
+ grid->addWidget(button, 2, 0);
+ connect(button, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotImportMemo()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n ("Read a text file and add it to the Pilot's memo database.") :
+ i18n("<qt><i>Import is disabled by the 'internal editors' setting.</i></qt>");
+ TQWhatsThis::add(button,wt);
+
+ fExportButton = new TQPushButton(i18n("Export Memo..."), this);
+ grid->addWidget(fExportButton, 2, 1);
+ connect(fExportButton, TQT_SIGNAL(clicked()), this,
+ TQT_SLOT(slotExportMemo()));
+ TQWhatsThis::add(fExportButton,
+ i18n("Write the selected memo to a file."));
+
+ fDeleteButton = new TQPushButton(i18n("Delete Memo"), this);
+ grid->addWidget(fDeleteButton, 3, 1);
+ connect(fDeleteButton, TQT_SIGNAL(clicked()), this,
+ TQT_SLOT(slotDeleteMemo()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("Delete the selected memo.") :
+ i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
+ TQWhatsThis::add(fDeleteButton, wt);
+
+ button = new TQPushButton(i18n("Add Memo"), this);
+ grid->addWidget(button, 3, 0);
+ connect(button, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotAddMemo()));
+ TQWhatsThis::add(button,i18n("Add a new memo to the database."));
+}
+
+void MemoWidget::slotUpdateButtons()
+{
+ FUNCTIONSETUP;
+
+ bool highlight = false;
+
+ if ((fListBox->currentItem() != -1) &&
+ (fListBox->isSelected(fListBox->currentItem())))
+ highlight=true;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Selected items " << highlight << endl;
+#endif
+
+ if (fExportButton)
+ {
+ fExportButton->setEnabled(highlight);
+ }
+
+ // The remaining buttons are relevant only if the
+ // internal editors are editable.
+ highlight &= KPilotSettings::internalEditors() ;
+ if (fDeleteButton)
+ {
+ fDeleteButton->setEnabled(highlight);
+ }
+}
+
+void MemoWidget::slotSetCategory(int)
+{
+ FUNCTIONSETUP;
+ updateWidget();
+}
+
+void MemoWidget::slotDeleteMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ int item = fListBox->currentItem();
+
+ if (item == -1)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No current item selected\n";
+#endif
+ return;
+ }
+ if (KMessageBox::questionYesNo(this,
+ i18n("Delete currently selected memo?"),
+ i18n("Delete Memo?"), KStdGuiItem::del(), KStdGuiItem::cancel()) != KMessageBox::Yes)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": User decided not to delete memo.\n";
+#endif
+ return;
+ }
+
+ PilotListItem *p = (PilotListItem *) fListBox->item(item);
+ PilotMemo *selectedMemo = (PilotMemo *) p->rec();
+
+ if (selectedMemo->id() == 0x0)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Searching for record to delete (it's fresh)" << endl;
+#endif
+ PilotLocalDatabase *memoDB = new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ if (!memoDB || (!memoDB->isOpen()))
+ {
+ // Err.. peculiar.
+ WARNINGKPILOT << "Can't open MemoDB" << endl;
+ KMessageBox::sorry(this,
+ i18n("Cannot open MemoDB to delete record."),
+ i18n("Cannot Delete Memo"));
+ return;
+ }
+ memoDB->resetDBIndex();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Searching for new record." << endl;
+#endif
+ const PilotRecord *r = 0L;
+ while ((r = memoDB->findNextNewRecord()))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": got record " << (void *) r << endl;
+#endif
+ PilotMemo m(r);
+ if (m.text() == selectedMemo->text())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": I think I found the memo." << endl;
+#endif
+ (const_cast<PilotRecord *>(r))->setDeleted(true);
+ break;
+ }
+ }
+ delete memoDB;
+ }
+ else
+ {
+ selectedMemo->setDeleted(true);
+ writeMemo(selectedMemo);
+ }
+ d->fMemoList.remove(selectedMemo);
+ delete p;
+}
+
+
+void MemoWidget::updateWidget()
+{
+ FUNCTIONSETUP;
+ if (!shown || !d->fMemoAppInfo ) return;
+
+ if (fCatList->currentItem() == -1)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No category selected.\n";
+#endif
+ return;
+ }
+
+ int listIndex = 0;
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), false);
+
+
+ fListBox->clear();
+ d->fMemoList.first();
+
+
+ // Iterate through all the memos and insert each memo
+ // only if the category of the memo matches the selected category
+ // (using -1 to mean "All")
+ //
+ //
+ while (d->fMemoList.current())
+ {
+ PilotMemo *curr = d->fMemoList.current();
+ if ((curr->category() == currentCatID) ||
+ (currentCatID == -1))
+ {
+ PilotListItem *p =
+ new PilotListItem(curr->shortTitle(),
+ listIndex,
+ curr);
+
+ // List will delete the title of the memo,
+ // so there's no memory leak here.
+ //
+ //
+ fListBox->insertItem(p);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Added memo "
+ << curr->getTitle() << endl;
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Skipped memo "
+ << curr->getTitle() << endl;
+#endif
+ }
+
+ listIndex++;
+ d->fMemoList.next();
+ }
+
+ fTextWidget->clear();
+
+ slotUpdateButtons();
+
+ lastSelectedMemo=-1;
+}
+
+void MemoWidget::showMemo(const PilotMemo *m)
+{
+ FUNCTIONSETUP;
+
+ int index = fListBox->count();
+ for (int x = 0; x < index; x++)
+ {
+ PilotMemo *p = (PilotMemo *) ((PilotListItem *)fListBox->item(x))->rec();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Memo @" << (void *) p <<endl;
+ DEBUGKPILOT << fname << " :" << fListBox->item(x)->text() << endl;
+#endif
+ if (m==p)
+ {
+ fListBox->setSelected(x,true);
+ slotShowMemo(x);
+ break;
+ }
+ }
+
+}
+
+void MemoWidget::slotShowMemo(int which)
+{
+ FUNCTIONSETUP;
+ if ( which == -1 ) return;
+ if (!shown) return;
+
+ slotUpdateButtons();
+ if ( !fListBox->isSelected(which) )
+ {
+ // Handle unselecting a memo. This is easy.
+ fTextWidget->blockSignals(true);
+ fTextWidget->clear();
+ fTextWidget->blockSignals(false);
+ return;
+ }
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Displaying memo " << which << endl;
+#endif
+ fTextWidget->blockSignals(true);
+ PilotListItem *p = (PilotListItem *) fListBox->item(which);
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+ fTextWidget->setText(theMemo->text());
+ fTextWidget->blockSignals(false);
+}
+
+
+void MemoWidget::writeMemo(PilotMemo * which)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+ PilotRecord *pilotRec = which->pack();
+ PilotDatabase *memoDB = new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ memoDB->writeRecord(pilotRec);
+ markDBDirty(CSL1("MemoDB"));
+ KPILOT_DELETE( memoDB );
+ KPILOT_DELETE( pilotRec );
+}
+
+void MemoWidget::saveChangedMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ if (-1 == lastSelectedMemo) return;
+ if (!fTextWidget->isModified()) return;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Saving changed memo " << lastSelectedMemo << endl;
+#endif
+
+ PilotListItem *p =
+ (PilotListItem *) fListBox->item(lastSelectedMemo);
+ PilotMemo *currentMemo = (PilotMemo *) p->rec();
+
+// TODO: overload setText in PilotMemo
+ currentMemo->setText(Pilot::toPilot(fTextWidget->text()));
+ writeMemo(currentMemo);
+}
+
+/* virtual */ bool MemoWidget::preHotSync(TQString &)
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ return true;
+}
+
+bool MemoWidget::addMemo(const TQString &s, int category)
+{
+ FUNCTIONSETUP;
+
+ if (s.length() >= MemoWidget::MAX_MEMO_LEN)
+ {
+ return false;
+ }
+ if ((category<0) || (category>=(int)Pilot::CATEGORY_COUNT))
+ {
+ category=Pilot::Unfiled;
+ }
+
+ PilotMemo *aMemo = new PilotMemo();
+ aMemo->setCategory(category);
+ aMemo->setText(s);
+
+ d->fMemoList.append(aMemo);
+ writeMemo(aMemo);
+ updateWidget();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": New memo @" << (void *)aMemo << endl;
+#endif
+ showMemo(aMemo);
+ return true;
+}
+
+void MemoWidget::slotAddMemo()
+{
+ FUNCTIONSETUP;
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), true);
+ addMemo(TQDateTime::currentDateTime().toString(), currentCatID);
+}
+
+void MemoWidget::slotImportMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown || !d->fMemoAppInfo ) return;
+
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), true);
+
+ TQString fileName = KFileDialog::getOpenFileName();
+
+ if (!fileName.isEmpty())
+ {
+ TQFile importFile(fileName);
+
+ if (importFile.open(IO_ReadOnly) == FALSE)
+ {
+ // show error!
+ return;
+ }
+
+ if (importFile.size() > MemoWidget::MAX_MEMO_LEN)
+ {
+ // Perhaps read first 64k?
+ return;
+ }
+
+ TQTextStream stream(&importFile);
+ TQString memoText = stream.read();
+ addMemo(memoText, currentCatID);
+ }
+}
+
+void MemoWidget::slotExportMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ int index = fListBox->numRows();
+ if (index == 0)
+ return;
+
+ TQString data;
+
+ const TQString filter = CSL1("*|Plain text output\n*.xml|XML output");
+ TQString fileName;
+
+ KFileDialog tdefile( TQString() , filter, fExportButton , "memoSave" , true );
+ tdefile.setOperationMode( KFileDialog::Saving );
+
+ if ( tdefile.exec() == TQDialog::Accepted ) {
+ fileName = tdefile.selectedFile();
+ }
+
+ if (fileName.isEmpty())
+ return;
+
+ TQPtrList<PilotListItem> menu_items;
+
+ for (int x = 0; x < index; x++){
+ if (fListBox->item(x)->isSelected()){
+ menu_items.append((PilotListItem *) fListBox->item(x));
+ }
+ }
+
+ if (tdefile.currentFilter() == CSL1("*.xml") )
+ {
+ MemoWidget::saveAsXML( fileName , menu_items );
+ }
+ else
+ {
+ MemoWidget::saveAsText( fileName , menu_items );
+ }
+
+
+ return;
+}
+
+bool MemoWidget::saveAsText(const TQString &fileName,const TQPtrList<PilotListItem> &memo_list)
+{
+ TQFile f( fileName );
+ TQTextStream stream(&f);
+
+ if ( TQFile::exists( fileName ) )
+ {
+ if( !f.open(IO_ReadWrite | IO_Append) )
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if( !f.open(IO_WriteOnly) )
+ {
+ return false;
+ }
+ }
+
+ TQPtrListIterator<PilotListItem> it(memo_list);
+ for ( ; it.current(); ++it )
+ {
+ PilotListItem *p = it.current();
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+ stream << theMemo->text() << endl;
+ }
+
+
+ return true;
+}
+
+bool MemoWidget::saveAsXML(const TQString &fileName,const TQPtrList<PilotListItem> &memo_list)
+{
+ TQDomDocument doc( CSL1("kpilotmemos") );
+ TQFile f( fileName );
+ TQTextStream stream( &f );
+ TQDomElement memos;
+ int append = 0;
+
+
+ if ( f.exists() )
+ {
+ if ( !f.open(IO_ReadOnly ) ) return false;
+
+ if ( doc.setContent( &f ) )
+ {
+ //
+ //
+ //Only if TQDom can read the .xml file and set the doc object to be populated with it's contents
+ memos = doc.documentElement();
+ if ( memos.tagName()!= CSL1("memos") )
+ {
+ return false;
+ }
+ //
+ //
+ //This is an XML Document but it isn't a valid KPilot-Memo xml document
+ else
+ {
+ append = 1;
+ }
+ //
+ //
+ //This is a valid KPilot memo, and we will append the current memo to the xml
+ }
+ else
+ {
+ //
+ //
+ //We *couldn't* understand the xml. Return false!
+ return false;
+ }
+ }
+ else
+ {
+ if ( !f.open(IO_ReadWrite ) ) return false;
+ //
+ //
+ //If there's no such file, we are not appending, just opening the file to read/write.
+ }
+
+ f.close();
+ // These are temporary, and should be retrieved from the pilot stuff
+ TQString mpilotid;
+ mpilotid = "1";
+ // End of temp variables
+
+ if (append == 1)
+ {
+ memos = doc.documentElement();
+ }
+ else
+ {
+ memos = doc.createElement( CSL1("memos") );
+ doc.appendChild ( memos );
+ }
+
+ TQPtrListIterator<PilotListItem> it(memo_list);
+ for ( ; it.current(); ++it )
+ {
+ PilotListItem *p = it.current();
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+
+
+ TQDomElement memo = doc.createElement( CSL1("memo") );
+ memo.setAttribute ( CSL1("pilotid") , mpilotid );
+ memos.appendChild ( memo );
+
+ //TQDomElement category = doc.createElement( "category" );
+ //head.appendChild ( category );
+ //
+ //TQDomText categorytext = doc.createTextNode( memo->category() );
+ //category.appendChild ( categorytext );
+ //FIXME
+
+ TQDomElement title = doc.createElement(CSL1("title" ));
+ memo.appendChild ( title );
+
+ TQDomText titletext = doc.createTextNode( theMemo->shortTitle() );
+ title.appendChild ( titletext );
+
+ TQDomText body = doc.createTextNode( theMemo->text() );
+ memo.appendChild ( body );
+ }
+ if ( !f.open(IO_WriteOnly ) ) return false;
+ stream << doc.toString();
+ return true;
+}
+