diff options
Diffstat (limited to 'kjots')
28 files changed, 3733 insertions, 0 deletions
diff --git a/kjots/ANNOUNCE b/kjots/ANNOUNCE new file mode 100644 index 0000000..d9a696f --- /dev/null +++ b/kjots/ANNOUNCE @@ -0,0 +1,26 @@ +kjots (version 0.3.0) - a note taker +------------------------------------ + +Hi ! + +New versions of kjots go directly into the kdeutils distribution. +This is for version 0.3.0. + +What is kjots +------------- + +Name and idea for this program are taken from the jots program included +in the tkgoodstuff package by Mark Crimmins (markcrim@umich.edu). + +Kjots helps you to write down some notes and maybe reduces the stack of +paper lying on your desk. + +New in this version +------------------- + +- added lots of keyboard shortcuts + + +Regards. + + Chris. diff --git a/kjots/BUGS b/kjots/BUGS new file mode 100644 index 0000000..f8de6a4 --- /dev/null +++ b/kjots/BUGS @@ -0,0 +1,6 @@ +kjots - a note taker +------------------------------------ + +Please use the bug tracking system at http://bugs.kde.org to +report bugs. + diff --git a/kjots/CHANGES b/kjots/CHANGES new file mode 100644 index 0000000..9815d90 --- /dev/null +++ b/kjots/CHANGES @@ -0,0 +1,75 @@ + +new in version 0.5 (Aaron J. Seigo) +- redesign of UI +- use of XMLGUI +- simplification of internals +- insertion of date and time +- printing +- stability improvements +- made KUniqueApp + +(Carsten Pfeiffer <pfeiffer@kde.org>) +- use KEdit instead of QMultiLineEdit directly + -> gains Search & replace + undo +- allocate KTMainWindow on the heap to avoid double deletion on quit + +new in version 0.4 (Mario Weilguni <mweilguni@kde.org>) +- works now with Qt 2.0 +- fixed broken layout of main window +- layout improvements in AskFileName() +- layout improvements in SubjList() +- compiles without warnings +- "Apply" button is only activated when changes were made +- improved layout of configuration dialog +- fixed a bug in the font selection + +- now compiles with EGCS ( Robert Williams ) + +new in version 0.3.0 +- added lots of keyboard shortcuts +- added klocale->translate() + +new in version 0.2.6 +- icons should be visible in the toolbar + +new in version 0.2.5 +- you may save books and pages to an ascii file +- more kde conforming due to the use of KTopLevelWidget + +new in version 0.2.4 +- uses kfontdialog to set the font of the editor widget +- you may select an URL in your text and press the right mouse button + to execute a program with this URL. The program to execute is + configurable for http and ftp URLs. +- some code cleanup + +new in version 0.2.3 +- compiles with libkde-970510 NOTE: this version is needed ! +- shouldn't segfault, if you delete pages +- double clicking on an entry in the subjectlist closes the subjectlist window +- fixed fonds -> fonts ;) + +new in version 0.2.2 +- compiles with libkde-0.7.2 +- several bug fixes + +new in version 0.2.1 + +- should compile cleanly with libqt1.2 and libkde-0.7.1 and later + +new in version 0.2.0 + +- changed the layout to be more KDE conforming (toolbar, statusbar,...) +- folders are now called books and entries are pages +- added subject to each page +- you may popup a window with a list of all subjects and use it to find + pages more easily +- further reduced the minimum size of the window + +new in version 0.1.1 + +- does not delete empty lines anymore +- you may insert TABs into your text +- the minimum size of the window is smaller now +- the size of the window is saved and read the next + time kjots is started diff --git a/kjots/KJotsMain.cpp b/kjots/KJotsMain.cpp new file mode 100644 index 0000000..a54cead --- /dev/null +++ b/kjots/KJotsMain.cpp @@ -0,0 +1,1199 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002-2004 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +#include <qheader.h> +#include <qwidgetstack.h> + +#include <kio/netaccess.h> + +#include <kaction.h> +#include <kapplication.h> +#include <kbookmarkmenu.h> +#include <kconfigdialog.h> +#include <kdebug.h> +#include <keditcl.h> +#include <kencodingfiledialog.h> +#include <kglobalsettings.h> +#include <kinputdialog.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <krun.h> +#include <kstandarddirs.h> +#include <kstdaccel.h> +#include <ktextbrowser.h> + +#include "KJotsMain.h" +#include "KJotsSettings.h" +#include "kjotsbookmarks.h" +#include "kjotsedit.h" +#include "kjotsentry.h" +#include "confpagemisc.h" +#include "confpagefont.h" + +#define KJOTSVERSION "0.7" + +extern KIconLoader* global_pix_loader; + +//---------------------------------------------------------------------- +// KJOTSMAIN +//---------------------------------------------------------------------- +KJotsMain::KJotsMain(const char* name) + : KMainWindow(0,name), + currentEntry(0), + invalidMoveFlag(false) +{ + // + // Main widget + // + QWidget* f_main = new QFrame( this, "Frame_0" ); + setCentralWidget(f_main); + + splitter = new QSplitter(f_main); + splitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + + // the subject list + subjectList = new KListView(splitter, "subjectList"); + subjectList->setRootIsDecorated(true); + subjectList->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); + subjectList->setMinimumWidth(subjectList->fontMetrics().maxWidth() * 10 + 5); + subjectList->addColumn(i18n("Pages")); + subjectList->setFullWidth(true); + subjectList->setHScrollBarMode(QScrollView::AlwaysOff); + subjectList->setDefaultRenameAction(QListView::Accept); + subjectList->setSorting(-1); + subjectList->setAlternateBackground(QColor()); + subjectList->header()->hide(); + subjectList->setDragEnabled(true); + subjectList->setAcceptDrops(true); + subjectList->setItemsMovable(true); + subjectList->setItemsRenameable(true); + subjectList->setRenameable(0,true); + + textStack = new QWidgetStack(splitter); + + me_text = new KJotsEdit(textStack, "me_text"); + me_text->setFocusPolicy(QWidget::StrongFocus); + me_text->setEnabled(false); + textStack->addWidget(me_text); + connect(me_text, SIGNAL(findSuccessful()), this, SLOT(slotFindSuccessful())); + + roTextView = new KTextBrowser(textStack, "roTextView", true); + textStack->addWidget(roTextView); + + QVBoxLayout *bookGrid = new QVBoxLayout(f_main, KDialog::marginHint(), KDialog::spacingHint()); + bookGrid->addWidget(splitter, 0, 0); + bookGrid->setMargin(0); + splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, 2, 1)); + + // create actions + actions[ACTION_NEXT_BOOK] = new KAction(i18n("Next Book"), QString::null, CTRL + Key_D, this, + SLOT(nextBook()), actionCollection(), "go_next_book"); + actions[ACTION_PREV_BOOK] = new KAction(i18n("Previous Book"), QString::null, CTRL + SHIFT + Key_D, this, + SLOT(prevBook()), actionCollection(), "go_prev_book"); + actions[ACTION_NEXT_PAGE] = new KAction(i18n("Next Page"), QString::null, CTRL + Key_PageDown, this, + SLOT(nextPage()), actionCollection(), "go_next_page"); + actions[ACTION_PREV_PAGE] = new KAction(i18n("Previous Page"), QString::null, CTRL + Key_PageUp, this, + SLOT(prevPage()), actionCollection(), "go_prev_page"); + + actions[ACTION_NEW_PAGE] = KStdAction::openNew(this, SLOT(newEntry()), actionCollection()); + actions[ACTION_NEW_PAGE]->setText(i18n("&New Page")); + actions[ACTION_NEW_BOOK] = new KAction(i18n("New &Book..."), "contents", CTRL + SHIFT + Key_N, this, + SLOT(createNewBook()), actionCollection(), "new_book"); + + exportPageMenu = new KActionMenu(i18n("Export Page"), actionCollection(), "save_page_to"); + actions[ACTION_PAGE2TEXT] = new KAction(i18n("To Text File..."), QString::null, 0, this, + SLOT(writePage()), actionCollection(), "save_page_to_ascii"); + actions[ACTION_PAGE2TEXT]->plug(exportPageMenu->popupMenu()); + actions[ACTION_PAGE2HTML] = new KAction(i18n("To HTML File..."), QString::null, 0, this, + SLOT(writePageToHTML()), actionCollection(), "save_page_to_html"); + actions[ACTION_PAGE2HTML]->plug(exportPageMenu->popupMenu()); + + exportBookMenu = new KActionMenu(i18n("Export Book"), actionCollection(), "save_book_to"); + actions[ACTION_BOOK2TEXT] = new KAction(i18n("To Text File..."), QString::null, 0, this, + SLOT(writeBook()), actionCollection(), "save_book_to_ascii"); + actions[ACTION_BOOK2TEXT]->plug(exportBookMenu->popupMenu()); + actions[ACTION_BOOK2HTML] = new KAction(i18n("To HTML File..."), QString::null, 0, this, + SLOT(writeBookToHTML()), actionCollection(), "save_book_to_html"); + actions[ACTION_BOOK2HTML]->plug(exportBookMenu->popupMenu()); + + actions[ACTION_DELETE_PAGE] = new KAction(i18n("&Delete Page"), "editdelete", CTRL + Key_Delete, this, + SLOT(deleteEntry()), actionCollection(), "del_page"); + actions[ACTION_DELETE_BOOK] = new KAction(i18n("Delete Boo&k"), "editdelete", CTRL + SHIFT + Key_Delete, this, + SLOT(deleteBook()), actionCollection(), "del_folder"); + + actions[ACTION_MANUAL_SAVE] = new KAction(i18n("Manual Save"), 0, KStdAccel::save(), + this, SLOT(autoSave()), actionCollection(), "manual_save"); + actions[ACTION_PRINT] = KStdAction::print(this, SLOT(slotPrint()), actionCollection()); + actions[ACTION_QUIT] = KStdAction::quit(this, SLOT(slotQuit()), actionCollection()); + + actions[ACTION_CUT] = KStdAction::cut(me_text, SLOT(cut()), actionCollection()); + connect(me_text, SIGNAL(copyAvailable(bool)), actions[ACTION_CUT], SLOT(setEnabled(bool))); + actions[ACTION_CUT]->setEnabled(false); + actions[ACTION_COPY] = KStdAction::copy(me_text, SLOT(copy()), actionCollection()); + connect(me_text, SIGNAL(copyAvailable(bool)), actions[ACTION_COPY], SLOT(setEnabled(bool))); + actions[ACTION_COPY]->setEnabled(false); + actions[ACTION_PASTE2TITLE] = new KAction(i18n("Copy &into Page Title"), "editcopy", CTRL+Key_T, this, + SLOT(copySelection()), actionCollection(), "copyIntoTitle"); + connect(me_text, SIGNAL(copyAvailable(bool)), actions[ACTION_PASTE2TITLE], SLOT(setEnabled(bool))); + actions[ACTION_PASTE2TITLE]->setEnabled(false); + actions[ACTION_PASTE] = KStdAction::pasteText(me_text, SLOT(paste()), actionCollection()); + + actions[ACTION_FIND] = KStdAction::find( this, SLOT( slotSearch() ), actionCollection() ); + actions[ACTION_FIND_NEXT] = KStdAction::findNext( this, SLOT( slotRepeatSearch() ), actionCollection() ); + actions[ACTION_FIND_NEXT]->setEnabled(false); + actions[ACTION_REPLACE] = KStdAction::replace( this, SLOT( slotReplace() ), actionCollection() ); + + actions[ACTION_RENAME] = new KAction(i18n("Rename..."), QString::null, CTRL + Key_M, this, + SLOT(slotRenameEntry()), actionCollection(), "rename_entry"); + actions[ACTION_INSERT_DATE] = new KAction(i18n("Insert Date"), "date", CTRL + Key_I, this, + SLOT(insertDate()), actionCollection(), "insert_date"); + + KStdAction::preferences(this, SLOT(configure()), actionCollection()); + + bookmarkMenu = new KActionMenu(i18n("&Bookmarks"), "bookmarks", actionCollection(), "bookmarks"); + KJotsBookmarks* bookmarks = new KJotsBookmarks(this); + connect(bookmarks, SIGNAL(openPage(const QString&)), SLOT(jumpToBookmark(const QString&))); + new KBookmarkMenu(KBookmarkManager::managerForFile(locateLocal("appdata","bookmarks.xml")), + bookmarks, bookmarkMenu->popupMenu(), + actionCollection(), true); + setupGUI(); + /* + * TODO: add a bookmark bar, something like this + KToolBar* bar = dynamic_cast<KToolBar *>(child("bookmarkToolBar", "KToolBar")); + new KBookmarkBar(KBookmarkManager::managerForFile(locateLocal("appdata","bookmarks.xml")), + bookmarks, bar, actionCollection(), this, "BookmarkBar"); + if (bar->count() == 0) + { + bar->hide(); + } + */ + + m_autosaveTimer = new QTimer(this, "autosave_timer"); + + // + // Set startup size. + // + if (!KJotsSettings::splitterSizes().isEmpty()) + { + splitter->setSizes(KJotsSettings::splitterSizes()); + } + + // + // Now load the books + // + loadBooks(); + + updateConfiguration(); + updateMenu(); + + QTimer::singleShot(0, this, SLOT(slotSetupInterface())); + + //connect new slots + connect(subjectList, SIGNAL(selectionChanged(QListViewItem*)), + this, SLOT(jumpToEntry(QListViewItem*))); + connect(subjectList, SIGNAL(moved(QListViewItem*, QListViewItem*, QListViewItem*)), + this, SLOT(slotItemMoved(QListViewItem*, QListViewItem*, QListViewItem*))); + connect(subjectList, SIGNAL(expanded(QListViewItem*)), + this, SLOT(slotExpandBook(QListViewItem*))); + connect(subjectList, SIGNAL(collapsed(QListViewItem*)), + this, SLOT(slotCollapseBook(QListViewItem*))); + connect(subjectList, SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)), + this, SLOT(showListviewContextMenu(KListView*,QListViewItem*,const QPoint&))); + connect(subjectList, SIGNAL(itemRenamed(QListViewItem*,const QString&,int)), + this, SLOT(slotItemRenamed(QListViewItem*,const QString&,int))); + connect(roTextView, SIGNAL(urlClick(const QString&)), + this, SLOT(linkClicked(const QString&))); + connect(m_autosaveTimer, SIGNAL(timeout()), + this, SLOT(autoSave())); +} + +void KJotsMain::slotSetupInterface() +{ + if (subjectList->childCount() == 0) + { + if ( !createNewBook() ) + { + roTextView->clear(); + textStack->raiseWidget(roTextView); + } + } +} + +/*! + \brief Loads all the books it can find in the appdata directory. + Needless to say: this should only ever be called once. +*/ +void KJotsMain::loadBooks() +{ + QDir dir(locateLocal("appdata","")); + QStringList files = dir.entryList(QDir::Files|QDir::Readable); + Q_UINT64 currentSelection = KJotsSettings::currentSelection(); + + //TODO: Eventually we can make use of the ".book" extension here, but for + //right now (2005/06/04) there's just too much legacy data out there. + + for (QStringList::Iterator it = files.begin(); it != files.end(); it++) + { + QString filepath = dir.absFilePath(*it); + + if (!KJotsBook::isBookFile(filepath) ) + { + continue; + } + + KJotsBook* book = new KJotsBook(subjectList, 0); + book->openBook(filepath); + } + + QListViewItemIterator it( subjectList ); + while ( it.current() ) { + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(it.current()); + if ( entry && entry->id() == currentSelection ) + { + subjectList->ensureItemVisible(entry); + subjectList->setSelected(entry, true); + jumpToEntry(entry); + break; + } + ++it; + } + + return; +} + +bool KJotsMain::createNewBook() +{ + bool ok; + + QString name = KInputDialog::getText( i18n( "New Book" ), + i18n( "Book name:" ), QString::null, &ok, this ); + + if (!ok) + return false; + + KJotsBook* book = new KJotsBook(subjectList, 0); + book->setSubject(name); + book->openBook(""); + book->setOpen(true); + subjectList->setSelected(book->firstChild(), true); + return true; +} + +void KJotsMain::slotRenameEntry() +{ + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + + if (entry) + { + entry->rename(); + jumpToEntry(entry, true); //reflect the changes on screen + } +} + +void KJotsMain::deleteBook() +{ + KJotsBook* b = currentBook(); + + if (!b) + return; + + QString msg = i18n("<qt>Are you sure you want to delete the <strong>%1</strong> book?</qt>"); + int result = KMessageBox::warningContinueCancel(topLevelWidget(), msg.arg(b->subject()), i18n("Delete Book"),KStdGuiItem::del()); + + if (result!=KMessageBox::Continue) + return; + + KJotsBook* nxt=dynamic_cast<KJotsBook*>(b->nextSibling()); + + b->deleteBook(); + currentEntry = 0L; + delete b; + + if (!nxt) + nxt=dynamic_cast<KJotsBook*>(subjectList->firstChild()); + + if (nxt) + { + subjectList->setSelected(nxt, true); + } + else + { + roTextView->clear(); + textStack->raiseWidget(roTextView); + updateMenu(); + } +} + +void KJotsMain::newEntry() +{ + KJotsBook* b = currentBook(); + + if (b) + { + KJotsPage* s = b->addPage(); + subjectList->setSelected(s, true); + } +} + +void KJotsMain::deleteEntry() +{ + KJotsPage* cur = currentPage(); + + if (!cur || + KMessageBox::warningContinueCancel(topLevelWidget(), + i18n("<qt>Are you sure you want to delete the <strong>%1</strong> page?</qt>") + .arg(cur->subject()), + i18n("Delete Page"),KStdGuiItem::del()) != KMessageBox::Continue) + { + return; + } + + KJotsBook* bk = cur->parentBook(); + KJotsPage* nxt = dynamic_cast<KJotsPage*>(cur->nextSibling()); + + me_text->setEntry(0); + delete cur; + currentEntry = 0; + + if (!nxt) + nxt = dynamic_cast<KJotsPage*>(bk->firstChild()); + + if (nxt) + { + subjectList->setSelected(nxt, true); + } else { + subjectList->setSelected(bk, true); + } + + updateMenu(); +} + +void KJotsMain::configure() +{ + if(KConfigDialog::showDialog("settings")) + return; + + KConfigDialog* dialog = new KConfigDialog(this, "settings", KJotsSettings::self()); + + confPageFont* cpFont = new confPageFont(0, "Font"); + dialog->addPage(cpFont, i18n("Font"), "fonts"); + + confPageMisc* cpMisc = new confPageMisc(0, "Autosave"); + dialog->addPage(cpMisc, i18n("Autosave"), "misc"); + + connect(dialog, SIGNAL(settingsChanged()), this, SLOT(updateConfiguration())); + + dialog->show(); +} + +void KJotsMain::slotSearch() +{ + me_text->search(); +} + +void KJotsMain::slotRepeatSearch() +{ + me_text->repeatSearch(); +} + +void KJotsMain::slotReplace() +{ + me_text->replace(); +} + +void KJotsMain::updateConfiguration() +{ + static int encoding = -1; + + //Keep track of the encoding setting. If the user changes it, we + //need to mark all books dirty so they are saved correctly. + if ( encoding == -1 ) { + encoding = KJotsSettings::unicode(); + } else { + if ( (int)encoding != KJotsSettings::unicode() ) { + KJotsBook *book = dynamic_cast<KJotsBook*>(subjectList->firstChild()); + while (book) { + book->setDirty(true); + book = dynamic_cast<KJotsBook*>(book->nextSibling()); + } + + encoding = (int)KJotsSettings::unicode(); + } + } + + me_text->setFont(KJotsSettings::font()); + if (KJotsSettings::autoSave()) + m_autosaveTimer->changeInterval(KJotsSettings::autoSaveInterval()*1000*60); + else + m_autosaveTimer->stop(); +} + +/*! + \brief Saves any books that need saving. +*/ +void KJotsMain::autoSave() +{ + KJotsBook *book = dynamic_cast<KJotsBook*>(subjectList->firstChild()); + while (book) + { + if ( book->isDirty() ) + { + book->saveBook(); + } + + book = dynamic_cast<KJotsBook*>(book->nextSibling()); + } +} + +void KJotsMain::writeBook() +{ + saveBookToFile(true); +} + +void KJotsMain::writeBookToHTML() +{ + saveBookToFile(false); +} + +void KJotsMain::saveBookToFile(bool plainText) +{ + KJotsBook* b = currentBook(); + + if (!b) + return; + + bool tryAgain = true; + KEncodingFileDialog::Result res; + while (tryAgain) + { + + res = KEncodingFileDialog::getSaveURLAndEncoding(); + + if (res.URLs[0].isEmpty()) + { + tryAgain = false; + } + + if (!KIO::NetAccess::exists(res.URLs[0], true, this) || + KMessageBox::warningYesNo(this, "<qt>" + i18n("The file <strong>%1</strong> already exists. Do you wish to overwrite it?").arg(res.URLs[0].prettyURL()) + "</qt>", i18n("File Exists"), i18n("Overwrite"), KStdGuiItem::cancel()) == KMessageBox::Yes) + { + tryAgain = false; + } + } + + if (!res.URLs[0].isEmpty()) + { + b->saveToFile(res.URLs[0], plainText, res.encoding); + } +} + +void KJotsMain::writePage() +{ + savePageToFile(true); +} + +void KJotsMain::writePageToHTML() +{ + savePageToFile(false); +} + +void KJotsMain::savePageToFile(bool plainText) +{ + KJotsPage* e = currentPage(); + + if (!e) + return; + + bool tryAgain = true; + KEncodingFileDialog::Result res; + while (tryAgain) + { + res = KEncodingFileDialog::getSaveURLAndEncoding(); + + if (res.URLs[0].isEmpty()) + { + tryAgain = false; + } + + if (!KIO::NetAccess::exists(res.URLs[0], true, this) || + KMessageBox::warningYesNo(this, "<qt>" + i18n("The file <strong>%1</strong> already exists. Do you wish to overwrite it?").arg(res.URLs[0].prettyURL()) + "</qt>", i18n("File Exists"), i18n("Overwrite"), KStdGuiItem::cancel()) == KMessageBox::Yes) + { + tryAgain = false; + } + } + + if (!res.URLs[0].isEmpty()) + { + e->saveToFile(res.URLs[0], plainText, res.encoding); + } +} + +void KJotsMain::copySelection() +{ + //TODO: Strip HTML tags + KJotsPage* cur = currentPage(); + + if (cur && me_text->hasSelectedText()) + cur->setSubject(me_text->selectedText()); +} + +void KJotsMain::slotPrint() +{ + autoSave(); + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + + if (entry) + { + entry->print(m_font); + } +} + +void KJotsMain::slotQuit() +{ + close(); +} + +void KJotsMain::insertDate() +{ + me_text->insert(KGlobal::locale()->formatDateTime(QDateTime::currentDateTime(), true) + " "); +} + +void KJotsMain::updateMenu() +{ + KJotsEntryBase* cur = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + + if (!cur) + { + // no (meaningful?) selection + actions[ACTION_DELETE_BOOK]->setEnabled(false); + actions[ACTION_DELETE_PAGE]->setEnabled(false); + actions[ACTION_NEW_PAGE]->setEnabled(false); + actions[ACTION_PRINT]->setEnabled(false); + actions[ACTION_CUT]->setEnabled(false); + actions[ACTION_PASTE]->setEnabled(false); + actions[ACTION_FIND]->setEnabled(false); + actions[ACTION_REPLACE]->setEnabled(false); + actions[ACTION_BOOK2TEXT]->setEnabled(false); + actions[ACTION_BOOK2HTML]->setEnabled(false); + actions[ACTION_PAGE2TEXT]->setEnabled(false); + actions[ACTION_PAGE2HTML]->setEnabled(false); + actions[ACTION_RENAME]->setEnabled(false); + actions[ACTION_INSERT_DATE]->setEnabled(false); + actions[ACTION_NEXT_BOOK]->setEnabled(false); + actions[ACTION_PREV_BOOK]->setEnabled(false); + actions[ACTION_NEXT_PAGE]->setEnabled(false); + actions[ACTION_PREV_PAGE]->setEnabled(false); + actions[ACTION_MANUAL_SAVE]->setEnabled(false); + bookmarkMenu->setEnabled(false); + exportPageMenu->setEnabled(false); + exportBookMenu->setEnabled(false); + } + else + { + actions[ACTION_DELETE_BOOK]->setEnabled(true); + actions[ACTION_NEW_PAGE]->setEnabled(true); + actions[ACTION_PRINT]->setEnabled(true); + actions[ACTION_FIND]->setEnabled(true); + actions[ACTION_BOOK2TEXT]->setEnabled(true); + actions[ACTION_BOOK2HTML]->setEnabled(true); + actions[ACTION_RENAME]->setEnabled(true); + actions[ACTION_MANUAL_SAVE]->setEnabled(true); + bookmarkMenu->setEnabled(true); + exportBookMenu->setEnabled(true); + + //TODO: Only activate if there is a next/prev book/page. + actions[ACTION_NEXT_BOOK]->setEnabled(true); + actions[ACTION_PREV_BOOK]->setEnabled(true); + actions[ACTION_NEXT_PAGE]->setEnabled(true); + actions[ACTION_PREV_PAGE]->setEnabled(true); + + if ( cur->isBook() ) + { + actions[ACTION_CUT]->setEnabled(false); + actions[ACTION_PASTE]->setEnabled(false); + actions[ACTION_REPLACE]->setEnabled(false); + actions[ACTION_DELETE_PAGE]->setEnabled(false); + actions[ACTION_PAGE2TEXT]->setEnabled(false); + actions[ACTION_PAGE2HTML]->setEnabled(false); + actions[ACTION_INSERT_DATE]->setEnabled(false); + exportPageMenu->setEnabled(false); + } + else + { + actions[ACTION_PASTE]->setEnabled(true); + actions[ACTION_REPLACE]->setEnabled(true); + actions[ACTION_DELETE_PAGE]->setEnabled(true); + actions[ACTION_PAGE2TEXT]->setEnabled(true); + actions[ACTION_PAGE2HTML]->setEnabled(true); + actions[ACTION_INSERT_DATE]->setEnabled(true); + exportPageMenu->setEnabled(true); + } + } +} + +void KJotsMain::slotFindSuccessful() +{ + actions[ACTION_FIND_NEXT]->setEnabled(true); +} + +void KJotsMain::showListviewContextMenu(KListView*, QListViewItem* i, const QPoint& p) +{ + if ( invalidMoveFlag ) return; //Prevent race condition + KActionMenu* am = new KActionMenu(this); + + if (!i) + { + // clicked on empty space + am->insert(actions[ACTION_NEW_BOOK]); + } + else if (dynamic_cast<KJotsBook*>(i)) + { + // clicked on book + am->insert(actions[ACTION_NEW_PAGE]); + am->insert(actions[ACTION_RENAME]); + am->insert(exportBookMenu); + am->insert(new KActionSeparator(am)); + am->insert(actions[ACTION_DELETE_BOOK]); + } + else + { + //clicked on page + am->insert(actions[ACTION_NEW_PAGE]); + am->insert(actions[ACTION_RENAME]); + am->insert(exportPageMenu); + am->insert(new KActionSeparator(am)); + am->insert(actions[ACTION_DELETE_PAGE]); + } + + am->popup(p); +} + +/*! + \brief Handle link clicks in read-only HTML view + All URL clicks in the read-only window come here. For some reason + KTextBrowser doesn't handle anchor links itself, so we have to take + care of those, too. +*/ +void KJotsMain::linkClicked(const QString& link) +{ + if (link[0] == '#') + { + // internal link from TOC + roTextView->scrollToAnchor(link.mid(1)); + return; + } + + Q_UINT64 target = link.toULongLong(); + QListViewItemIterator it( subjectList ); + while ( it.current() ) { + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(it.current()); + if ( entry && entry->id() == target ) + { + subjectList->ensureItemVisible(entry); + subjectList->setSelected(entry, true); + jumpToEntry(entry); + break; + } + ++it; + } + + return; +} + +bool KJotsMain::queryClose() +{ + autoSave(); + saveProperties(); + return true; +} + +/*! + \brief Saves settings to the ini-like config file. + This function only needs to be called before program termination. +*/ +void KJotsMain::saveProperties() +{ + KJotsSettings::setSplitterSizes(splitter->sizes()); + + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + KJotsSettings::setCurrentSelection( entry ? entry->id() : 0); + + KJotsSettings::writeConfig(); + return; +} + +/*! + \brief Called when a book is opened/expanded/whatever. +*/ +void KJotsMain::slotExpandBook(QListViewItem *item) +{ + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(item); + if ( entry ) entry->setDirty(true); +} + +/*! + \brief Called when a book is closed/collapsed/whatever. +*/ +void KJotsMain::slotCollapseBook(QListViewItem *item) +{ + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(item); + if ( entry ) entry->setDirty(true); +} + +/*! + Returns the name of the active book or page. +*/ +QString KJotsMain::currentBookmarkTitle() +{ + QString title; + QListViewItem *item = subjectList->currentItem(); + + while ( item ) + { + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(item); + item = item->parent(); + + if ( item ) + { + title = ": " + entry->subject() + title; + } else { + title = entry->subject() + title; + } + } + + return title; +} + +/*! + Returns a bookmark that identifies the active book or page. +*/ +QString KJotsMain::currentBookmarkURL() +{ + QString url; + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + + if ( entry ) + { + url.setNum( entry->id() ); + } + + return url; +} + +/*! + Accepts a bookmark from the bookmark manager and jumps to the given entry. + \param bookmark The bookmark. +*/ +void KJotsMain::jumpToBookmark(const QString& bookmark) +{ + Q_UINT64 id = bookmark.toULongLong(); + + if ( id ) + { + QListViewItemIterator it( subjectList ); + while ( it.current() ) { + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(it.current()); + if ( entry && entry->id() == id ) + { + subjectList->ensureItemVisible(entry); + subjectList->setSelected(entry, true); + jumpToEntry(entry); + break; + } + ++it; + } + } else { + //This is an old bookmark. Warn, and then continue. This can all be removed at some point + //in the future. CREATION DATE: 2005/06/10 + + KMessageBox::information(this, + i18n("This bookmark is from an older version of KJots and is not fully supported. It may or may not work. You should delete and recreate this bookmark."), QString::null, "oldBookmarkWarning"); + + int slash = bookmark.findRev('/'); + + if (slash != -1) + { + QString bookName = bookmark.left(slash); + int pageNo = bookmark.mid(slash+1).toInt(); + int pageCount = 0; + + //First, find the book. It'll only be root-level. + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(subjectList->firstChild()); + + while (entry) + { + if ( entry->subject() == bookName ) + { + break; + } + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + if ( !entry ) return; + + if ( !pageNo ) + { + subjectList->setSelected(entry, true); + jumpToEntry(entry); + } else { + //Now, find the right page + entry = dynamic_cast<KJotsEntryBase*>(entry->firstChild()); + + while (entry) + { + KJotsPage *page = dynamic_cast<KJotsPage*>(entry); + + if ( page ) + { + if ( ++pageCount == pageNo ) + { + static_cast<QListViewItem*>(entry)->parent()->setOpen(true); + subjectList->ensureItemVisible(entry); + subjectList->setSelected(entry, true); + jumpToEntry(entry); + break; + } + } + + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + } + } + } +} + +/*! + \brief Moves to the next book after the current selection. +*/ +void KJotsMain::nextBook() +{ + QListViewItem *item = subjectList->currentItem(); + if ( !item ) return; //sanity check + + QListViewItemIterator it ( item ); + QListViewItemIterator start ( it ); + + do { + it++; + + //if we iterate off the list, start over again. + if ( !it.current() ) + { + it = QListViewItemIterator ( subjectList ); + } + + if ( it.current() == start.current() ) return; //Bail out if we loop. + } while ( !dynamic_cast<KJotsBook*>(it.current())); + + subjectList->ensureItemVisible(it.current()); + subjectList->setSelected(it.current(), true); + + return; +} + +/*! + \brief Moves to the previous book before the current selection. +*/ +void KJotsMain::prevBook() +{ + //Don't get caught by parent book. + QListViewItem *startingPoint = subjectList->currentItem(); + if ( !startingPoint ) return; //sanity check + + if ( dynamic_cast<KJotsPage*>(startingPoint) ) + startingPoint = startingPoint->parent(); + + QListViewItemIterator it ( startingPoint ); + do { + it--; + + //if we iterate off the list, start over again. + if ( !it.current() ) + { + it = QListViewItemIterator ( subjectList->lastItem() ); + } + + if ( it.current() == startingPoint ) return; //Bail out if we loop. + } while ( !dynamic_cast<KJotsBook*>(it.current())); + + subjectList->ensureItemVisible(it.current()); + subjectList->setSelected(it.current(), true); + + return; +} + +/*! + \brief Moves to the next page after the current selection. +*/ +void KJotsMain::nextPage() +{ + QListViewItem *item = subjectList->currentItem(); + if ( !item ) return; //sanity check + + QListViewItemIterator it ( item ); + QListViewItemIterator start ( it ); + + do { + it++; + + //if we iterate off the list, start over again. + if ( !it.current() ) + { + it = QListViewItemIterator ( subjectList ); + } + + if ( it.current() == start.current() ) return; //Bail out if we loop. + } while ( !dynamic_cast<KJotsPage*>(it.current())); + + subjectList->ensureItemVisible(it.current()); + subjectList->setSelected(it.current(), true); + + return; +} + +/*! + \brief Moves to the previous page before the current selection. +*/ +void KJotsMain::prevPage() +{ + QListViewItem *item = subjectList->currentItem(); + if ( !item ) return; //sanity check + + QListViewItemIterator it ( item ); + QListViewItemIterator start ( it ); + + do { + it--; + + //if we iterate off the list, start over again. + if ( !it.current() ) + { + it = QListViewItemIterator ( subjectList->lastItem() ); + } + + if ( it.current() == start.current() ) return; //Bail out if we loop. + } while ( !dynamic_cast<KJotsPage*>(it.current())); + + subjectList->ensureItemVisible(it.current()); + subjectList->setSelected(it.current(), true); + + return; +} + +void KJotsMain::jumpToEntry(QListViewItem* entry, bool force) +{ + //This won't lose data or anything; but it does reset the cursor postion and waste cycles. + if (currentEntry == entry && !force) + return; + + if (entry == 0) + { + me_text->setEntry(0); + currentEntry = 0; + } + else if (dynamic_cast<KJotsBook*>(entry)) + { + me_text->setEntry(0); //clear any old data + + KJotsBook* book = static_cast<KJotsBook*>(entry); + QString html = book->generateHtml(book, false); + + roTextView->setText(html); + roTextView->setCursorPosition(0, 0); + textStack->raiseWidget(roTextView); + currentEntry = 0; + } + else + { + textStack->raiseWidget(me_text); + me_text->setEntry(dynamic_cast<KJotsPage*>(entry)); + currentEntry = static_cast<KJotsEntryBase*>(entry); + } + + updateCaption(); + updateMenu(); +} + +/*! + Sets the window caption. +*/ +void KJotsMain::updateCaption() +{ + QString caption; + QListViewItem *item = subjectList->currentItem(); + + while ( item ) + { + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(item); + item = item->parent(); + + if ( item ) + { + caption = " / " + entry->subject() + caption; + } else { + caption = entry->subject() + caption; + } + } + + setCaption(kapp->makeStdCaption(caption)); + return; +} + +void KJotsMain::slotItemRenamed(QListViewItem* item, const QString& str, int /*col*/) +{ + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(item); + + if (entry) + { + entry->setSubject(str); + entry->setDirty(true); + updateCaption(); + jumpToEntry(entry, true); //reflect the changes on screen + } +} + +/*! + \brief Called when an item is moved via drag-and-drop. + \warning The whole drag-n-drop reordering system is completely booched. + Tread lightly and test well when modifying things here. +*/ +void KJotsMain::slotItemMoved(QListViewItem *item, QListViewItem* afterFirst, QListViewItem */*afterNow*/ ) +{ + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(item); + + //afterFirst doesn't work like we need it to. We want it to point to the + //previous sibling, not just the entry directly above it. + if ( afterFirst && afterFirst->parent() != entry->parentBook() ) + { + QListViewItemIterator it ( afterFirst ); + afterFirst = 0; + + //Rewind backwards up the tree... + while ( it.current() ) + { + //No other items were above this one. + if ( it.current() == entry->parentBook() ) + { + break; + } + + //Found a previous sibling! + if ( it.current()->parent() == entry->parentBook() ) + { + afterFirst = it.current(); + break; + } + + --it; + } + } + + KJotsEntryBase *entryAfter = dynamic_cast<KJotsEntryBase*>(afterFirst); + + if ( entry->isPage() && !item->parent() ) + { + invalidMoveFlag=true; //Don't do anything while we're stuck here. + subjectList->setItemsMovable(false); + subjectList->setItemsRenameable(false); + + // We don't accept pages in the root. Create a new book? + if (KMessageBox::questionYesNo(this, + i18n("All pages must be inside a book. " + "Would you like to create a new book to put the page in, " + "or would you prefer to not move the page at all?"), + QString::null, + i18n("Create New Book"), i18n("Do Not Move Page")) == + KMessageBox::No || + !createNewBook()) + { + //We have to move item back. + subjectList->takeItem(item); + entry->parentBook()->insertItem(item); + entry->moveItem(afterFirst); + } else { + subjectList->takeItem(item); + delete currentBook()->firstChild(); + currentBook()->insertItem(item); + subjectList->ensureItemVisible(item); + subjectList->setSelected(item, true); + } + + invalidMoveFlag=false; + subjectList->setItemsMovable(true); + subjectList->setItemsRenameable(true); + } + + if ( entry ) + { + entry->resetParent(); + entry->setDirty(true); + } + + if ( entryAfter ) + { + //Set the old parent book to dirty, since it just lost a page. + if ( entryAfter->isBook() ) + entryAfter->setDirty(true); + else + entryAfter->parentBook()->setDirty(true); + } + + return; +} + +/*! + Returns a pointer to the currently selected book, or the book that owns + the currently selected page. +*/ +KJotsBook* KJotsMain::currentBook() +{ + KJotsEntryBase* e = dynamic_cast<KJotsEntryBase*>(subjectList->currentItem()); + + while (e) + { + if (dynamic_cast<KJotsBook*>(e)) + { + return dynamic_cast<KJotsBook*>(e); + } + e = dynamic_cast<KJotsEntryBase*>(e->KListViewItem::parent()); + } + + return 0; +} + +/*! + Returns the currently selected page or 0 if no page is selected. +*/ +KJotsPage* KJotsMain::currentPage() +{ + return dynamic_cast<KJotsPage*>(subjectList->currentItem()); +} + +void addBookmark() +{ +} + +void editBookmarks() +{ +} + +#include "KJotsMain.moc" +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/KJotsMain.h b/kjots/KJotsMain.h new file mode 100644 index 0000000..28ec089 --- /dev/null +++ b/kjots/KJotsMain.h @@ -0,0 +1,165 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002-2004 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef KJotsMain_included +#define KJotsMain_included + +#include <qlayout.h> +#include <qpushbutton.h> + +#include <kdialogbase.h> +#include <kmainwindow.h> + +class QGroupBox; +class QWidgetStack; +class KTextBrowser; +class KAccel; +class KJotsMain; +class KToolBar; +class KListBox; +class KListView; +class KPopupMenu; +class ConfigureDialog; +class KEdFind; +class KEdReplace; +class QTimer; +class KAction; +class KActionMenu; + +class KJotsPage; +class KJotsBook; +class KJotsEntryBase; +class KJotsEdit; + +// +// KJotsMain +// +#define ACTION_NEXT_BOOK 0 +#define ACTION_PREV_BOOK 1 +#define ACTION_NEXT_PAGE 2 +#define ACTION_PREV_PAGE 3 +#define ACTION_NEW_PAGE 4 +#define ACTION_NEW_BOOK 5 +#define ACTION_PAGE2TEXT 6 +#define ACTION_PAGE2HTML 7 +#define ACTION_BOOK2TEXT 8 +#define ACTION_BOOK2HTML 9 +#define ACTION_DELETE_PAGE 10 +#define ACTION_DELETE_BOOK 11 +#define ACTION_MANUAL_SAVE 12 +#define ACTION_PRINT 13 +#define ACTION_QUIT 14 +#define ACTION_CUT 15 +#define ACTION_COPY 16 +#define ACTION_PASTE2TITLE 17 +#define ACTION_PASTE 18 +#define ACTION_FIND 19 +#define ACTION_FIND_NEXT 20 +#define ACTION_REPLACE 21 +#define ACTION_RENAME 22 +#define ACTION_INSERT_DATE 23 +#define ACTION_MAX 24 + +class KJotsMain : public KMainWindow +{ + Q_OBJECT + + public: + KJotsMain( const char* name = 0 ); + + QString currentBookmarkTitle(); + QString currentBookmarkURL(); + + public: + void updateCaption(); + + protected slots: + void slotSetupInterface(); + bool createNewBook(); + void deleteBook(); + void newEntry(); + void deleteEntry(); + void slotRenameEntry(); + void configure(); + void updateConfiguration(); + + void copySelection(); + void insertDate(); + void slotPrint(); + void slotSearch(); + void slotRepeatSearch(); + void slotReplace(); + void slotQuit(); + void slotFindSuccessful(); + + void jumpToEntry(QListViewItem* entry, bool=false); + + void slotExpandBook(QListViewItem* item); + void slotCollapseBook(QListViewItem* item); + void slotItemRenamed(QListViewItem*,const QString&,int); + void slotItemMoved(QListViewItem*,QListViewItem*,QListViewItem*); + void writeBook(); + void writeBookToHTML(); + void saveBookToFile(bool plainText); + void writePage(); + void writePageToHTML(); + void savePageToFile(bool plainText); + + void nextBook(); + void prevBook(); + void nextPage(); + void prevPage(); + + // handling page changes in the listview + void showListviewContextMenu(KListView* l, QListViewItem* i, const QPoint& p); + void linkClicked(const QString&); + void autoSave(void); + + // bookmarks + void jumpToBookmark(const QString& page); + + protected: + void saveProperties(); + bool queryClose(); + void updateMenu(); + void loadBooks(); + KJotsBook* currentBook(); + KJotsPage* currentPage(); + + QHBoxLayout *bg_top_layout; + QButtonGroup *bg_top; + KJotsEdit *me_text; + KTextBrowser *roTextView; + KListView *subjectList; + KJotsEntryBase *currentEntry; + QSplitter *splitter; + QWidgetStack *textStack; + QFont m_font; + QTimer* m_autosaveTimer; + bool invalidMoveFlag; //!< Used to fix a race condition. See Bug #109299 + + KAction* actions[ACTION_MAX]; + KActionMenu *exportPageMenu, *exportBookMenu, *bookmarkMenu; +}; + +#endif // KJotsMain_included +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/KJotsSettings.kcfgc b/kjots/KJotsSettings.kcfgc new file mode 100644 index 0000000..44b75cc --- /dev/null +++ b/kjots/KJotsSettings.kcfgc @@ -0,0 +1,8 @@ +# Code generation options for kconfig_compiler +File=kjots.kcfg +ClassName=KJotsSettings +Singleton=true +Mutators=Width,Height,SplitterSizes,CurrentSelection,OpenBooks,LastId +# Inherits=KConfigSkeleton +# IncludeFiles=libkdepim/kpimprefs.h +# MemberVariables=public diff --git a/kjots/Kjots.desktop b/kjots/Kjots.desktop new file mode 100644 index 0000000..b0550e0 --- /dev/null +++ b/kjots/Kjots.desktop @@ -0,0 +1,80 @@ +[Desktop Entry] +DocPath=kjots/index.html +Name=KJots +Name[af]=Kjots +Name[eo]=Notlibro +Name[hi]=के-जॉट्स +Name[hr]=Bilješke +Name[pt_BR]=Tomador de notas +Name[sv]=Kjots +Name[ta]= KJots +Name[th]=บันทึกช่วยจำ +Name[xh]=Amaxabiso amancinane e K +GenericName=Note Taker +GenericName[af]=Nota Afnemer +GenericName[ar]=برنامج لأخذ الملاحظات +GenericName[bg]=Бележки +GenericName[bs]=Uzimanje bilješki +GenericName[ca]=Anotador +GenericName[cs]=Poznámkový blok +GenericName[cy]=Cofnodydd +GenericName[da]=Notetager +GenericName[de]=Notizen machen +GenericName[el]=Καταγραφέας σημειώσεων +GenericName[eo]=Notolibro +GenericName[es]=Para tomar notas +GenericName[et]=Märkmete tegemine +GenericName[eu]=Ohar Hartzailea +GenericName[fa]=یادداشت بردار +GenericName[fi]=Muistilappuohjelma +GenericName[fr]=Prise de notes +GenericName[ga]=Eagarthóir Nótaí +GenericName[he]=כותב הערות +GenericName[hi]=नोट टेकर +GenericName[hr]=Program za pisanje bilježaka +GenericName[hu]=Jegyzetlapok +GenericName[is]=Minnispunktar +GenericName[it]=Blocco per appunti +GenericName[ja]=メモを取る +GenericName[kk]=Шағын дәптер +GenericName[km]=កម្មវិធីកត់ចំណាំNote Taker +GenericName[lt]=Pastabų gavėjas +GenericName[lv]=Piezīmju Ņēmējs +GenericName[mk]=Прибележувач +GenericName[ms]=Pengambil Nota +GenericName[mt]=Ħu noti +GenericName[nb]=Beskjedverktøy +GenericName[nds]=Notizen maken +GenericName[ne]=टिपोट टेकर +GenericName[nl]=Notitieboekje +GenericName[nn]=Notatprogram +GenericName[pa]=ਨੋਟ ਲਵੋ +GenericName[pl]=Notatnik +GenericName[pt]=Bloco de Notas +GenericName[pt_BR]=Anotar pequenos apontamentos +GenericName[ro]=Notiţe +GenericName[ru]=Записная книжка +GenericName[sk]=Ukladanie poznámok +GenericName[sl]=Majhna beležnica +GenericName[sr]=Прибележивач +GenericName[sr@Latn]=Pribeleživač +GenericName[sv]=Elektroniska anteckningar +GenericName[ta]= குறிப்பு எடுப்பான் +GenericName[tg]=Китобчаи Навиштаҷот +GenericName[th]=บันทึกช่วยจำ +GenericName[tr]=Not alıcı +GenericName[uk]=Записна книжка +GenericName[ven]=Mudzhii wa dzinotsi +GenericName[wa]=Usteye po prinde des notes +GenericName[xh]=Umthathi Womakuqwalaselwe +GenericName[zh_CN]=笔记记录 +GenericName[zh_TW]=筆記簡記 +GenericName[zu]=Umthathi Wepheshana +Icon=kjots +Exec=kjots -caption "%c" %i %m +Type=Application +Path= +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Utility;X-KDE-Utilities-PIM; diff --git a/kjots/Makefile.am b/kjots/Makefile.am new file mode 100644 index 0000000..32af728 --- /dev/null +++ b/kjots/Makefile.am @@ -0,0 +1,28 @@ +INCLUDES = $(all_includes) +AM_LDFLAGS = $(all_libraries) $(KDE_RPATH) +LDADD = $(LIB_KFILE) $(LIB_KDEPRINT) + +bin_PROGRAMS = kjots + +kjots_SOURCES = main.cpp\ + KJotsMain.cpp\ + kjotsentry.cpp\ + kjotsedit.cpp\ + kjotsbookmarks.cpp\ + confpagefont.ui\ + confpagemisc.ui \ + KJotsSettings.kcfgc + +kjots_METASOURCES = AUTO + +SUBDIRS = icons + +xdg_apps_DATA = Kjots.desktop +kde_kcfg_DATA = kjots.kcfg + +rcdir = $(kde_datadir)/kjots +rc_DATA = kjotsui.rc + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kjots.pot + diff --git a/kjots/README b/kjots/README new file mode 100644 index 0000000..2ac51eb --- /dev/null +++ b/kjots/README @@ -0,0 +1,33 @@ +kjots - a note taker +------------------------------------ + +(C) 2002, 2003 Aaron J. Seigo <aseigo@olympusproject.org> + +(C) 1997 Christoph Neerfeld (Christoph.Neerfeld@home.ivm.de) +You may distribute kjots under the terms of the GNU General Public License. + +kjots is a small note taker program. Name and idea are taken from the jots +program included in the tkgoodstuff package. The tkgoodstuff package is +copyright (C) 1995-96 by Mark Crimmins (markcrim@umich.edu). + +Features: + - you may create several folders to store small text notes + +Bugs: + - see the BUGS doc or http://bugs.kde.org + +TODO for 3.2: + - preserve ordering of books between reloads + +TODO for post 3.2: + - statusbar with e.g. timestamp of last mod + - allow formatting of text in notes + - allow trees of pages + - page templates (TODO, diary, etc) + - encryption of pages + - syncing w/handhelds + +Install: + see INSTALL for details + +If you find bugs or have suggestions, send me an email diff --git a/kjots/confpagefont.ui b/kjots/confpagefont.ui new file mode 100644 index 0000000..e89e5b5 --- /dev/null +++ b/kjots/confpagefont.ui @@ -0,0 +1,38 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>confPageFont</class> +<widget class="QDialog"> + <property name="name"> + <cstring>confPageFont</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>520</width> + <height>406</height> + </rect> + </property> + <property name="caption"> + <string>Font</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KFontChooser"> + <property name="name"> + <cstring>kcfg_Font</cstring> + </property> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kfontdialog.h</includehint> +</includehints> +</UI> diff --git a/kjots/confpagemisc.ui b/kjots/confpagemisc.ui new file mode 100644 index 0000000..ef66e21 --- /dev/null +++ b/kjots/confpagemisc.ui @@ -0,0 +1,152 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>confPageMisc</class> +<widget class="QDialog"> + <property name="name"> + <cstring>confPageMisc</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>289</width> + <height>123</height> + </rect> + </property> + <property name="caption"> + <string>Miscellaneous</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KIntSpinBox" row="1" column="2"> + <property name="name"> + <cstring>kcfg_AutoSaveInterval</cstring> + </property> + <property name="suffix"> + <string> minutes</string> + </property> + <property name="specialValueText"> + <string>1 minute</string> + </property> + <property name="maxValue"> + <number>1440</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the number of minutes KJots will wait before automatically saving changes.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>S&ave every:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_AutoSaveInterval</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the number of minutes KJots will wait before automatically saving changes.</string> + </property> + </widget> + <spacer row="1" column="3"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>30</height> + </size> + </property> + </spacer> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_AutoSave</cstring> + </property> + <property name="text"> + <string>&Save changes periodically</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>When "Enable autosave" is checked, KJots will automatically save changes made to books at the interval defined below.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kcfg_Unicode</cstring> + </property> + <property name="text"> + <string>Use Unico&de encoding</string> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>kcfg_AutoSave</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_AutoSaveInterval</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_AutoSave</sender> + <signal>toggled(bool)</signal> + <receiver>textLabel1</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kjots/icons/Makefile.am b/kjots/icons/Makefile.am new file mode 100644 index 0000000..7345ca5 --- /dev/null +++ b/kjots/icons/Makefile.am @@ -0,0 +1,6 @@ + +pics_DATA = filedel.png +picsdir = $(kde_datadir)/kjots/pics + +KDE_ICON = kjots + diff --git a/kjots/icons/README b/kjots/icons/README new file mode 100644 index 0000000..3926e1e --- /dev/null +++ b/kjots/icons/README @@ -0,0 +1,24 @@ +The file jots.xpm is part of the tkgoodstuff package +copyright (C) 1995-96 by Mark Crimmins (markcrim@umich.edu) + +Here is the copyright notice of tkgoodstuff: +# tkgoodstuff by Mark Crimmins (markcrim@umich.edu) +# copyright (C) 1995-96, all rights reserved. +# Void where prohibited. Your mileage may vary. + +# Seriously, enjoy my handiwork, but don't sue me if it causes troubles. +# Also, the University of Michigan has NOTHING WHATEVER to do with this +# software. + +# This program (the tkgoodstuff package) 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 (version 2 of the License). 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. For a copy of the GNU General Public +# License, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + diff --git a/kjots/icons/filedel.png b/kjots/icons/filedel.png Binary files differnew file mode 100644 index 0000000..6d0d29d --- /dev/null +++ b/kjots/icons/filedel.png diff --git a/kjots/icons/hi16-app-kjots.png b/kjots/icons/hi16-app-kjots.png Binary files differnew file mode 100644 index 0000000..5466e25 --- /dev/null +++ b/kjots/icons/hi16-app-kjots.png diff --git a/kjots/icons/hi22-app-kjots.png b/kjots/icons/hi22-app-kjots.png Binary files differnew file mode 100644 index 0000000..36ce904 --- /dev/null +++ b/kjots/icons/hi22-app-kjots.png diff --git a/kjots/icons/hi32-app-kjots.png b/kjots/icons/hi32-app-kjots.png Binary files differnew file mode 100644 index 0000000..b2b128d --- /dev/null +++ b/kjots/icons/hi32-app-kjots.png diff --git a/kjots/icons/hi48-app-kjots.png b/kjots/icons/hi48-app-kjots.png Binary files differnew file mode 100644 index 0000000..142af59 --- /dev/null +++ b/kjots/icons/hi48-app-kjots.png diff --git a/kjots/icons/hi64-app-kjots.png b/kjots/icons/hi64-app-kjots.png Binary files differnew file mode 100644 index 0000000..ec0f270 --- /dev/null +++ b/kjots/icons/hi64-app-kjots.png diff --git a/kjots/kjots.kcfg b/kjots/kjots.kcfg new file mode 100644 index 0000000..4350210 --- /dev/null +++ b/kjots/kjots.kcfg @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kjotsrc"/> + <group name="kjots"> + <entry name="SplitterSizes" type="IntList"> + <label>How the main window is divided.</label> + </entry> + <entry name="CurrentSelection" type="UInt64"> + <label>The book or page that is currently active.</label> + </entry> + <entry name="Font" type="Font"> + <label>The font used to display the contents of books.</label> + <default code="true">KGlobalSettings::generalFont()</default> + </entry> + <entry name="AutoSave" type="Bool"> + <label>Whether books should be saved automatically.</label> + <default>true</default> + </entry> + <entry name="Unicode" type="Bool"> + <label>Whether UTF-8 encoding should be forced for saving and loading.</label> + <default>false</default> + </entry> + <entry name="AutoSaveInterval" type="Int"> + <label>The interval in minutes at which books should be saved automatically.</label> + <default>5</default> + </entry> + <entry name="LastId" type="UInt64"> + <label>The last ID that was used for a book or page.</label> + <default>0</default> + </entry> + </group> +</kcfg> diff --git a/kjots/kjotsbookmarks.cpp b/kjots/kjotsbookmarks.cpp new file mode 100644 index 0000000..b339a46 --- /dev/null +++ b/kjots/kjotsbookmarks.cpp @@ -0,0 +1,51 @@ +// +// kjotsbookmarks +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "KJotsMain.h" +#include "kjotsbookmarks.h" + +KJotsBookmarks::KJotsBookmarks(KJotsMain* parent, const char* name) + : QObject(parent, name), + m_kjots(parent) +{ +} + +KJotsBookmarks::~KJotsBookmarks() +{ +} + +void KJotsBookmarks::openBookmarkURL(const QString& page) +{ + emit openPage(page); +} + +QString KJotsBookmarks::currentURL() const +{ + return m_kjots->currentBookmarkURL(); +} + +QString KJotsBookmarks::currentTitle() const +{ + return m_kjots->currentBookmarkTitle(); +} + +#include "kjotsbookmarks.moc" diff --git a/kjots/kjotsbookmarks.h b/kjots/kjotsbookmarks.h new file mode 100644 index 0000000..7cb3144 --- /dev/null +++ b/kjots/kjotsbookmarks.h @@ -0,0 +1,51 @@ +// +// kjotsbookmarks +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef KJOTSBOOKMARKS +#define KJOTSBOOKMARKS + +#include <kbookmarkmanager.h> + +class KJotsMain; + +class KJotsBookmarks : public QObject, public KBookmarkOwner +{ + Q_OBJECT + + public: + KJotsBookmarks(KJotsMain* parent = 0, const char* name = 0); + ~KJotsBookmarks(); + + virtual void openBookmarkURL(const QString& url); + virtual QString currentURL() const; + QString currentTitle() const; + + signals: + void openPage(const QString& page); + + private: + KJotsMain* m_kjots; +}; + + +#endif +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/kjotsedit.cpp b/kjots/kjotsedit.cpp new file mode 100644 index 0000000..0a61c62 --- /dev/null +++ b/kjots/kjotsedit.cpp @@ -0,0 +1,150 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qpainter.h> +#include <qpaintdevicemetrics.h> +#include <qcursor.h> + +#include <kpopupmenu.h> +#include <keditcl.h> +#include <klocale.h> +#include <kopenwith.h> +#include <kprinter.h> + +#include "kjotsedit.h" +#include "kjotsentry.h" + +//---------------------------------------------------------------------- +// MYMULTIEDIT +//---------------------------------------------------------------------- +KJotsEdit::KJotsEdit (QWidget* parent, const char* name) + : KEdit(parent, name), + m_entry(0) +{ + // no rich text until printing and other such issues are worked out + setTextFormat(Qt::PlainText); + setWordWrap(QTextEdit::WidgetWidth); + setLinkUnderline(true); + web_menu = new KPopupMenu(this);; + web_menu->insertItem(i18n("Open URL"), this, SLOT(openUrl()) ); +} + +KJotsEdit::~KJotsEdit() +{ + +} + +void KJotsEdit::mousePressEvent( QMouseEvent *e ) +{ + if(e->button() == RightButton && + hasSelectedText()) + { + KURL url(selectedText()); + + if(url.isValid()) + { + web_menu->popup(QCursor::pos()); + return; + } + } + + KEdit::mousePressEvent(e); +} + +void KJotsEdit::openUrl() +{ + if (hasSelectedText()) + { + KURL url(selectedText()); + if(url.isValid()) + { + new KRun(url); + } + } +} + +void KJotsEdit::print(QString title) +{ + KPrinter printer; + printer.setDocName(title); + printer.setFullPage(false); + printer.setCreator("KJots"); + + if (printer.setup(this)) + { + QFont printFont = font(); + QPainter painter( &printer ); + QPaintDeviceMetrics metrics( &printer ); + int y = 0; + int maxWidth = metrics.width(); + int maxHeight = metrics.height(); + QString currentParagraph; + + for (int paragraphCount = 0; paragraphCount < paragraphs(); ++paragraphCount ) + { + currentParagraph = text(paragraphCount); + QRect r = painter.boundingRect(0, y, maxWidth, maxHeight, + QPainter::ExpandTabs | QPainter::WordBreak, + currentParagraph); + + if ((y + r.height()) > maxHeight) + { + printer.newPage(); + y = 0; + } + + painter.drawText(0, y, maxWidth, maxHeight - y, + QPainter::ExpandTabs | QPainter::WordBreak, + currentParagraph); + y += r.height(); + } + painter.end(); + } +} + +void KJotsEdit::setEntry (KJotsPage *entry) +{ + //tell the old entry to take a hike + if ( m_entry ) + { + m_entry->setEditor(0); + } + + //load up the new entry (assuming there is one) + if ( entry ) + { + m_entry = entry; + setText(entry->body()); + removeSelection(); + repaint(); + setEnabled(true); + setFocus(); + entry->setEditor(this); + } else { + clear(); + } + + m_entry = entry; +} + +#include "kjotsedit.moc" +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/kjotsedit.h b/kjots/kjotsedit.h new file mode 100644 index 0000000..cae025c --- /dev/null +++ b/kjots/kjotsedit.h @@ -0,0 +1,54 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef __KJOTSEDIT_H +#define __KJOTSEDIT_H + +#include <keditcl.h> +class KPopupMenu; +class KJotsPage; + +class KJotsEdit : public KEdit +{ + Q_OBJECT + public: + KJotsEdit (QWidget* parent=0, const char* name=0); + ~KJotsEdit (); + + void print(QString title = QString::null); + void setEntry(KJotsPage*); + + signals: + void findSuccessful(); + + protected slots: + void openUrl(); + + protected: + virtual void mousePressEvent (QMouseEvent *e); + + KPopupMenu *web_menu; + KJotsPage *m_entry; //!< The entry we are editing. It needs to be kept informed. +}; + +#endif // __KJOTSEDIT_H +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/kjotsentry.cpp b/kjots/kjotsentry.cpp new file mode 100644 index 0000000..a27b00e --- /dev/null +++ b/kjots/kjotsentry.cpp @@ -0,0 +1,1234 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qdir.h> +#include <qpainter.h> +#include <qpaintdevicemetrics.h> +#include <qtextcodec.h> +#include <qdom.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprogress.h> +#include <kstandarddirs.h> +#include <ktempfile.h> + +#include <kio/job.h> +#include <assert.h> + +#include "kjotsedit.h" +#include "KJotsMain.h" +#include "KJotsSettings.h" +#include "kjotsentry.h" + +// helper functions for HTML output +QString prepForHTML(QString text) +{ + text.replace("<", "<"); + text.replace(">", ">"); + text.replace("\n", "<br>"); + return text; +} + +QString htmlHeader(const QString& title, QTextCodec* codec) +{ + QString head = "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset="; + head+=codec->mimeName(); + head+="\" ><title>" + prepForHTML(title) + "</title></head><body>"; + return head; +} + +QString htmlFooter() +{ + return "</body></html>"; +} + +// +// KJotsEntryBase +// + +KJotsEntryBase::KJotsEntryBase(KListView* parent, QListViewItem* after=0) + :KListViewItem(parent,after) +{ + m_id = 0; + m_saveInProgress = m_dirty = false; + m_parent = 0; +} + +KJotsEntryBase::KJotsEntryBase(KListViewItem* parent, QListViewItem* after=0) + :KListViewItem(parent,after) +{ + m_id = 0; + m_saveInProgress = m_dirty = false; + m_parent = dynamic_cast<KJotsBook*>(parent); +} + +void KJotsEntryBase::setSubject(const QString& subj) +{ + setText(0, subj); +} + +void KJotsEntryBase::setText(int column, const QString& text) +{ + if (column == 0 && text.isEmpty()) + KListViewItem::setText(0, defaultSubject()); + else + KListViewItem::setText(column, text); +} + +/*! + \brief Sets a new parent. + This is mostly just used during drag-and-drop reordering in the list view. + We need to keep track of the previous parent in case the move is invalid. +*/ +void KJotsEntryBase::resetParent() +{ + m_parent = dynamic_cast<KJotsBook*>(QListViewItem::parent()); +} + +/*! +* \brief Set the ID number. +* \param id The ID to set, or 0 to pick a fresh one. +* +* Set ourselves to a particular ID number, or pick a new one. The lastId used is +* stored in the settings. Now in theory it will eventually wrap, and may collide +* with preexisting IDs. Seeing as how we are using an unsigned long long, I am +* comfortable with the amount of time we have to worry about this. +*/ +void KJotsEntryBase::setId(Q_UINT64 id) +{ + //Find an unused id... + if ( id == 0 ) + { + Q_UINT64 lastId = KJotsSettings::lastId(); + + //TODO: In theory, we could wrap. The universe may end beforehand tho. + id = ++lastId; + if ( id == 0 ) id = ++lastId; //*IF* by some chance we do wrap, this will prevent bad things. + KJotsSettings::setLastId(id); + } + + m_id = id; + return; +} + +/*! + \brief Performs functions necessary to save the entry to a KJots file. + This function should ONLY be called when saving the file, as it performs + other functions than generating XML. +*/ +void KJotsEntryBase::generateXml( QDomDocument &doc, QDomElement &parent ) +{ + QDomElement title = doc.createElement( "Title" ); + title.appendChild( doc.createTextNode( subject() )); + parent.appendChild( title ); + + QDomElement id = doc.createElement( "ID" ); + QString id_string; + id_string.setNum(m_id); + id.appendChild( doc.createTextNode(id_string) ); + parent.appendChild( id ); + + setDirty( false ); + return; +} + +/*! + Parses through XML data for settings inherent to the base class. +*/ +void KJotsEntryBase::parseXml( QDomElement &e ) +{ + if ( !e.isNull() ) + { + if ( e.tagName() == "Title" ) + { + setSubject(e.text()); + } + else + if ( e.tagName() == "ID" ) + { + setId(e.text().toULongLong()); + } + } + + return; +} + +/*! + \brief Draws the Title box when printing. + This is a helper function for the derived classes. Code consolidation==the good. +*/ +int KJotsEntryBase::printTitleBox(QString title, KPrinter& printer, QPainter& painter, int y) +{ + QPaintDeviceMetrics metrics( &printer ); + int maxWidth = metrics.width(); + int maxHeight = metrics.height(); + + QRect r = painter.boundingRect(0, y, + maxWidth, maxHeight, + QPainter::ExpandTabs | QPainter::WordBreak | QPainter::AlignHCenter, + title); + y += 10; + + if ((y + r.height()) > maxHeight) + { + printer.newPage(); + y = 0; + } + else + { + r.moveBy(0, 10); + } + + r.setLeft(0); + r.setRight(maxWidth); + painter.drawRect(r); + painter.drawText(0, y, maxWidth, maxHeight - y, + QPainter::ExpandTabs | QPainter::WordBreak | QPainter::AlignHCenter, + title); + y += r.height() + 15; + + return y; +} + +// +// KJotsBook +// + +KJotsBook::KJotsBook(KListView* parent, QListViewItem* after) + : KJotsEntryBase(parent, after) +{ + init(); +} + +KJotsBook::KJotsBook(KListViewItem* parent, QListViewItem* after) + : KJotsEntryBase(parent, after) +{ + init(); +} + +KJotsBook::~KJotsBook() +{ +} + +/*! + \brief Initialize a KJotsBook object. + + This function is used for code consolidation. Otherwise, you'de have to change these + things in both constructors. +*/ +void KJotsBook::init() +{ + m_isBook = true; + m_open = false; + m_saveProgressDialog = 0; + setExpandable(true); + setPixmap(0, kapp->iconLoader()->loadIcon(QString("contents"),KIcon::Small)); +} + +/*! + \brief Is this a KJots file? + \param filename Filename to check. + + This function does a cursory check to see if this looks like it is a KJots file. + It's a little too quick and dirty for my taste, but seems to work OK. +*/ +bool KJotsBook::isBookFile(const QString& filename) +{ + QFile folder(filename); + bool test = false; + + if ( folder.exists() ) + { + if ( folder.open(IO_ReadWrite) ) + { + QTextStream st(static_cast<QIODevice*>(&folder)); + st.setEncoding( KJotsSettings::unicode() ? QTextStream::UnicodeUTF8 : QTextStream::Locale ); + QString buf = st.readLine().stripWhiteSpace(); + + //Check for new-style book. Not very pretty, but it is faster than loading the DOM. + if (buf == "<!DOCTYPE KJots>") + { + test=true; + } + else + //Check for old-style book. See KJotsBook::loadOldBook() + if (buf.left(9) == "\\NewEntry") + { + test=true; + } + + } + } + + return test; +} + +/*! + \brief Reads a book in from a disk file. + This function is only called for root-level books. +*/ +bool KJotsBook::openBook(const QString& filename) +{ + if ( !m_open ) //sanity check + { + listView()->setUpdatesEnabled(false); + m_fileName = filename; + + if ( m_fileName.isEmpty() ) //new books names are empty. + { + addPage(); + m_open = true; + } else { + QFile file(m_fileName); + + if ( file.exists() && file.open(IO_ReadWrite) ) //TODO: Implement read-only mode? + { + QTextStream st(static_cast<QIODevice*>(&file)); + st.setEncoding( KJotsSettings::unicode() ? QTextStream::UnicodeUTF8 : QTextStream::Locale ); + QString data = st.read(); + + QDomDocument doc( "KJots" ); + if ( doc.setContent( data ) ) + { + QDomElement docElem = doc.documentElement(); + + if ( docElem.tagName() == "KJots" ) + { + QDomNode n = docElem.firstChild(); + while( !n.isNull() ) + { + QDomElement e = n.toElement(); // try to convert the node to an element. + if( !e.isNull() && e.tagName() == "KJotsBook" ) + { + parseXml(e); + } + n = n.nextSibling(); + } + } + + } else { + //Woah. Something didn't work right. Maybe this is an old file? + file.reset(); + if ( loadOldBook(file) ) + { + QFileInfo fi( file ); + setSubject(fi.fileName()); + } + } + } + + if ( !childCount() ) //sanity check + { + //We should NOT be here. That must not have been a book file, or it is damaged. + //To make things happy-happy, we just create a blank page and continue. + //TODO: Add an information message? Make a translater work for something so unlikely? + addPage(); + } + + m_open = true; + + // Support legacy files. Can be removed at some point. CREATION DATE: 2005/06/04 + if ( !m_fileName.isEmpty() && !m_fileName.endsWith(".book") ) + { + //some old books have incorrect names. So we save a new copy, then kill the old file + m_fileName = QString::null; //trick ourselves into thinking we're a new book + saveBook(); + file.remove(); + } + } + + listView()->setUpdatesEnabled(true); + + // Support legacy files. Can be removed at some point. CREATION DATE: 2005/06/07 + if ( m_open && !id() ) + { + //This book (and its pages) need new IDs! + setId(0); + + KJotsPage *page = dynamic_cast<KJotsPage*>(firstChild()); + while ( page ) + { + page->setId(0); //TODO: Make setId() a protected function if this legacy code is removed. + page = dynamic_cast<KJotsPage*>(page->nextSibling()); + } + } + } + + return m_open; +} + +/*! + \brief Load an old-style book file. + + This is a function for files made from older KJots versions. It could probably be removed + at some point in the future. CREATION DATE: 2005/05/30 +*/ +bool KJotsBook::loadOldBook(QFile &file) +{ + QTextStream st(static_cast<QIODevice*>(&file)); + st.setEncoding( KJotsSettings::unicode() ? QTextStream::UnicodeUTF8 : QTextStream::Locale ); + QString buf = st.readLine(); + + if (buf.left(9) != "\\NewEntry") + { + addPage(); + return false; + } + + KJotsPage *entry = 0; + QString body; + + bool quit=false; + + while (1) + { + if (buf.left(9) == "\\NewEntry") + { + if (entry) + { + entry->setBody(body); + } + + body = QString::null; + QString title = buf.mid(10, buf.length()); + + // now catch the page id + buf = st.readLine(); + if (buf.left(3) == "\\ID") + { + buf = st.readLine(); + } + + entry = new KJotsPage(this, entry); + entry->setSubject(title); + } + + int pos = 0; + + while ((pos = buf.find('\\',pos)) != -1) + if (buf[++pos] == '\\') + buf.remove(pos, 1 ); + + body.append( buf + "\n"); + + if (quit) + break; + + buf = st.readLine(); + + quit = st.eof(); + } + + entry->setBody(body); + return true; +} + +/*! + \brief Saves this book and everything in it to the data directory. +*/ +void KJotsBook::saveBook(void) +{ + if (!m_open) //sanity check + return; + + // Are we a new book? + if ( m_fileName.isEmpty() ) + { + KTempFile temp(locateLocal("appdata",""), ".book", 0644); + m_fileName = temp.name(); + } + + QFile file(m_fileName); + if (file.open(IO_WriteOnly | IO_Truncate)) + { + QDomDocument doc("KJots"); + QDomElement root = doc.createElement( "KJots" ); + doc.appendChild( root ); + + this->generateXml( doc, root ); //recursive + + QTextStream st((QIODevice *) &file); + st.setEncoding( KJotsSettings::unicode() ? QTextStream::UnicodeUTF8 : QTextStream::Locale ); + st << doc.toString(); + + file.close(); + } + +} + +/*! + \brief Deletes a book by removing the data file. + This does not affect the list display, and can be called for reasons other than + choosing to delete an entry from the list. If you want the object to dissappear + from the list, then you have to delete it. +*/ +void KJotsBook::deleteBook() +{ + QFile::remove(m_fileName); + m_fileName = QString::null; +} + +void KJotsBook::rename() +{ + bool ok; + QString name = KInputDialog::getText(i18n( "Rename Book" ), + i18n( "Book name:" ), + subject(), &ok, listView()); + if (ok) + { + setSubject(name); + + KJotsMain* m = dynamic_cast<KJotsMain*>(kapp->mainWidget()); + + if (m) + m->updateCaption(); + + setDirty(true); + } +} + +/*! + \brief Initiated when the user chooses to save this to a file. + This function gets everything ready to go to save to the disk. +*/ +void KJotsBook::saveToFile(KURL url, bool plainText, const QString& encoding) +{ + if (url.isEmpty() || m_saveInProgress) + return; + + m_saveToPlainText = plainText; + m_saveEncoding = QTextCodec::codecForName(encoding.ascii()); + KIO::TransferJob* job = KIO::put(url, -1, true, false, false); + + if (!job) + { + return; + } + + //NOTE: The current implementation does not need the progress dialog, but further + //revisions will likely use it. I don't want to make the translators add, remove, + //and re-add translations, so I'm just keeping this here for now. + m_saveProgressDialog = new KProgressDialog(listView(), "bookSaveInProgress", + i18n("Saving %1").arg(subject()), + i18n("Saving the contents of %1 to %2") + .arg(subject(), url.prettyURL()), + true); + + m_saveProgressDialog->progressBar()->setTotalSteps(1); + m_saveProgressDialog->showCancelButton(false); + m_saveProgressDialog->setAutoClose(true); + + connect(job, SIGNAL(dataReq(KIO::Job*, QByteArray&)), SLOT(saveDataReq(KIO::Job*, QByteArray&))); + connect(job, SIGNAL(result( KIO::Job *)), SLOT(slotSaveResult( KIO::Job *))); + + m_saveInProgress = true; +} + +/*! + \brief Pumps out data when saving to a file. + This function pumps out page data during a disk save. +*/ +void KJotsBook::saveDataReq(KIO::Job* /* job */, QByteArray& data) +{ + if (!m_saveInProgress) return; //sanity check + + QTextStream stream(data, IO_WriteOnly); + stream.setCodec(m_saveEncoding); + + if (!m_saveToPlainText) + { + stream << htmlHeader(subject(), m_saveEncoding); + stream << generateHtml(this, true); + stream << htmlFooter(); + } else { + stream << generateText(); + } + + m_saveInProgress = false; +} + +/*! + \brief Completes a disk save. + This function is called after a disk save. The disk save may or may + not have completed normally. +*/ +void KJotsBook::slotSaveResult(KIO::Job *) +{ + m_saveInProgress = false; + delete m_saveProgressDialog; + m_saveProgressDialog = 0; + /* if (job->error() != 0) {} */ +} + +/*! + \brief Add a new page to the end of this book. +*/ +KJotsPage* KJotsBook::addPage() +{ + QListViewItem *after = 0; + + // append new pages + QListViewItem* tmp = firstChild(); + while (tmp) + { + after = tmp; + tmp = tmp->nextSibling(); + } + + KJotsPage *page = new KJotsPage(this, after); + page->initNewPage(); + return page; +} + +/*! + \brief Called when the user wants to print the book. +*/ +void KJotsBook::print(QFont& defaultFont) +{ + KPrinter printer; + printer.setDocName(subject()); + printer.setFullPage(false); + printer.setCreator("KJots"); + + if (!printer.setup(listView(), i18n("Print: %1").arg(subject()))) + { + return; + } + + QPainter painter(&printer); + painter.setFont(defaultFont); + print(printer, painter, 0); + + painter.end(); +} + +/*! + \brief Prints this book. +*/ +int KJotsBook::print(KPrinter& printer, QPainter& painter, int y) +{ + y = printTitleBox(subject(), printer, painter, y); + + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while (entry) + { + y = entry->print(printer, painter, y); + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + return y; +} + +QString KJotsBook::defaultSubject() +{ + return i18n("Untitled Book"); +} + +/*! + \brief Does this book need to be saved? + This function recursively checks itself, and all books and pages it owns to + see if any changes have been made. +*/ +bool KJotsBook::isDirty() +{ + //Am I dirty? + if ( KJotsEntryBase::isDirty() ) return true; + + //Check all children to see if any of them are dirty + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while ( entry ) + { + if ( entry->isDirty() ) return true; + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + return false; +} + +/*! + \brief Creates XML code and performs necessary tasks to save file. + This function should ONLY be called when saving the file. +*/ +void KJotsBook::generateXml( QDomDocument &doc, QDomElement &parent ) +{ + QDomElement book = doc.createElement( "KJotsBook" ); + parent.appendChild( book ); + + KJotsEntryBase::generateXml(doc, book); //let the base class save important stuff + + QDomElement open = doc.createElement( "Open" ); + open.appendChild( this->isOpen() ? doc.createTextNode("1") : doc.createTextNode("0") ); + book.appendChild( open ); + + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while ( entry ) + { + entry->generateXml( doc, book ); + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + if ( !m_fileName.isEmpty() && QListViewItem::parent() ) + { + //Hmmmm... We were originally loaded from a file, but now we have a parent, so + //we must have been moved into another tree. Remove the old file now that we + //have saved ourselves into the new tree. + deleteBook(); + } + + return; +} + +/*! + Parses through XML code from a file. +*/ +void KJotsBook::parseXml( QDomElement &me ) +{ + KJotsEntryBase *lastEntry = 0; //keep track of the last entry inserted for speed + + if ( me.tagName() == "KJotsBook" ) + { + QDomNode n = me.firstChild(); + while( !n.isNull() ) + { + QDomElement e = n.toElement(); // try to convert the node to an element. + if ( !e.isNull() ) + { + if ( e.tagName() == "KJotsPage" ) + { + KJotsPage *page = new KJotsPage(this, lastEntry); + page->parseXml(e); + lastEntry=page; + } + else + if ( e.tagName() == "KJotsBook" ) + { + KJotsBook *book = new KJotsBook(this, lastEntry); + book->parseXml(e); + lastEntry=book; + } + else + if ( e.tagName() == "Open" ) + { + if ( e.text() == "1" ) + { + this->setOpen(true); + } + } + else + { + //What was this? Send it to the base class and see if it can figure it out. + KJotsEntryBase::parseXml(e); + } + } + n = n.nextSibling(); + } + } + + return; +} + +/*! + \brief Returns an HTML Table of contents for this book. + This is a helper function for generateHtml(). +*/ +QString KJotsBook::getToc() +{ + QString toc; + + toc += "<ul>"; + + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while ( entry ) { + QString htmlSubject = prepForHTML(entry->subject()); + toc += QString("<li><a href=\"#%1\">").arg(entry->id()) + htmlSubject + "</a></li>"; + + KJotsBook *book = dynamic_cast<KJotsBook*>(entry); + if ( book ) toc += book->getToc(); + + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + toc += "</ul>"; + return toc; +} + +/*! + \brief Returns HTML for the read-only "book" view. + \param top Pointer to the "starting point" of this tree. + \param diskMode Files saved to disk have a slightly different format. +*/ +QString KJotsBook::generateHtml( KJotsEntryBase* top, bool diskMode ) +{ + QString toc, body; + QString htmlTitle = prepForHTML(subject()); + + if ( top == this ) + { + toc = QString("<h1><a name=\"%1\">%2</a></h1>").arg(id()).arg(htmlTitle); + } else { + if ( diskMode ) + { + toc = QString("<h2><a name=\"%1\">%2</a></h2>").arg(id()).arg(htmlTitle); + } else { + toc = QString("<h2><a name=\"%1\" href=\"%2\">%3</a></h2>").arg(id()).arg(id()).arg(htmlTitle); + } + } + + toc += "<h3>" + i18n("Table of Contents") + "</h3>"; + toc += getToc(); + toc += "<hr>"; + + // Do the body text of the entries. + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while ( entry ) + { + body += entry->generateHtml(top, diskMode); + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + return toc + body; +} + +/*! + \brief Returns Text when saving to a file. + + This functions output moderately formatted text when the user chooses to save as + a text file. +*/ +QString KJotsBook::generateText( void ) +{ + QString out; + + //Print Fancy Text header + QString line, buf; + line.fill('#', subject().length() + 2); + line += "\n"; + out = line + QString("# ") + subject() + QString("\n") + line; + + KJotsEntryBase* entry = dynamic_cast<KJotsEntryBase*>(firstChild()); + while ( entry ) + { + out += entry->generateText(); + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + + out += "\n"; + return out; +} + +// +// KJotsPage +// + +KJotsPage::KJotsPage(KJotsBook* parent, QListViewItem *after) + : KJotsEntryBase(parent,after), + m_editor(0) +{ + m_isBook = false; + m_paraPos = m_indexPos = 0; + setPixmap(0, kapp->iconLoader()->loadIcon(QString("edit"), KIcon::Small)); +} + +KJotsPage::~KJotsPage() +{ + if ( m_editor ) + { + //Well now, this isn't good. We're going bye-bye but the editor + //still thinks we're here. Set ourselves to 0 (IMPORTANT!!) and + //then clear the editor. + KJotsEdit *temp = m_editor; + m_editor=0; + temp->setEntry(0); + } +} + +/*! + \brief Sets up info for a new page. + + This should be called on brand new pages. +*/ +void KJotsPage::initNewPage(void) +{ + setId(0); + setSubject(defaultSubject()); +} + +/*! + \brief Return the text of this page. +*/ +QString KJotsPage::body() +{ + //if we're being edited we want the current text, not whatever we saved before. + if ( m_editor && m_editor->edited() ) + { + m_text = m_editor->text(); + m_editor->setEdited(false); + setDirty(true); + } + + return m_text; +} + +/*! + \brief Sets the text of this page. +*/ +void KJotsPage::setBody(const QString& text) +{ + assert ( !m_editor ); //m_editor should *never* be set. + m_text = text; +} + +void KJotsPage::rename() +{ + bool ok; + + QString name = KInputDialog::getText(i18n( "Rename Page" ), + i18n( "Page title:" ), + subject(), &ok, listView() ); + + if (ok) + { + setSubject(name); + + KJotsMain* m = dynamic_cast<KJotsMain*>(kapp->mainWidget()); + + if (m) + m->updateCaption(); + + setDirty(true); + } +} + +/*! + \brief Initiated when the user chooses to save this to a file. + This function gets everything ready to go to save to the disk. +*/ +void KJotsPage::saveToFile(KURL url, bool plainText, const QString& encoding) +{ + if (url.isEmpty() || m_saveInProgress) + return; + + m_saveToPlainText = plainText; + m_saveEncoding = QTextCodec::codecForName(encoding.ascii()); + KIO::TransferJob* job = KIO::put(url, -1, true, false, false); + if (!job) + { + return; + } + + connect(job, SIGNAL(dataReq(KIO::Job*, QByteArray&)), SLOT(saveDataReq(KIO::Job*, QByteArray&))); + connect(job, SIGNAL(result( KIO::Job *)), SLOT(slotSaveResult( KIO::Job *))); + m_saveInProgress = true; +} + +/*! + \brief Pumps out data when saving to a file. + This function pumps out page data during a disk save. + + \todo This should be augmented to cycle in case of REALLY long pages. +*/ +void KJotsPage::saveDataReq(KIO::Job* /* job */, QByteArray& data) +{ + if (!m_saveInProgress) return; //sanity check + + QTextStream stream(data, IO_WriteOnly); + stream.setCodec(m_saveEncoding); + + if ( !m_saveToPlainText ) + { + stream << htmlHeader(subject(), m_saveEncoding); + stream << generateHtml(this, true); + stream << htmlFooter(); + } else { + stream << generateText(); + } + + m_saveInProgress = false; +} + +/*! + \brief Completes a disk save. + This function is called after a disk save. The disk save may or may + not have completed normally. +*/ +void KJotsPage::slotSaveResult(KIO::Job *) +{ + m_saveInProgress = false; + /* if (job->error() != 0) {} */ +} + +void KJotsPage::print(QFont& defaultFont) +{ + KJotsEntryBase* book = dynamic_cast<KJotsEntryBase*>(KListViewItem::parent()); + + QString docName = book->subject(); + if (!subject().isNull()) + { + docName += ": " + subject(); + } + + KPrinter printer; + printer.setDocName(docName); + printer.setFullPage(false); + printer.setCreator("KJots"); + + if (printer.setup(listView(), i18n("Print: %1").arg(docName))) + { + QPainter painter( &printer ); + painter.setFont(defaultFont); + print(printer, painter, 0); + painter.end(); + } +} + +/*! + \brief Prints this page. +*/ +int KJotsPage::print(KPrinter& printer, QPainter& painter, int y) +{ + QPaintDeviceMetrics metrics( &printer ); + int maxWidth = metrics.width(); + int maxHeight = metrics.height(); + //TODO: Is it really necessary to copy the entire body when printing? + QStringList paragraphs = QStringList::split(QChar('\n'), body(), true); + + y = printTitleBox(subject(), printer, painter, y); + + for (QStringList::iterator para = paragraphs.begin(); + para != paragraphs.end(); + ++para) + { + //Watch for blank lines inserted as spacers. + if ( (*para).isNull() ) *para = " "; + + QRect r = painter.boundingRect(0, y, + maxWidth, maxHeight, + QPainter::ExpandTabs | QPainter::WordBreak, + *para); + + if ((y + r.height()) > maxHeight) + { + printer.newPage(); + y = 0; + } + + painter.drawText(0, y, maxWidth, maxHeight - y, + QPainter::ExpandTabs | QPainter::WordBreak, + *para); + y += r.height(); + } + + return y; +} + +/*! + \brief Get the default title of this page. + \note This is only used by initNewPage(); it could probably be removed. +*/ +QString KJotsPage::defaultSubject() +{ + int page = 0; + + if ( parentBook() ) + { + //We can't use childCount() here because it will count books, too. + KJotsEntryBase *entry = dynamic_cast<KJotsEntryBase*>(parentBook()->firstChild()); + while ( entry ) + { + if ( entry->isPage() ) ++page; + entry = dynamic_cast<KJotsEntryBase*>(entry->nextSibling()); + } + } else { + //We should never be here. + page = 1; + } + + return i18n("Page %1").arg(page); +} + +/*! + \brief Tells this page that it has been loaded into the edit window. +*/ +void KJotsPage::setEditor( KJotsEdit *editor ) +{ + //out with the old... + if ( m_editor ) + { + m_editor->getCursorPosition(&m_paraPos, &m_indexPos); + + if ( m_editor->edited() ) + { + m_text = m_editor->text(); + setDirty(true); + } + } + + m_editor = editor; + + //and in with the new + if ( m_editor ) + { + m_editor->setEdited(false); + m_editor->setCursorPosition(m_paraPos, m_indexPos); + } + + return; +} + +/*! + \brief Has the data in this page been changed? + We first check the editor status, if we are being edited. Then we let + the base class handle things for us. +*/ +bool KJotsPage::isDirty() +{ + if ( m_editor && m_editor->edited() ) + { + setDirty(true); + } + + return KJotsEntryBase::isDirty(); +} + +/*! + \brief Creates XML code and performs necessary tasks to save file. + This function should ONLY be called when saving the file. +*/void KJotsPage::generateXml( QDomDocument &doc, QDomElement &parent ) +{ + QDomElement page = doc.createElement( "KJotsPage" ); + parent.appendChild( page ); + + KJotsEntryBase::generateXml(doc, page); //let the base class save important stuff + + QDomElement text = doc.createElement( "Text" ); + QString saveText = body(); + if ( saveText.contains("]]>") ) { + saveText.replace("]]>","]]>"); + text.setAttribute("fixed", "1"); + } + text.appendChild( doc.createCDATASection( saveText )); + page.appendChild( text ); + + return; +} + +/*! + Parses through XML code from a file. +*/ +void KJotsPage::parseXml( QDomElement &me ) +{ + if ( me.tagName() == "KJotsPage" ) + { + QDomNode n = me.firstChild(); + while( !n.isNull() ) + { + QDomElement e = n.toElement(); // try to convert the node to an element. + if ( !e.isNull() ) + { + if ( e.tagName() == "Text" ) + { + QString bodyText = e.text(); + if ( e.hasAttribute("fixed") ) + { + bodyText.replace("]]>", "]]>"); + } + setBody(bodyText); + } + else + { + //What was this? Send it to the base class and see if it can figure it out. + KJotsEntryBase::parseXml(e); + } + } + n = n.nextSibling(); + } + } + + return; +} + +/*! + \brief Returns HTML for the read-only "book" overview. + \param top This tells us that we are the toplevel. + \param diskMode Files saved to disk have a slightly different format. +*/ +QString KJotsPage::generateHtml( KJotsEntryBase *top, bool diskMode ) +{ + QString html; + QString htmlSubject = prepForHTML(subject()); + + if ( top == this || diskMode ) { + html += QString("<h3><a name=\"%1\">%2</a></h3>").arg(id()).arg(htmlSubject); + } else { + html += QString("<h3><a name=\"%1\" href=\"%2\">%3</a></h3>").arg(id()).arg(id()).arg(htmlSubject); + } + html += prepForHTML(body()); + + html += "<br><table border=1><tr>"; + html += QString("<td><a href=\"#%1\">%2</a></td>").arg(id()).arg(subject()); + + if ( top != this ) + { + KJotsBook *parent = parentBook(); + while ( parent ) + { + html += QString("<td><a href=\"#%1\">%2</a></td>").arg(parent->id()).arg(parent->subject()); + if ( parent == top ) break; + parent = parent->parentBook(); + } + } + html += QString("</tr></table>"); + + if ( top != this ) html += "<hr>"; + return html; +} + +/*! + \brief Returns Text when saving to a file. + \param top This is a hint to specify if this book is the "starting point" or not. + + This functions output moderately formatted text when the user chooses to save as + a text file. +*/ +QString KJotsPage::generateText( void ) +{ + QString out; + + //Print Fancy Text header + QString line, buf; + line.fill('#', subject().length() + 2); + line += "\n"; + out = line + QString("# ") + subject() + QString("\n") + line; + + out += body(); + + out += "\n"; + return out; +} + +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ + +#include "kjotsentry.moc" diff --git a/kjots/kjotsentry.h b/kjots/kjotsentry.h new file mode 100644 index 0000000..a16d176 --- /dev/null +++ b/kjots/kjotsentry.h @@ -0,0 +1,179 @@ +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// Copyright (C) 2002, 2003 Aaron J. Seigo +// Copyright (C) 2003 Stanislav Kljuhhin +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef __KJOTSENTRY_H +#define __KJOTSENTRY_H + +#include <klistview.h> +#include <kprinter.h> + +// +// class KJotsEntryBase +// + +class KURL; +class KJotsPage; +class KProgressDialog; +class KJotsEdit; +class QTextCodec; +class QDomDocument; +class QDomElement; +class QFile; + +class KJotsBook; + +namespace KIO +{ + class Job; +} + +class KJotsEntryBase : public QObject, public KListViewItem +{ + Q_OBJECT + public: + KJotsEntryBase(KListView*, QListViewItem*); + KJotsEntryBase(KListViewItem*, QListViewItem*); + + public: + virtual void setSubject(const QString&); + QString subject() { return text(0); } + void setText(int,const QString&); + virtual void saveToFile(KURL, bool plainText, const QString& encoding) = 0; + virtual void print(QFont& defaultFont) = 0; + virtual int print(KPrinter&, QPainter&, int) = 0; + virtual QString defaultSubject() = 0; //!< "subject" is the caption name + virtual void rename() = 0; + virtual void generateXml( QDomDocument&, QDomElement& ); + virtual void parseXml( QDomElement& ); + virtual QString generateHtml( KJotsEntryBase*, bool ) = 0; + virtual QString generateText( void ) = 0; + + void setDirty(bool d) { m_dirty = d; } //!< Toggles the dirty flag. + virtual bool isDirty() { return m_dirty; }; //!< Accessor for dirty flag. + + Q_UINT64 id() { return m_id; } + void setId(Q_UINT64); + + KJotsBook *parentBook() { return m_parent; } + void resetParent(); + + bool isBook() const { return m_isBook; } + bool isPage() const { return !m_isBook; } + + protected: + int printTitleBox(QString, KPrinter&, QPainter&, int); + + bool m_saveInProgress; //!< Toggled during a manual disk save. + bool m_isBook; //!< used for speed and code clarity. + + private: + Q_UINT64 m_id; //!< unique ID for this entry + bool m_dirty; //!< Set when this entry has been changed. + KJotsBook *m_parent; //!< used during drag-n-drop moving +}; + +// +// class KjotsBook +// + +class KJotsBook : public KJotsEntryBase +{ + Q_OBJECT + public: + KJotsBook(KListView*, QListViewItem* after = 0); + KJotsBook(KListViewItem*, QListViewItem* after = 0); + ~KJotsBook(); + + static bool isBookFile(const QString& book); + bool openBook(const QString&); + void saveBook(); + void deleteBook(); + void rename(); + void saveToFile(KURL, bool plainText, const QString& encoding); + KJotsPage* addPage(); //!< Add a new page to this book. + void print(QFont& defaultFont); + int print(KPrinter&, QPainter&, int); + bool isDirty(); + QString defaultSubject(); + void generateXml( QDomDocument&, QDomElement& ); + void parseXml( QDomElement& ); + QString generateHtml( KJotsEntryBase*, bool ); + QString generateText( void ); + + protected slots: + void saveDataReq(KIO::Job* job, QByteArray& data); + void slotSaveResult(KIO::Job*); + + private: + QString getToc(); + bool loadOldBook(QFile &); + void init(); + + bool m_open; + QString m_fileName; + bool m_saveToPlainText; + QTextCodec* m_saveEncoding; + KProgressDialog* m_saveProgressDialog; +}; + +// +// class KJotsPage +// +class KJotsPage : public KJotsEntryBase +{ + Q_OBJECT + public: + KJotsPage(KJotsBook* parent, QListViewItem* after = 0); + ~KJotsPage(); + + public: + QString body(); + void setBody(const QString&); + void saveToFile(KURL, bool plainText, const QString& encoding); + void print(QFont& defaultFont); + int print(KPrinter&, QPainter&, int); + QString defaultSubject(); + void rename(); + + void setEditor(KJotsEdit*); + bool isDirty(); + void generateXml( QDomDocument&, QDomElement& ); + void parseXml( QDomElement& ); + void initNewPage(void); + QString generateHtml( KJotsEntryBase*, bool ); + QString generateText( void ); + + protected slots: + void saveDataReq(KIO::Job* job, QByteArray& data); + void slotSaveResult(KIO::Job*); + + private: + QString m_text; + QTextCodec* m_saveEncoding; + bool m_saveToPlainText; + KJotsEdit *m_editor; //!< ptr to editor if this is the active subject + int m_paraPos; //< used to remrmber the cursor position + int m_indexPos; //< used to remrmber the cursor position +}; + +#endif // __KJOTSENTRY_H +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/kjots/kjotsui.rc b/kjots/kjotsui.rc new file mode 100644 index 0000000..6c63a07 --- /dev/null +++ b/kjots/kjotsui.rc @@ -0,0 +1,41 @@ +<!DOCTYPE kpartgui> +<kpartgui version="2" name="kjots" > + <MenuBar> + + <Menu name="file"> + <Action name="new_page" append="new_merge"/> + <Action name="new_book" append="new_merge"/> + <Separator/> + <Action name="save_page_to" append="save_merge"/> + <Action name="save_book_to" append="save_merge"/> + <Separator/> + <Action name="del_page" append="save_merge"/> + <Action name="del_folder" append="save_merge"/> + </Menu> + + <Menu name="edit"> + <Action name="copyIntoTitle" append="edit_paste_merge"/> + <Action name="rename_entry"/> + <Action name="insert_date"/> + </Menu> + + <Menu name="go_document"> + <Action name="go_next_page"/> + <Action name="go_prev_page"/> + <Separator/> + <Action name="go_next_book"/> + <Action name="go_prev_book"/> + </Menu> + + <Action name="bookmarks"/> + + <Menu name="settings"></Menu> + + <Menu name="help"></Menu> + </MenuBar> + + <ToolBar name="mainToolBar" fullWidth="true" > + <Separator/> + <Action name="insert_date"/> + </ToolBar> +</kpartgui> diff --git a/kjots/main.cpp b/kjots/main.cpp new file mode 100644 index 0000000..4b0c10d --- /dev/null +++ b/kjots/main.cpp @@ -0,0 +1,98 @@ +// -*- C++ -*- + +// +// kjots +// +// Copyright (C) 1997 Christoph Neerfeld +// email: Christoph.Neerfeld@home.ivm.de or chris@kde.org +// +// 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; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include <stdlib.h> +#include <kuniqueapplication.h> +#include <kcmdlineargs.h> +#include <kconfig.h> +#include <kaboutdata.h> + +#include "KJotsMain.h" + + +static const char description[] = I18N_NOOP("KDE note taking utility"); + +static const char version[] = "v0.7"; + + +int main( int argc, char **argv ) +{ + KAboutData aboutData( "kjots", I18N_NOOP("KJots"), + version, description, KAboutData::License_GPL, + "(c) 1997-2002, Christoph Neerfeld"); + aboutData.addAuthor("Pradeepto K. Bhattacharya", I18N_NOOP("Current maintainer"), "pradeepto@kde.org"); + aboutData.addAuthor("Jaison Lee", 0, "lee.jaison@gmail.com"); + aboutData.addAuthor("Aaron J. Seigo", 0, "aseigo@kde.org"); + aboutData.addAuthor("Stanislav Kljuhhin", 0, "crz@starman.ee"); + aboutData.addAuthor("Christoph Neerfeld", I18N_NOOP("Original author"), "chris@kde.org"); + KCmdLineArgs::init(argc, argv, &aboutData); + KUniqueApplication::addCmdLineOptions(); + + if (!KUniqueApplication::start()) + { + fprintf(stderr, "kjots is already running!\n"); + exit(0); + } + + KUniqueApplication a; + + // backwards compatibility code to convert "old" user font settings + // to the new config settings + KConfig *config = a.config(); + config->setGroup("kjots"); + if (config->hasKey("EFontFamily")) { + // read old font and create it + QFont font( config->readEntry("EFontFamily"), + config->readNumEntry("EFontSize", 12), + config->readNumEntry("EFontWeight", 0), + config->readNumEntry("EFontItalic", 0)); + // delete old entries + config->deleteEntry("EFontFamily"); + config->deleteEntry("EFontSize"); + config->deleteEntry("EFontWeight"); + config->deleteEntry("EFontItalic"); + config->deleteEntry("EFontCharset"); + // write new "converted" entry + config->writeEntry("Font", font); + } + + KJotsMain *jots = new KJotsMain; + if( a.isRestored() ) + { + if( KJotsMain::canBeRestored(1) ) + { + jots->restore(1); + } + } + + a.setMainWidget( (QWidget *) jots ); + jots->show(); + jots->resize(jots->size()); + return a.exec(); +} + +/* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ |