You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kpilot/kpilot/memoWidget.cc

804 lines
17 KiB

/* 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 <kapplication.h>
#include <kmessagebox.h>
#include <kfiledialog.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 kfile( TQString() , filter, fExportButton , "memoSave" , true );
kfile.setOperationMode( KFileDialog::Saving );
if ( kfile.exec() == TQDialog::Accepted ) {
fileName = kfile.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 (kfile.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;
}