KnowIt – tool for managing notes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
11KB

  1. /***************************************************************************
  2. notes.cpp - description
  3. -------------------
  4. begin : sob lis 16 2002
  5. copyright : (C) 2002-2004 by Micha³ Rudolf
  6. email : mrudolf@kdewebdev.org
  7. ***************************************************************************/
  8. /***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************/
  16. #include "notes.h"
  17. #include <tqstringlist.h>
  18. #include <tqfile.h>
  19. #include <tqdatetime.h>
  20. #include <tqtextstream.h>
  21. #include <tqtextcodec.h>
  22. #include <tdelocale.h>
  23. #include <tdelistview.h>
  24. #include <tdeglobal.h>
  25. #include <kiconloader.h>
  26. #include <kmimetype.h>
  27. #include <krun.h>
  28. #include <kurl.h>
  29. #include <tdelistview.h>
  30. #ifdef HAVE_CONFIG_H
  31. #include <config.h>
  32. #else
  33. #define VERSION "?"
  34. #endif
  35. void TNoteLink::save(TQTextStream& ts) const
  36. {
  37. if (!link.isEmpty()) {
  38. ts << "\\Link " << link << "\n";
  39. if (!description.isEmpty())
  40. ts << "\\Descr " << description << "\n";
  41. }
  42. }
  43. TQString TNoteLink::text(int fmt) const
  44. {
  45. if (fmt == LinkOnly || description.isEmpty()) return link;
  46. else if (fmt == DescriptionOnly) return description;
  47. else if (fmt == LinkDescription)
  48. return TQString("%1 (%2)").arg(link).arg(description);
  49. else return TQString("%1 (%2)").arg(description).arg(link);
  50. }
  51. TQPixmap TNoteLink::icon() const
  52. {
  53. return TDEGlobal::iconLoader()->loadIcon(KMimeType::iconForURL(KURL(link)),
  54. TDEIcon::Small);
  55. }
  56. void TNoteLink::open() const
  57. {
  58. if (!isLocalReference())
  59. new KRun(KURL(link), 0, false, true);
  60. }
  61. void TNoteLink::openWith() const
  62. {
  63. if (!isLocalReference())
  64. KRun::displayOpenWithDialog(KURL(link));
  65. }
  66. bool TNoteLink::isLocalReference() const
  67. {
  68. KURL url(link);
  69. return url.protocol() == "knowit";
  70. }
  71. TNotesCollection::TNotesCollection()
  72. {
  73. Pixmaps[0] = TDEGlobal::iconLoader()->loadIcon("ascii", TDEIcon::Small);
  74. Pixmaps[1] = TDEGlobal::iconLoader()->loadIcon("txt", TDEIcon::Small);
  75. Pixmaps[2] = TDEGlobal::iconLoader()->loadIcon("folder", TDEIcon::Small);
  76. Pixmaps[3] = TDEGlobal::iconLoader()->loadIcon("folder_txt", TDEIcon::Small);
  77. modified = false;
  78. autoUpdate = true;
  79. }
  80. TNotesCollection::~TNotesCollection()
  81. {}
  82. void TNotesCollection::addNote(TQListViewItem* item)
  83. {
  84. insert(item, new TNote(item, this));
  85. TQListViewItem* parent = item->parent();
  86. if (parent) find(parent)->updateView();
  87. modified = true;
  88. }
  89. void TNotesCollection::addNote(TQListViewItem* item, const TQString& s)
  90. {
  91. insert(item, new TNote(item, this, s));
  92. TQListViewItem* parent = item->parent();
  93. if (parent) find(parent)->updateView();
  94. modified = true;
  95. }
  96. void TNotesCollection::removeNote(TQListViewItem* item)
  97. {
  98. TNote* note = find(item);
  99. if (!note) tqWarning("Internal error while removing note\n");
  100. else {
  101. TQListViewItem* parent = item->parent();
  102. for (TQListViewItemIterator it(item); it.current() &&
  103. (it.current() == item || it.current()->depth() > item->depth()); ++it)
  104. find(it.current())->destroy();
  105. delete item;
  106. if (parent) find(parent)->updateView();
  107. modified = true;
  108. }
  109. }
  110. bool TNotesCollection::changeNote(TQListViewItem* item, const TQString& s)
  111. {
  112. TNote* changed = find(item);
  113. if (!changed) {
  114. tqWarning("Internal error while changing note\n");
  115. return false;
  116. }
  117. if (changed->change(s))
  118. return modified = true;
  119. else
  120. return false;
  121. }
  122. void TNotesCollection::clearNotes()
  123. {
  124. setAutoDelete(true);
  125. clear();
  126. setAutoDelete(false);
  127. }
  128. const TQString& TNotesCollection::text(TQListViewItem* item)
  129. {
  130. TNote* note = find(item);
  131. if (!note)
  132. tqFatal("Internal error while accessing note text\n");
  133. return note->text;
  134. }
  135. void TNotesCollection::updateNotesView()
  136. {
  137. for (TQPtrDictIterator<TNote> it(*this); it.current(); ++it)
  138. it.current()->updateView();
  139. }
  140. TNote::TNote(TQListViewItem* i, TNotesCollection* coll) : text()
  141. {
  142. collection = coll;
  143. item = i;
  144. updateView();
  145. }
  146. TNote::TNote(TQListViewItem* i, TNotesCollection* coll, const TQString& s) :
  147. text(s)
  148. {
  149. collection = coll;
  150. item = i;
  151. updateView();
  152. }
  153. bool TNote::isEmpty()
  154. {
  155. return !text.length();
  156. }
  157. bool TNote::contains(const TQString& sought, bool case_sensitive)
  158. {
  159. return text.contains(sought, case_sensitive);
  160. }
  161. TNote::~TNote()
  162. {
  163. }
  164. void TNote::destroy()
  165. {
  166. collection->remove(item);
  167. delete this;
  168. }
  169. bool TNote::change(const TQString& s)
  170. {
  171. if (text == s)
  172. return false;
  173. text = s;
  174. updateView();
  175. return true;
  176. }
  177. TNote::State TNote::state()
  178. {
  179. if (text.stripWhiteSpace().isEmpty())
  180. return (item->childCount()) ? EmptyParent : Empty;
  181. else
  182. return (item->childCount()) ? TextParent : Text;
  183. }
  184. void TNote::updateView()
  185. {
  186. if (collection->autoUpdate)
  187. item->setPixmap(0, collection->Pixmaps[state()]);
  188. }
  189. bool TNote::saveHTML(const KURL& fname, const TQString& origname, const TQString& style,
  190. int flags)
  191. {
  192. TQFile file(fname.path());
  193. if (!file.open( IO_WriteOnly))
  194. return false;
  195. TQTextStream ts(&file);
  196. if (flags & UseUTF8) ts.setEncoding(TQTextStream::UnicodeUTF8);
  197. else ts.setEncoding(TQTextStream::Locale);
  198. ts << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
  199. "<html>\n<head>\n <title>" << i18n("KnowIt document") <<
  200. TQString("</title>\n <meta http-equiv=\"Content-Type\" "
  201. "content=\"text/html; charset=%1\">\n").arg(ts.codec()->mimeName());
  202. if (!style.isEmpty())
  203. ts << " <style type=\"text/css\">\n " << style << "\n </style>\n";
  204. ts << "</head>\n\n<body>\n";
  205. TQValueVector<int> Depths;
  206. Depths.append(0);
  207. if (flags & TOC) {
  208. ts << TQString("<h1>%1</h1>\n").arg(i18n("Table of contents"));
  209. saveHTMLTocEntry(ts, Depths, flags);
  210. ts << "\n\n";
  211. }
  212. Depths.clear();
  213. Depths.append(0);
  214. saveHTMLBuf(ts, Depths, flags);
  215. TQString epilog = i18n("Exported from %1 by KnowIt %2, %3.");
  216. ts << "<br><br><br><small>" << epilog.arg(origname)
  217. .arg(VERSION)
  218. .arg(TQDateTime::currentDateTime().toString()) << "</small>\n\n";
  219. ts << "</body>\n</html>\n\n";
  220. return true;
  221. }
  222. bool TNote::saveHTMLBuf(TQTextStream& ts, TQValueVector<int>& depths,
  223. int flags)
  224. {
  225. int hlevel = depths.count();
  226. depths.last() = depths.last()+1;
  227. if (hlevel < 1) hlevel = 1;
  228. else if (hlevel > 3) hlevel = 3;
  229. TQString id, number;
  230. for (uint i=0; i<depths.count(); i++)
  231. id += TQString("%1.").arg(depths[i]);
  232. if (flags & Enumerate)
  233. number = id + " ";
  234. ts << TQString("<h%1 id=\"S%2\">%3%4</h%5>").arg(hlevel).arg(id).arg(number)
  235. .arg(item->text(0)).arg(hlevel);
  236. TQString htmltext = text;
  237. int begin = htmltext.find("<body");
  238. if (begin >= 0) begin = htmltext.find(">", begin);
  239. int end = htmltext.find("</body>");
  240. if (begin < 0) begin = 0;
  241. if (end <= begin) end = htmltext.length();
  242. ts << htmltext.mid(begin+1, end-begin-1);
  243. /* save links */
  244. for (TQValueList<TNoteLink>::Iterator LinkList = links.begin();
  245. LinkList != links.end(); ++LinkList)
  246. ts << TQString("<a href=\"%1\">%2</a><br>\n").arg((*LinkList).link)
  247. .arg((*LinkList).text(TNoteLink::DescriptionOnly));
  248. /* save rule */
  249. if (flags & AddRule) ts << "<hr size=\"1\" noshade>\n\n";
  250. else ts << "\n\n";
  251. /* save children */
  252. if ((SaveSubnotes | SaveAll) & flags && item->childCount()) {
  253. depths.append(0);
  254. collection->find(item->firstChild())->saveHTMLBuf(ts, depths, flags);
  255. }
  256. if ((SaveSubnotes | SaveAll) & flags && item->nextSibling())
  257. collection->find(item->nextSibling())->saveHTMLBuf(ts, depths, flags);
  258. if (!item->nextSibling()) depths.pop_back();
  259. return true;
  260. }
  261. bool TNote::saveHTMLTocEntry(TQTextStream& ts, TQValueVector<int>& depths, int flags)
  262. {
  263. TQString space;
  264. space.fill(' ', depths.count());
  265. depths.last() = depths.last()+1;
  266. if (depths.last() == 1) {
  267. ts << space;
  268. if (depths.count() != 1) ts << "<dd>";
  269. ts << "<dl>\n";
  270. }
  271. TQString id, number;
  272. for (uint i=0; i<depths.count(); i++)
  273. id += TQString("%1.").arg(depths[i]);
  274. if (flags & Enumerate) number = id + " ";
  275. ts << space;
  276. ts << TQString("<dt><a href=\"#S%1\">%2%3</a></dt>\n").arg(id).arg(number).
  277. arg(item->text(0));
  278. if ((SaveSubnotes | SaveAll) & flags && item->childCount()) {
  279. depths.append(0);
  280. collection->find(item->firstChild())->saveHTMLTocEntry(ts, depths, flags);
  281. }
  282. if ((SaveSubnotes | SaveAll) & flags && item->nextSibling())
  283. collection->find(item->nextSibling())->saveHTMLTocEntry(ts, depths, flags);
  284. if (!item->nextSibling()) {
  285. depths.pop_back();
  286. ts << space;
  287. ts << "</dl>";
  288. if (depths.count()) ts << "</dd>";
  289. ts << "\n";
  290. }
  291. return true;
  292. }
  293. void TNote::addLink(const TQString& s)
  294. {
  295. links.append(TNoteLink(s));
  296. collection->modified = true;
  297. }
  298. void TNote::addLink(const TNoteLink& l)
  299. {
  300. links.append(l);
  301. collection->modified = true;
  302. }
  303. void TNote::removeLink(int i)
  304. {
  305. links.remove(links[i]);
  306. collection->modified = true;
  307. }
  308. void TNote::modifyLink(int i, const TQString& s)
  309. {
  310. links[i].link = s;
  311. collection->modified = true;
  312. }
  313. void TNote::modifyLink(int i, TNoteLink& l)
  314. {
  315. if (l != links[i])
  316. collection->modified = true;
  317. links[i] = l;
  318. }
  319. void TNote::modifyLinkDescription(int i, const TQString& s)
  320. {
  321. links[i].description = s;
  322. collection->modified = true;
  323. }
  324. int TNote::linkCount() const
  325. {
  326. return links.count();
  327. }
  328. const TNoteLink& TNote::link(int i) const
  329. {
  330. return links[i];
  331. }
  332. void TNote::save(TQTextStream& ts, bool current)
  333. {
  334. const TQString header = "\\NewEntry %1 %2\n";
  335. const TQString activeheader = "\\CurrentEntry %1 %2\n";
  336. if (current)
  337. ts << activeheader.arg(item->depth()).arg(item->text(0));
  338. else
  339. ts << header.arg(item->depth()).arg(item->text(0));
  340. for (TQValueList<TNoteLink>::Iterator LinkList = links.begin();
  341. LinkList != links.end(); ++LinkList)
  342. (*LinkList).save(ts);
  343. ts << text;
  344. if (!text.isEmpty())
  345. ts << '\n';
  346. ts << '\n';
  347. }
  348. void TNote::open(TQTextStream& ts)
  349. {
  350. TQString s;
  351. text = "";
  352. links.clear();
  353. while (true) {
  354. s = ts.readLine();
  355. if (s.isNull() || s.isEmpty())
  356. break;
  357. if (s.left(6) == "\\Link ")
  358. addLink(s.mid(6));
  359. else if (s.left(7) == "\\Descr " && links.count())
  360. modifyLinkDescription(links.count()-1, s.mid(7));
  361. else {
  362. if (text.length())
  363. text += '\n';
  364. text += s;
  365. }
  366. }
  367. }