00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "kjotsentry.h"
00027
00028 #include <QTextCodec>
00029 #include <QTextDocumentFragment>
00030 #include <qdom.h>
00031
00032 #include <kiconloader.h>
00033 #include <kinputdialog.h>
00034 #include <klocale.h>
00035 #include <kmessagebox.h>
00036 #include <kstandarddirs.h>
00037 #include <ktemporaryfile.h>
00038 #include <ksavefile.h>
00039
00040 #include <assert.h>
00041
00042 #include "kjotsedit.h"
00043 #include "KJotsMain.h"
00044 #include "KJotsSettings.h"
00045
00046 QSet<quint64> KJotsEntry::all_ids;
00047
00048
00049
00050
00051 KJotsEntry::KJotsEntry()
00052 {
00053 m_id = 0;
00054 }
00055
00056 void KJotsEntry::setTitle(const QString& title)
00057 {
00058 setText(0, title);
00059 }
00060
00064 KJotsBook* KJotsEntry::parentBook()
00065 {
00066 return dynamic_cast<KJotsBook*>(QTreeWidgetItem::parent());
00067 }
00068
00072 KJotsBook* KJotsEntry::topLevelBook()
00073 {
00074 KJotsBook *topBook = parentBook();
00075 if ( !topBook ) {
00076 topBook = static_cast<KJotsBook*>(this);
00077 } else {
00078 while ( topBook->parentBook() ) {
00079 topBook = topBook->parentBook();
00080 }
00081 }
00082
00083 return topBook;
00084 }
00085
00093 void KJotsEntry::setId(quint64 id)
00094 {
00095 if ( id && all_ids.contains(id) ) {
00096
00097
00098
00099 KMessageBox::ButtonCode answer = (KMessageBox::ButtonCode) KMessageBox::warningYesNo(0,
00100 i18n("A duplicate ID was found in the book %1. This can happen if you "
00101 "manipulate the data files by hand, and will prevent KJots from working correctly."
00102 " KJots can attempt to fix this, or you can fix it yourself. In either "
00103 "case, bookmarks and links between pages may be broken.", title()),
00104 i18n("A duplicate ID was found"), KGuiItem(i18n("Exit and fix by hand")),
00105 KGuiItem(i18n("Fix it automatically")), "duplicateIdError",
00106 (KMessageBox::Notify | KMessageBox::Dangerous) );
00107
00108 if ( answer == KMessageBox::Yes ) {
00109 QCoreApplication::exit(1);
00110 } else {
00111 id = 0;
00112 topLevelBook()->m_dirty = true;
00113 }
00114 }
00115
00116
00117 if ( id == 0 ) {
00118 quint64 lastId = KJotsSettings::lastId();
00119
00120
00121 do {
00122 id = ++lastId;
00123 if ( id == 0 ) {
00124 id = ++lastId;
00125 }
00126 } while ( all_ids.contains(id) );
00127 KJotsSettings::setLastId(id);
00128 }
00129
00130 all_ids << id;
00131 m_id = id;
00132 return;
00133 }
00134
00140 void KJotsEntry::generateXml( QDomDocument &doc, QDomElement &parent )
00141 {
00142 QDomElement title = doc.createElement( "Title" );
00143 title.appendChild( doc.createTextNode( text(0) ));
00144 parent.appendChild( title );
00145
00146 QDomElement id = doc.createElement( "ID" );
00147 QString id_string;
00148 id_string.setNum(m_id);
00149 id.appendChild( doc.createTextNode(id_string) );
00150 parent.appendChild( id );
00151
00152 QColor currentColor = backgroundColor(0);
00153 if ( currentColor.isValid() ) {
00154 QDomElement color = doc.createElement( "Color" );
00155 color.appendChild( doc.createTextNode( currentColor.name() ));
00156 parent.appendChild( color );
00157 }
00158
00159 return;
00160 }
00161
00165 void KJotsEntry::parseXml( QDomElement &e, bool )
00166 {
00167 if ( !e.isNull() )
00168 {
00169 if ( e.tagName() == "Title" )
00170 {
00171 setTitle(e.text());
00172 }
00173 else
00174 if ( e.tagName() == "ID" )
00175 {
00176 setId(e.text().toULongLong());
00177 }
00178 else
00179 if ( e.tagName() == "Color" )
00180 {
00181 QColor color( e.text() );
00182 setBackgroundColor(0, color);
00183 }
00184 }
00185
00186 return;
00187 }
00188
00189
00190
00191
00192 KJotsBook::KJotsBook()
00193 {
00194 m_isBook = true;
00195 m_open = m_shouldBeOpened = m_dirty = false;
00196 setIcon(0, KIconLoader::global()->loadIcon(QString("x-office-address-book"),KIconLoader::Small));
00197 setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
00198 | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled);
00199 }
00200
00201 KJotsBook::~KJotsBook()
00202 {
00203 }
00204
00208 void KJotsBook::setDirty(bool dirty)
00209 {
00210
00211 if ( !m_open ) return;
00212
00213 topLevelBook()->m_dirty = dirty;
00214 }
00215
00219 bool KJotsBook::dirty()
00220 {
00221 return topLevelBook()->m_dirty;
00222 }
00223
00228 bool KJotsBook::openBook(const QString& filename)
00229 {
00230
00231 if ( m_open ) return true;
00232
00233 m_fileName = filename;
00234
00235
00236 if ( m_fileName.isEmpty() ) {
00237
00238 if (childCount() == 0){
00239 addPage();
00240 }
00241 m_open = m_dirty = true;
00242 setId(0);
00243 } else {
00244 QFile file(m_fileName);
00245 QDomDocument doc( "KJots" );
00246 bool oldBook = false;
00247
00248
00249 if ( !file.exists() || !file.open(QIODevice::ReadWrite) ) {
00250 return false;
00251 }
00252
00253
00254 QByteArray firstLine = file.readLine();
00255 file.reset();
00256
00257 if ( !firstLine.startsWith("<?xml") ) {
00258 kDebug(0) << m_fileName << " is an old-style book." ;
00259
00260 QTextStream st(&file);
00261 if ( KJotsSettings::unicode() ) {
00262 st.setCodec( "UTF-8" );
00263 } else {
00264 st.setCodec( QTextCodec::codecForLocale () );
00265 }
00266
00267 doc.setContent( st.readAll() );
00268 oldBook = true;
00269 } else {
00270 doc.setContent(&file);
00271 }
00272
00273 QDomElement docElem = doc.documentElement();
00274
00275 if ( docElem.tagName() == "KJots" ) {
00276 QDomNode n = docElem.firstChild();
00277 while( !n.isNull() ) {
00278 QDomElement e = n.toElement();
00279 if( !e.isNull() && e.tagName() == "KJotsBook" ) {
00280 parseXml(e, oldBook);
00281 }
00282 n = n.nextSibling();
00283 }
00284
00285 m_open = true;
00286 }
00287 }
00288
00289 return m_open;
00290 }
00291
00295 void KJotsBook::saveBook(void)
00296 {
00297 bool failed = false;
00298
00299 if (!m_open)
00300 return;
00301
00302
00303 if ( m_fileName.isEmpty() ) {
00304 KTemporaryFile file;
00305 file.setPrefix(KStandardDirs::locateLocal("appdata",""));
00306 file.setSuffix(".book");
00307 file.setAutoRemove(false);
00308 if ( file.open() ) {
00309 m_fileName = file.fileName();
00310 } else {
00311 failed = true;
00312 }
00313 }
00314
00315 if ( !failed ) {
00316 KSaveFile file(m_fileName);
00317 if ( file.open() ) {
00318 QDomDocument doc("KJots");
00319 QDomElement root = doc.createElement( "KJots" );
00320 doc.appendChild( root );
00321
00322 this->generateXml( doc, root );
00323
00324 QTextStream st(&file);
00325 st.setCodec( "UTF-8" );
00326 st << "<?xml version='1.0' encoding='UTF-8' ?>\n";
00327 st << doc.toString();
00328 st.flush();
00329
00330 setDirty(false);
00331 } else {
00332 failed = true;
00333 }
00334 }
00335
00336 if ( failed ) {
00337 KMessageBox::error(0, i18n("<qt>KJots is having problems saving your data. " \
00338 "This might be a permissions problem, or you may be out of disk space.</qt>"));
00339 }
00340 }
00341
00348 void KJotsBook::deleteBook ( void )
00349 {
00350 QFile::remove(m_fileName);
00351 m_fileName.clear();
00352 }
00353
00357 void KJotsBook::rename()
00358 {
00359 bool ok;
00360 QString name = KInputDialog::getText(i18n( "Rename Book" ),
00361 i18n( "Book name:" ), title(), &ok, treeWidget());
00362
00363 if (ok) {
00364 setTitle(name);
00365 topLevelBook()->setDirty(true);
00366 }
00367 }
00368
00372 KJotsPage* KJotsBook::addPage(void)
00373 {
00374 int pageCount = 1;
00375
00376
00377 for ( int i=0; i<childCount(); i++ ) {
00378 if ( dynamic_cast<KJotsEntry*>(QTreeWidgetItem::child(i)) ) {
00379 ++pageCount;
00380 }
00381 }
00382
00383 KJotsPage *page = KJotsPage::createNewPage(pageCount);
00384 addChild(page);
00385 return page;
00386 }
00387
00392 void KJotsBook::generateXml( QDomDocument &doc, QDomElement &parent )
00393 {
00394 QDomElement book = doc.createElement( "KJotsBook" );
00395 parent.appendChild( book );
00396
00397 KJotsEntry::generateXml(doc, book);
00398
00399 QDomElement open = doc.createElement( "Open" );
00400 open.appendChild( treeWidget()->isItemExpanded(this) ? doc.createTextNode("1") : doc.createTextNode("0") );
00401 book.appendChild( open );
00402
00403 for ( int i=0; i<childCount(); i++ ) {
00404 KJotsEntry *entry = dynamic_cast<KJotsEntry*>(QTreeWidgetItem::child(i));
00405 if ( entry ) {
00406 entry->generateXml( doc, book );
00407 }
00408 }
00409
00410 if ( !m_fileName.isEmpty() && QTreeWidgetItem::parent() )
00411 {
00412
00413
00414
00415 deleteBook();
00416 }
00417
00418 return;
00419 }
00420
00424 void KJotsBook::parseXml( QDomElement &me, bool oldBook )
00425 {
00426 if ( me.tagName() == "KJotsBook" ) {
00427 QDomNode n = me.firstChild();
00428 while( !n.isNull() ) {
00429 QDomElement e = n.toElement();
00430 if ( !e.isNull() ) {
00431 if ( e.tagName() == "KJotsPage" ) {
00432 KJotsPage *page = new KJotsPage();
00433 addChild(page);
00434 page->parseXml(e, oldBook);
00435 }
00436 else if ( e.tagName() == "KJotsBook" ) {
00437 KJotsBook *book = new KJotsBook();
00438 addChild(book);
00439 book->parseXml(e, oldBook);
00440 }
00441 else if ( e.tagName() == "Open" ) {
00442 if ( e.text() == "1" ) {
00443
00444 m_shouldBeOpened = true;
00445 }
00446 } else {
00447
00448 KJotsEntry::parseXml(e, oldBook);
00449 }
00450 }
00451 n = n.nextSibling();
00452 }
00453 }
00454
00455 return;
00456 }
00457
00462 QString KJotsBook::getToc()
00463 {
00464 QString toc;
00465
00466 toc += "<ul>";
00467
00468 for ( int i=0; i<childCount(); i++ ) {
00469 KJotsEntry *entry = dynamic_cast<KJotsEntry*>(QTreeWidgetItem::child(i));
00470 if ( entry ) {
00471 QString htmlSubject = Qt::escape(entry->title());
00472 toc += QString("<li><a href=\"#%1\">").arg(entry->id()) + htmlSubject + "</a></li>";
00473
00474 KJotsBook *book = dynamic_cast<KJotsBook*>(entry);
00475 if ( book ) {
00476 toc += book->getToc();
00477 }
00478 }
00479 }
00480
00481 toc += "</ul><br>";
00482 return toc;
00483 }
00484
00490 void KJotsBook::generateHtml( KJotsEntry* top, bool diskMode, QTextCursor *cursorOut )
00491 {
00492 QString toc;
00493 QString htmlTitle = Qt::escape(title());
00494
00495 if ( top == this ) {
00496 toc = QString("<h1><a name=\"%1\">%2</a></h1>").arg(id()).arg(htmlTitle);
00497 } else {
00498 if ( diskMode ) {
00499 toc = QString("<h2><a name=\"%1\">%2</a></h2>").arg(id()).arg(htmlTitle);
00500 } else {
00501
00502 toc = QString("<h2><a name=\"%1\"> </a><a href=\"kjots://0.0.0.0/%2\">%3</a></h2>").arg(id()).arg(id()).arg(htmlTitle);
00503 }
00504 }
00505
00506 toc += "<table width=\"100%\"><tr><td>";
00507 toc += "<h3>" + i18n("Table of Contents") + "</h3>";
00508 toc += getToc();
00509 toc += "<hr /></td></tr></table>";
00510 cursorOut->insertFragment(QTextDocumentFragment::fromHtml(toc));
00511
00512
00513 foreach ( KJotsEntry *entry, children() ) {
00514 entry->generateHtml ( top, diskMode, cursorOut );
00515 }
00516
00517 return;
00518 }
00519
00526 QString KJotsBook::generateText( void )
00527 {
00528 QString out;
00529
00530
00531 QString line, buf;
00532 line.fill('#', title().length() + 2);
00533 line += '\n';
00534 out = line + QString("# ") + title() + QString("\n") + line;
00535
00536 foreach ( KJotsEntry *entry, children() ) {
00537 out += entry->generateText();
00538 }
00539
00540 out += '\n';
00541 return out;
00542 }
00543
00551 void KJotsBook::generatePrintData ( QTextCursor *cursor )
00552 {
00553 cursor->insertFragment(QTextDocumentFragment::fromHtml(
00554 QString ("<table border=1 width='100%'><tr><td><center>%1</center></td></tr></table>"
00555 ).arg(title()) ));
00556
00557 foreach ( KJotsEntry *entry, children() ) {
00558 entry->generatePrintData ( cursor );
00559 }
00560
00561 return;
00562 }
00563
00568 QList<KJotsEntry*> KJotsBook::contents ( void )
00569 {
00570 QList<KJotsEntry*> contents;
00571
00572 for ( int i=0; i<childCount(); i++ ) {
00573 contents << static_cast<KJotsEntry*>(QTreeWidgetItem::child(i));
00574 KJotsBook *childBook = dynamic_cast<KJotsBook*>(QTreeWidgetItem::child(i));
00575 if ( childBook ) {
00576 contents << childBook->contents();
00577 }
00578 }
00579
00580 return contents;
00581 }
00582
00587 QList<KJotsEntry*> KJotsBook::children ( void )
00588 {
00589 QList<KJotsEntry*> children;
00590
00591 for ( int i=0; i<childCount(); i++ ) {
00592 children << static_cast<KJotsEntry*>(QTreeWidgetItem::child(i));
00593 }
00594
00595 return children;
00596 }
00597
00598 KJotsBook *KJotsBook::createNewBook ( void )
00599 {
00600 KJotsBook *book = 0;
00601 bool ok;
00602
00603 QString name = KInputDialog::getText( i18n( "New Book" ),
00604 i18n( "Book name:" ), QString(), &ok );
00605
00606 if ( ok ) {
00607 book = new KJotsBook();
00608 book->setTitle(name);
00609 book->openBook(QString());
00610 }
00611
00612 return book;
00613 }
00614
00615
00616
00617
00618 KJotsPage::KJotsPage()
00619 {
00620 m_isBook = false;
00621 setIcon(0, KIconLoader::global()->loadIcon(QString("text-x-generic"), KIconLoader::Small));
00622 setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
00623 | Qt::ItemIsEnabled);
00624 connect(&document, SIGNAL(modificationChanged(bool)), SLOT(documentModified(bool)));
00625 }
00626
00627 KJotsPage::~KJotsPage()
00628 {
00629 }
00630
00634 KJotsPage *KJotsPage::createNewPage(int pageCount)
00635 {
00636 QString title = i18n("Page %1", pageCount);
00637
00638 if ( KJotsSettings::pageNamePrompt() ) {
00639 title = KInputDialog::getText( i18n( "New Page" ),
00640 i18n( "Page name:" ), title, 0 );
00641 }
00642
00643 KJotsPage *page = new KJotsPage();
00644 page->setId(0);
00645 page->setTitle(title);
00646 return page;
00647 }
00648
00655 void KJotsPage::documentModified(bool modified)
00656 {
00657 if ( modified ) {
00658 topLevelBook()->setDirty(true);
00659 }
00660
00661 return;
00662 }
00663
00667 void KJotsPage::rename()
00668 {
00669 bool ok;
00670 QString name = KInputDialog::getText(i18n( "Rename Page" ),
00671 i18n( "Page title:" ), title(), &ok, treeWidget() );
00672
00673 if (ok) {
00674 setTitle(name);
00675 topLevelBook()->setDirty(true);
00676 }
00677 }
00678 void KJotsPage::generateXml( QDomDocument &doc, QDomElement &parent )
00683 {
00684 QDomElement page = doc.createElement( "KJotsPage" );
00685 parent.appendChild( page );
00686
00687 KJotsEntry::generateXml(doc, page);
00688
00689 QDomElement text = doc.createElement( "Text" );
00690
00691 QString saveText = document.toHtml("UTF-8");
00692 text.appendChild( doc.createCDATASection( saveText ));
00693 page.appendChild( text );
00694
00695 return;
00696 }
00697
00701 void KJotsPage::parseXml( QDomElement &me, bool oldBook )
00702 {
00703 if ( me.tagName() == "KJotsPage" )
00704 {
00705 QDomNode n = me.firstChild();
00706 while( !n.isNull() )
00707 {
00708 QDomElement e = n.toElement();
00709 if ( !e.isNull() )
00710 {
00711 if ( e.tagName() == "Text" )
00712 {
00713 QString bodyText = e.text();
00714
00715
00716 if ( e.hasAttribute("fixed") ) {
00717 bodyText.replace("]]>", "]]>");
00718 }
00719
00720 if ( oldBook ) {
00721 bodyText = Qt::convertFromPlainText(bodyText, Qt::WhiteSpaceNormal);
00722 }
00723
00724 document.setHtml(bodyText);
00725 }
00726 else
00727 {
00728
00729 KJotsEntry::parseXml(e, oldBook);
00730 }
00731 }
00732 n = n.nextSibling();
00733 }
00734 }
00735
00736 return;
00737 }
00738
00744 void KJotsPage::generateHtml( KJotsEntry *top, bool diskMode, QTextCursor *cursorOut )
00745 {
00746 QTextBlockFormat defaultBlockFormat = cursorOut->blockFormat();
00747 QTextCharFormat defaultCharFormat = cursorOut->charFormat();
00748 QString html;
00749 QString htmlSubject = Qt::escape(title());
00750
00751 if ( diskMode ) {
00752 if ( top != this ) {
00753 html = "<table><tr><td>";
00754 html += QString("<h3><a name=\"%1\">%2</a></h3>").arg(id()).arg(htmlSubject);
00755 html += "</td></tr></table>";
00756 } else {
00757 html = "<table><tr><td>";
00758 html += QString("<h3>%1</h3>").arg(htmlSubject);
00759 html += "</td></tr></table>";
00760 }
00761 } else {
00762
00763
00764 html = "<table><tr><td>";
00765 html += QString("<h3><a name=\"%1\"> </a><a href=\"kjots://0.0.0.0/%2\" >%3</a></h3>").arg(id()).arg(id()).arg(htmlSubject);
00766 html += "</td></tr></table>";
00767 }
00768 html += "<br>";
00769
00770 cursorOut->insertFragment(QTextDocumentFragment::fromHtml(html));
00771 cursorOut->insertBlock(defaultBlockFormat, defaultCharFormat);
00772 html.clear();
00773
00774 QTextCursor allCursor ( &document );
00775 allCursor.select( QTextCursor::Document );
00776 cursorOut->insertFragment(allCursor.selection());
00777 cursorOut->insertBlock(defaultBlockFormat, defaultCharFormat);
00778
00779 if ( top != this ) {
00780 html = "<table width=\"100%\"><tr><td>";
00781 html += "<table border=1 cellpadding=\"10\"><tr>";
00782 html += QString("<td><a href=\"#%1\">%2</a></td>").arg(id()).arg(title());
00783
00784 KJotsBook *parent = parentBook();
00785 while ( parent ) {
00786 html += QString("<td><a href=\"#%1\">%2</a></td>").arg(parent->id()).arg(parent->title());
00787 if ( parent == top ) break;
00788 parent = parent->parentBook();
00789 }
00790
00791 html += QString("</tr></table>");
00792 html += "<hr /></td></tr></table>";
00793 }
00794
00795 cursorOut->insertFragment(QTextDocumentFragment::fromHtml(html));
00796
00797 return;
00798 }
00799
00807 QString KJotsPage::generateText( void )
00808 {
00809 QString out;
00810
00811
00812 QString line, buf;
00813 line.fill('#', title().length() + 2);
00814 line += '\n';
00815 out = line + QString("# ") + title() + QString("\n") + line;
00816
00817 out += document.toPlainText();
00818
00819 out += '\n';
00820 return out;
00821 }
00822
00830 void KJotsPage::generatePrintData ( QTextCursor *cursor )
00831 {
00832 QString docName = QString ("%1: %2").arg(parentBook()->title()).arg(title());
00833
00834 cursor->insertFragment(QTextDocumentFragment::fromHtml(
00835 QString ("<table border=1 width='100%'><tr><td><center>%1</center></td></tr></table>"
00836 ).arg(docName) ));
00837
00838 QTextCursor allCursor ( &document );
00839 allCursor.select( QTextCursor::Document );
00840 cursor->insertFragment(allCursor.selection());
00841
00842 return;
00843 }
00844
00845 #include "kjotsentry.moc"
00846
00847