1 /***************************************************************************
2 * Copyright (C) 2003 by Sébastien Laoût *
3 * slaout@linux62.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "bnpview.h"
22
23 #include <QtCore/QList>
24 #include <QtCore/QRegExp>
25 #include <QtCore/QEvent>
26 #include <QStackedWidget>
27 #include <QtGui/QPixmap>
28 #include <QtGui/QImage>
29 #include <QtGui/QResizeEvent>
30 #include <QtGui/QShowEvent>
31 #include <QtGui/QKeyEvent>
32 #include <QtGui/QHideEvent>
33 #include <QGraphicsView>
34 #include <QtCore/QSignalMapper>
35 #include <QtCore/QDir>
36 #include <QUndoStack>
37 #include <QCommandLineParser>
38 #include <QtXml/QDomDocument>
39 #include <QApplication>
40 #include <QMenu>
41 #include <QProgressDialog>
42 #include <QAction>
43
44 #include <KIconLoader>
45 #include <KMessageBox>
46 #include <KAboutData>
47 #include <KWindowSystem>
48 #include <KPassivePopup>
49 #include <KXMLGUIFactory>
50 #include <KActionMenu>
51 #include <KActionCollection>
52 #include <KStandardShortcut>
53 #include <KToggleAction>
54 #include <KLocalizedString>
55 #include <KGlobalAccel>
56 #include <KConfigGroup>
57
58 #ifndef BASKET_USE_DRKONQI
59 #include <KCrash>
60 #endif //BASKET_USE_DRKONQI
61
62 #include <cstdlib>
63 #include <unistd.h> // usleep
64
65 #include "gitwrapper.h"
66 #include "basketscene.h"
67 #include "decoratedbasket.h"
68 #include "tools.h"
69 #include "settings.h"
70 #include "debugwindow.h"
71 #include "xmlwork.h"
72 #include "basketfactory.h"
73 #include "softwareimporters.h"
74 #include "colorpicker.h"
75 #include "regiongrabber.h"
76 #include "basketlistview.h"
77 #include "basketproperties.h"
78 #include "password.h"
79 #include "newbasketdialog.h"
80 #include "notedrag.h"
81 #include "formatimporter.h"
82 #include "basketstatusbar.h"
83 #include "backgroundmanager.h"
84 #include "noteedit.h" // To launch InlineEditors::initToolBars()
85 #include "archive.h"
86 #include "htmlexporter.h"
87 #include "crashhandler.h"
88 #include "likeback.h"
89 #include "backup.h"
90 #include "notefactory.h"
91 #include "history.h"
92 #include "icon_names.h"
93
94 #include <qdbusconnection.h>
95 #include <QResource>
96 #include <QStandardPaths>
97 #include <QFileDialog>
98
99 //#include "bnpviewadaptor.h"
100
101 /** class BNPView: */
102
103 const int BNPView::c_delayTooltipTime = 275;
104
BNPView(QWidget * parent,const char * name,KXMLGUIClient * aGUIClient,KActionCollection * actionCollection,BasketStatusBar * bar)105 BNPView::BNPView(QWidget *parent, const char *name, KXMLGUIClient *aGUIClient,
106 KActionCollection *actionCollection, BasketStatusBar *bar)
107 : QSplitter(Qt::Horizontal, parent)
108 , m_actLockBasket(0)
109 , m_actPassBasket(0)
110 , m_loading(true)
111 , m_newBasketPopup(false)
112 , m_firstShow(true)
113 , m_regionGrabber(0)
114 , m_passiveDroppedSelection(0)
115 , m_actionCollection(actionCollection)
116 , m_guiClient(aGUIClient)
117 , m_statusbar(bar)
118 , m_tryHideTimer(0)
119 , m_hideTimer(0)
120 {
121
122 //new BNPViewAdaptor(this);
123 QDBusConnection dbus = QDBusConnection::sessionBus();
124 dbus.registerObject("/BNPView", this);
125
126 setObjectName(name);
127
128 /* Settings */
129 Settings::loadConfig();
130
131 Global::bnpView = this;
132
133 // Needed when loading the baskets:
134 Global::backgroundManager = new BackgroundManager();
135
136 setupGlobalShortcuts();
137 m_history = new QUndoStack(this);
138 initialize();
139 QTimer::singleShot(0, this, SLOT(lateInit()));
140 }
141
~BNPView()142 BNPView::~BNPView()
143 {
144 int treeWidth = Global::bnpView->sizes()[Settings::treeOnLeft() ? 0 : 1];
145
146 Settings::setBasketTreeWidth(treeWidth);
147
148 if (currentBasket() && currentBasket()->isDuringEdit())
149 currentBasket()->closeEditor();
150
151 Settings::saveConfig();
152
153 Global::bnpView = 0;
154
155 delete Global::systemTray;
156 Global::systemTray = 0;
157 delete m_colorPicker;
158 delete m_statusbar;
159 delete m_history;
160 m_history = 0;
161
162 NoteDrag::createAndEmptyCuttingTmpFolder(); // Clean the temporary folder we used
163 }
164
lateInit()165 void BNPView::lateInit()
166 {
167 /*
168 InlineEditors* instance = InlineEditors::instance();
169
170 if(instance)
171 {
172 KToolBar* toolbar = instance->richTextToolBar();
173
174 if(toolbar)
175 toolbar->hide();
176 }
177 */
178
179 #if 0
180 // This is the logic to show or hide Basket when it is started up; ideally,
181 // it will take on its last state when KDE's session restore kicks in.
182 if (!isPart()) {
183 if (Settings::useSystray() && KCmdLineArgs::parsedArgs() && KCmdLineArgs::parsedArgs()->isSet("start-hidden")) {
184 if (Global::mainWindow()) Global::mainWindow()->hide();
185 } else if (Settings::useSystray() && qApp->isSessionRestored()) {
186 if (Global::mainWindow()) Global::mainWindow()->setShown(!Settings::startDocked());
187 }
188 }
189 #else
190 #pragma message ("Proper fix for the systray problem")
191 #endif
192
193
194 // If the main window is hidden when session is saved, Container::queryClose()
195 // isn't called and the last value would be kept
196 Settings::setStartDocked(true);
197 Settings::saveConfig();
198
199 /* System tray icon */
200 Global::systemTray = new SystemTray(Global::activeMainWindow());
201 Global::systemTray->setIconByName(":/images/22-apps-basket");
202 connect(Global::systemTray, SIGNAL(showPart()), this, SIGNAL(showPart()));
203 /*if (Settings::useSystray())
204 Global::systemTray->show();*/
205
206 // Load baskets
207 DEBUG_WIN << "Baskets are loaded from " + Global::basketsFolder();
208
209 NoteDrag::createAndEmptyCuttingTmpFolder(); // If last exec hasn't done it: clean the temporary folder we will use
210 Tag::loadTags(); // Tags should be ready before loading baskets, but tags need the mainContainer to be ready to create KActions!
211 load();
212
213 // If no basket has been found, try to import from an older version,
214 if (topLevelItemCount() <= 0) {
215 QDir dir;
216 dir.mkdir(Global::basketsFolder());
217 if (FormatImporter::shouldImportBaskets()) {
218 FormatImporter::importBaskets();
219 load();
220 }
221 if (topLevelItemCount() <= 0) {
222 // Create first basket:
223 BasketFactory::newBasket(/*icon=*/"", /*name=*/i18n("General"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
224 GitWrapper::commitBasket(currentBasket());
225 GitWrapper::commitTagsXml();
226 }
227 }
228
229 // Load the Welcome Baskets if it is the First Time:
230 if (!Settings::welcomeBasketsAdded()) {
231 addWelcomeBaskets();
232 Settings::setWelcomeBasketsAdded(true);
233 Settings::saveConfig();
234 }
235
236 m_tryHideTimer = new QTimer(this);
237 m_hideTimer = new QTimer(this);
238 connect(m_tryHideTimer, SIGNAL(timeout()), this, SLOT(timeoutTryHide()));
239 connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(timeoutHide()));
240
241 // Preload every baskets for instant filtering:
242 /*StopWatch::start(100);
243 QListViewItemIterator it(m_tree);
244 while (it.current()) {
245 BasketListViewItem *item = ((BasketListViewItem*)it.current());
246 item->basket()->load();
247 qApp->processEvents();
248 ++it;
249 }
250 StopWatch::check(100);*/
251 }
252
addWelcomeBaskets()253 void BNPView::addWelcomeBaskets()
254 {
255 // Possible paths where to find the welcome basket archive, trying the translated one, and falling back to the English one:
256 QStringList possiblePaths;
257 if (QString(Tools::systemCodeset()) == QString("UTF-8")) { // Welcome baskets are encoded in UTF-8. If the system is not, then use the English version:
258 QString lang = QLocale().languageToString(QLocale().language());
259 possiblePaths.append(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "basket/welcome/Welcome_" + lang + ".baskets"));
260 possiblePaths.append(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "basket/welcome/Welcome_" + lang.split("_")[0] + ".baskets"));
261 }
262 possiblePaths.append(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "basket/welcome/Welcome_en_US.baskets"));
263
264 // Take the first EXISTING basket archive found:
265 QDir dir;
266 QString path;
267 for (QStringList::Iterator it = possiblePaths.begin(); it != possiblePaths.end(); ++it) {
268 if (dir.exists(*it)) {
269 path = *it;
270 break;
271 }
272 }
273
274 // Extract:
275 if (!path.isEmpty())
276 Archive::open(path);
277 }
278
onFirstShow()279 void BNPView::onFirstShow()
280 {
281 // Don't enable LikeBack until bnpview is shown. This way it works better with kontact.
282 /* LikeBack */
283 /* Global::likeBack = new LikeBack(LikeBack::AllButtons, / *showBarByDefault=* /true, Global::config());
284 Global::likeBack->setServer("basket.linux62.org", "/likeback/send.php");
285 Global:likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Only english and french languages are accepted."));
286 if (isPart())
287 Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
288 */
289
290 if (isPart())
291 Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
292
293 /*
294 LikeBack::init(Global::config(), Global::about(), LikeBack::AllButtons);
295 LikeBack::setServer("basket.linux62.org", "/likeback/send.php");
296 // LikeBack::setServer("localhost", "/~seb/basket/likeback/send.php");
297 LikeBack::setCustomLanguageMessage(i18n("Only english and french languages are accepted."));
298 // LikeBack::setWindowNamesListing(LikeBack:: / *NoListing* / / *WarnUnnamedWindows* / AllWindows);
299 */
300
301 // In late init, because we need qApp->mainWidget() to be set!
302 if (!isPart())
303 connectTagsMenu();
304
305 m_statusbar->setupStatusBar();
306
307 int treeWidth = Settings::basketTreeWidth();
308 if (treeWidth < 0)
309 treeWidth = m_tree->fontMetrics().maxWidth() * 11;
310 QList<int> splitterSizes;
311 splitterSizes.append(treeWidth);
312 setSizes(splitterSizes);
313 }
314
setupGlobalShortcuts()315 void BNPView::setupGlobalShortcuts()
316 {
317 KActionCollection *ac = new KActionCollection(this);
318 QAction *a = NULL;
319
320 // Ctrl+Shift+W only works when started standalone:
321 QWidget *basketMainWindow =
322 qobject_cast<KMainWindow *>(Global::bnpView->parent());
323
324 int modifier = Qt::CTRL + Qt::ALT + Qt::SHIFT;
325
326 if (basketMainWindow) {
327 a = ac->addAction("global_show_hide_main_window", Global::systemTray,
328 SLOT(toggleActive()));
329 a->setText(i18n("Show/hide main window"));
330 a->setStatusTip(
331 i18n("Allows you to show main Window if it is hidden, and to hide "
332 "it if it is shown."));
333 KGlobalAccel::self()->setGlobalShortcut(a, (QKeySequence(modifier + Qt::Key_W)));
334 }
335
336 a = ac->addAction("global_paste", Global::bnpView,
337 SLOT(globalPasteInCurrentBasket()));
338 a->setText(i18n("Paste clipboard contents in current basket"));
339 a->setStatusTip(
340 i18n("Allows you to paste clipboard contents in the current basket "
341 "without having to open the main window."));
342 KGlobalAccel::self()->setGlobalShortcut(a, QKeySequence(modifier + Qt::Key_V));
343
344
345
346 a = ac->addAction("global_show_current_basket", Global::bnpView,
347 SLOT(showPassiveContentForced()));
348 a->setText(i18n("Show current basket name"));
349 a->setStatusTip(i18n("Allows you to know basket is current without opening "
350 "the main window."));
351
352
353 a = ac->addAction("global_paste_selection", Global::bnpView,
354 SLOT(pasteSelInCurrentBasket()));
355 a->setText(i18n("Paste selection in current basket"));
356 a->setStatusTip(
357 i18n("Allows you to paste clipboard selection in the current basket "
358 "without having to open the main window."));
359 KGlobalAccel::self()->setGlobalShortcut(a, (QKeySequence(Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_S)));
360
361 a = ac->addAction("global_new_basket", Global::bnpView,
362 SLOT(askNewBasket()));
363 a->setText(i18n("Create a new basket"));
364 a->setStatusTip(
365 i18n("Allows you to create a new basket without having to open the "
366 "main window (you then can use the other global shortcuts to add "
367 "a note, paste clipboard or paste selection in this new basket).")
368 );
369
370 a = ac->addAction("global_previous_basket", Global::bnpView,
371 SLOT(goToPreviousBasket()));
372 a->setText(i18n("Go to previous basket"));
373 a->setStatusTip(
374 i18n("Allows you to change current basket to the previous one without "
375 "having to open the main window."));
376
377 a = ac->addAction("global_next_basket", Global::bnpView,
378 SLOT(goToNextBasket()));
379 a->setText(i18n("Go to next basket"));
380 a->setStatusTip(i18n("Allows you to change current basket to the next one "
381 "without having to open the main window."));
382
383 a = ac->addAction("global_note_add_html", Global::bnpView,
384 SLOT(addNoteHtml()));
385 a->setText(i18n("Insert text note"));
386 a->setStatusTip(
387 i18n("Add a text note to the current basket without having to open "
388 "the main window."));
389 KGlobalAccel::self()->setGlobalShortcut(a, (QKeySequence(modifier + Qt::Key_T)));
390
391 a = ac->addAction("global_note_add_image", Global::bnpView,
392 SLOT(addNoteImage()));
393 a->setText(i18n("Insert image note"));
394 a->setStatusTip(
395 i18n("Add an image note to the current basket without having to open "
396 "the main window."));
397
398 a = ac->addAction("global_note_add_link", Global::bnpView,
399 SLOT(addNoteLink()));
400 a->setText(i18n("Insert link note"));
401 a->setStatusTip(
402 i18n("Add a link note to the current basket without having "
403 "to open the main window."));
404
405 a = ac->addAction("global_note_add_color", Global::bnpView,
406 SLOT(addNoteColor()));
407 a->setText(i18n("Insert color note"));
408 a->setStatusTip(
409 i18n("Add a color note to the current basket without having to open "
410 "the main window."));
411
412 a = ac->addAction("global_note_pick_color", Global::bnpView,
413 SLOT(slotColorFromScreenGlobal()));
414 a->setText(i18n("Pick color from screen"));
415 a->setStatusTip(
416 i18n("Add a color note picked from one pixel on screen to the current "
417 "basket without " "having to open the main window."));
418
419 a = ac->addAction("global_note_grab_screenshot", Global::bnpView,
420 SLOT(grabScreenshotGlobal()));
421 a->setText(i18n("Grab screen zone"));
422 a->setStatusTip(
423 i18n("Grab a screen zone as an image in the current basket without "
424 "having to open the main window."));
425
426 #if 0
427 a = ac->addAction("global_note_add_text", Global::bnpView,
428 SLOT(addNoteText()));
429 a->setText(i18n("Insert plain text note"));
430 a->setStatusTip(
431 i18n("Add a plain text note to the current basket without having to "
432 "open the main window."));
433 #endif
434 }
435
initialize()436 void BNPView::initialize()
437 {
438 /// Configure the List View Columns:
439 m_tree = new BasketTreeListView(this);
440 m_tree->setHeaderLabel(i18n("Baskets"));
441 m_tree->setSortingEnabled(false/*Disabled*/);
442 m_tree->setRootIsDecorated(true);
443 m_tree->setLineWidth(1);
444 m_tree->setMidLineWidth(0);
445 m_tree->setFocusPolicy(Qt::NoFocus);
446
447 /// Configure the List View Drag and Drop:
448 m_tree->setDragEnabled(true);
449 m_tree->setDragDropMode(QAbstractItemView::DragDrop);
450 m_tree->setAcceptDrops(true);
451 m_tree->viewport()->setAcceptDrops(true);
452
453 /// Configure the Splitter:
454 m_stack = new QStackedWidget(this);
455
456 setOpaqueResize(true);
457
458 setCollapsible(indexOf(m_tree), true);
459 setCollapsible(indexOf(m_stack), false);
460 setStretchFactor(indexOf(m_tree), 0);
461 setStretchFactor(indexOf(m_stack), 1);
462
463 /// Configure the List View Signals:
464 connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(slotPressed(QTreeWidgetItem*, int)));
465 connect(m_tree, SIGNAL(itemPressed(QTreeWidgetItem*, int)), this, SLOT(slotPressed(QTreeWidgetItem*, int)));
466 connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotPressed(QTreeWidgetItem*, int)));
467
468 connect(m_tree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(needSave(QTreeWidgetItem*)));
469 connect(m_tree, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(needSave(QTreeWidgetItem*)));
470 connect(m_tree, SIGNAL(contextMenuRequested(const QPoint&)), this, SLOT(slotContextMenu(const QPoint &)));
471 connect(m_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(slotShowProperties(QTreeWidgetItem*)));
472
473 connect(m_tree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SIGNAL(basketChanged()));
474 connect(m_tree, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SIGNAL(basketChanged()));
475
476 connect(this, SIGNAL(basketChanged()), this, SLOT(slotBasketChanged()));
477
478 connect(m_history, SIGNAL(canRedoChanged(bool)), this, SLOT(canUndoRedoChanged()));
479 connect(m_history, SIGNAL(canUndoChanged(bool)), this, SLOT(canUndoRedoChanged()));
480
481 /* LikeBack */
482 Global::likeBack = new LikeBack(LikeBack::AllButtons, /*showBarByDefault=*/false, Global::config());
483 Global::likeBack->setServer("basket.linux62.org", "/likeback/send.php");
484
485 // There are too much comments, and people reading comments are more and more international, so we accept only English:
486 // Global::likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Please write in English or French."));
487
488 // if (isPart())
489 // Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
490
491 Global::likeBack->sendACommentAction(actionCollection()); // Just create it!
492 setupActions();
493
494 /// What's This Help for the tree:
495 m_tree->setWhatsThis(i18n(
496 "<h2>Basket Tree</h2>"
497 "Here is the list of your baskets. "
498 "You can organize your data by putting them in different baskets. "
499 "You can group baskets by subject by creating new baskets inside others. "
500 "You can browse between them by clicking a basket to open it, or reorganize them using drag and drop."));
501
502 setTreePlacement(Settings::treeOnLeft());
503 }
504
setupActions()505 void BNPView::setupActions()
506 {
507 QAction *a = NULL;
508 KActionCollection *ac = actionCollection();
509
510 a = ac->addAction("basket_export_basket_archive", this,
511 SLOT(saveAsArchive()));
512 a->setText(i18n("&Basket Archive..."));
513 a->setIcon(QIcon::fromTheme("baskets"));
514 a->setShortcut(0);
515 m_actSaveAsArchive = a;
516
517 a = ac->addAction("basket_import_basket_archive", this,
518 SLOT(openArchive()));
519 a->setText(i18n("&Basket Archive..."));
520 a->setIcon(QIcon::fromTheme("baskets"));
521 a->setShortcut(0);
522 m_actOpenArchive = a;
523
524 a = ac->addAction("window_hide", this, SLOT(hideOnEscape()));
525 a->setText(i18n("&Hide Window"));
526 m_actionCollection->setDefaultShortcut(a, KStandardShortcut::Close);
527 m_actHideWindow = a;
528
529 m_actHideWindow->setEnabled(Settings::useSystray()); // Init here !
530
531 a = ac->addAction("basket_export_html", this, SLOT(exportToHTML()));
532 a->setText(i18n("&HTML Web Page..."));
533 a->setIcon(QIcon::fromTheme("text-html"));
534 a->setShortcut(0);
535 m_actExportToHtml = a;
536
537 a = ac->addAction("basket_import_knotes", this, SLOT(importKNotes()));
538 a->setText(i18n("K&Notes"));
539 a->setIcon(QIcon::fromTheme("knotes"));
540 a->setShortcut(0);
541
542 a = ac->addAction("basket_import_kjots", this, SLOT(importKJots()));
543 a->setText(i18n("K&Jots"));
544 a->setIcon(QIcon::fromTheme("kjots"));
545 a->setShortcut(0);
546
547 a = ac->addAction("basket_import_knowit", this, SLOT(importKnowIt()));
548 a->setText(i18n("&KnowIt..."));
549 a->setIcon(QIcon::fromTheme("knowit"));
550 a->setShortcut(0);
551
552 a = ac->addAction("basket_import_tuxcards", this, SLOT(importTuxCards()));
553 a->setText(i18n("Tux&Cards..."));
554 a->setIcon(QIcon::fromTheme("tuxcards"));
555 a->setShortcut(0);
556
557 a = ac->addAction("basket_import_sticky_notes", this,
558 SLOT(importStickyNotes()));
559 a->setText(i18n("&Sticky Notes"));
560 a->setIcon(QIcon::fromTheme("gnome"));
561 a->setShortcut(0);
562
563 a = ac->addAction("basket_import_tomboy", this, SLOT(importTomboy()));
564 a->setText(i18n("&Tomboy"));
565 a->setIcon(QIcon::fromTheme(IconNames::TOMBOY));
566 a->setShortcut(0);
567
568 a = ac->addAction("basket_import_jreepad_file", this, SLOT(importJreepadFile()));
569 a->setText(i18n("J&reepad XML File..."));
570 a->setIcon(QIcon::fromTheme("text-xml"));
571 a->setShortcut(0);
572
573 a = ac->addAction("basket_import_text_file", this, SLOT(importTextFile()));
574 a->setText(i18n("Text &File..."));
575 a->setIcon(QIcon::fromTheme("text-plain"));
576 a->setShortcut(0);
577
578 a = ac->addAction("basket_backup_restore", this, SLOT(backupRestore()));
579 a->setText(i18n("&Backup && Restore..."));
580 a->setShortcut(0);
581
582 a = ac->addAction("check_cleanup", this, SLOT(checkCleanup()));
583 a->setText(i18n("&Check && Cleanup..."));
584 a->setShortcut(0);
585 if (Global::commandLineOpts->isSet("debug")) {
586 a->setEnabled(true);
587 } else {
588 a->setEnabled(false);
589 }
590
591 /** Note : ****************************************************************/
592
593 a = ac->addAction("edit_delete", this, SLOT(delNote()));
594 a->setText(i18n("D&elete"));
595 a->setIcon(QIcon::fromTheme("edit-delete"));
596 m_actionCollection->setDefaultShortcut(a, QKeySequence("Delete"));
597 m_actDelNote = a;
598
599 m_actCutNote = ac->addAction(KStandardAction::Cut, this, SLOT(cutNote()));
600 m_actCopyNote = ac->addAction(KStandardAction::Copy, this, SLOT(copyNote()));
601
602 m_actSelectAll = ac->addAction(KStandardAction::SelectAll, this,
603 SLOT(slotSelectAll()));
604 m_actSelectAll->setStatusTip(i18n("Selects all notes"));
605
606 a = ac->addAction("edit_unselect_all", this, SLOT(slotUnselectAll()));
607 a->setText(i18n("U&nselect All"));
608 m_actUnselectAll = a;
609 m_actUnselectAll->setStatusTip(i18n("Unselects all selected notes"));
610
611 a = ac->addAction("edit_invert_selection", this,
612 SLOT(slotInvertSelection()));
613 a->setText(i18n("&Invert Selection"));
614 m_actionCollection->setDefaultShortcut(a, Qt::CTRL + Qt::Key_Asterisk);
615 m_actInvertSelection = a;
616
617 m_actInvertSelection->setStatusTip(
618 i18n("Inverts the current selection of notes")
619 );
620
621 a = ac->addAction("note_edit", this, SLOT(editNote()));
622 a->setText(i18nc("Verb; not Menu", "&Edit..."));
623 //a->setIcon(QIcon::fromTheme("edit"));
624 m_actionCollection->setDefaultShortcut(a, QKeySequence("Return"));
625 m_actEditNote = a;
626
627 m_actOpenNote = ac->addAction(KStandardAction::Open, "note_open",
628 this, SLOT(openNote()));
629 m_actOpenNote->setIcon(QIcon::fromTheme("window-new"));
630 m_actOpenNote->setText(i18n("&Open"));
631 m_actionCollection->setDefaultShortcut(m_actOpenNote, QKeySequence("F9"));
632
633 a = ac->addAction("note_open_with", this, SLOT(openNoteWith()));
634 a->setText(i18n("Open &With..."));
635 m_actionCollection->setDefaultShortcut(a, QKeySequence("Shift+F9"));
636 m_actOpenNoteWith = a;
637
638 m_actSaveNoteAs = ac->addAction(KStandardAction::SaveAs,
639 "note_save_to_file",
640 this, SLOT(saveNoteAs()));
641 m_actSaveNoteAs->setText(i18n("&Save to File..."));
642 m_actionCollection->setDefaultShortcut(m_actSaveNoteAs, QKeySequence("F10"));
643
644 a = ac->addAction("note_group", this, SLOT(noteGroup()));
645 a->setText(i18n("&Group"));
646 a->setIcon(QIcon::fromTheme("mail-attachment"));
647 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+G"));
648 m_actGroup = a;
649
650 a = ac->addAction("note_ungroup", this, SLOT(noteUngroup()));
651 a->setText(i18n("U&ngroup"));
652 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+G"));
653 m_actUngroup = a;
654
655 a = ac->addAction("note_move_top", this, SLOT(moveOnTop()));
656 a->setText(i18n("Move on &Top"));
657 a->setIcon(QIcon::fromTheme("arrow-up-double"));
658 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+Home"));
659 m_actMoveOnTop = a;
660
661 a = ac->addAction("note_move_up", this, SLOT(moveNoteUp()));
662 a->setText(i18n("Move &Up"));
663 a->setIcon(QIcon::fromTheme("arrow-up"));
664 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+Up"));
665 m_actMoveNoteUp = a;
666
667 a = ac->addAction("note_move_down", this, SLOT(moveNoteDown()));
668 a->setText(i18n("Move &Down"));
669 a->setIcon(QIcon::fromTheme("arrow-down"));
670 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+Down"));
671 m_actMoveNoteDown = a;
672
673 a = ac->addAction("note_move_bottom", this, SLOT(moveOnBottom()));
674 a->setText(i18n("Move on &Bottom"));
675 a->setIcon(QIcon::fromTheme("arrow-down-double"));
676 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+End"));
677 m_actMoveOnBottom = a;
678
679 m_actPaste = ac->addAction(KStandardAction::Paste, this,
680 SLOT(pasteInCurrentBasket()));
681
682 /** Insert : **************************************************************/
683
684 QSignalMapper *insertEmptyMapper = new QSignalMapper(this);
685 QSignalMapper *insertWizardMapper = new QSignalMapper(this);
686 connect(insertEmptyMapper, SIGNAL(mapped(int)), this, SLOT(insertEmpty(int)));
687 connect(insertWizardMapper, SIGNAL(mapped(int)), this, SLOT(insertWizard(int)));
688
689 #if 0
690 a = ac->addAction("insert_text");
691 a->setText(i18n("Plai&n Text"));
692 a->setIcon(QIcon::fromTheme("text"));
693 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+T"));
694 m_actInsertText = a;
695 #endif
696
697 a = ac->addAction("insert_html");
698 a->setText(i18n("&Text"));
699 a->setIcon(QIcon::fromTheme("text-html"));
700 m_actionCollection->setDefaultShortcut(a, QKeySequence("Insert"));
701 m_actInsertHtml = a;
702
703 a = ac->addAction("insert_link");
704 a->setText(i18n("&Link"));
705 a->setIcon(QIcon::fromTheme(IconNames::LINK));
706 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Y"));
707 m_actInsertLink = a;
708
709 a = ac->addAction("insert_cross_reference");
710 a->setText(i18n("Cross &Reference"));
711 a->setIcon(QIcon::fromTheme(IconNames::CROSS_REF));
712 m_actInsertCrossReference = a;
713
714 a = ac->addAction("insert_image");
715 a->setText(i18n("&Image"));
716 a->setIcon(QIcon::fromTheme(IconNames::IMAGE));
717 m_actInsertImage = a;
718
719 a = ac->addAction("insert_color");
720 a->setText(i18n("&Color"));
721 a->setIcon(QIcon::fromTheme(IconNames::COLOR));
722 m_actInsertColor = a;
723
724 a = ac->addAction("insert_launcher");
725 a->setText(i18n("L&auncher"));
726 a->setIcon(QIcon::fromTheme(IconNames::LAUNCH));
727 m_actInsertLauncher = a;
728
729 a = ac->addAction("insert_kmenu");
730 a->setText(i18n("Import Launcher for &desktop application..."));
731 a->setIcon(QIcon::fromTheme(IconNames::KMENU));
732 m_actImportKMenu = a;
733
734 a = ac->addAction("insert_icon");
735 a->setText(i18n("Im&port Icon..."));
736 a->setIcon(QIcon::fromTheme(IconNames::ICONS));
737 m_actImportIcon = a;
738
739 a = ac->addAction("insert_from_file");
740 a->setText(i18n("Load From &File..."));
741 a->setIcon(QIcon::fromTheme(IconNames::DOCUMENT_IMPORT));
742 m_actLoadFile = a;
743
744 // connect( m_actInsertText, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()) );
745 connect(m_actInsertHtml, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()));
746 connect(m_actInsertImage, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()));
747 connect(m_actInsertLink, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()));
748 connect(m_actInsertCrossReference,SIGNAL(triggered()),insertEmptyMapper, SLOT(map()));
749 connect(m_actInsertColor, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()));
750 connect(m_actInsertLauncher, SIGNAL(triggered()), insertEmptyMapper, SLOT(map()));
751 // insertEmptyMapper->setMapping(m_actInsertText, NoteType::Text );
752 insertEmptyMapper->setMapping(m_actInsertHtml, NoteType::Html);
753 insertEmptyMapper->setMapping(m_actInsertImage, NoteType::Image);
754 insertEmptyMapper->setMapping(m_actInsertLink, NoteType::Link);
755 insertEmptyMapper->setMapping(m_actInsertCrossReference,NoteType::CrossReference);
756 insertEmptyMapper->setMapping(m_actInsertColor, NoteType::Color);
757 insertEmptyMapper->setMapping(m_actInsertLauncher, NoteType::Launcher);
758
759 connect(m_actImportKMenu, SIGNAL(triggered()), insertWizardMapper, SLOT(map()));
760 connect(m_actImportIcon, SIGNAL(triggered()), insertWizardMapper, SLOT(map()));
761 connect(m_actLoadFile, SIGNAL(triggered()), insertWizardMapper, SLOT(map()));
762 insertWizardMapper->setMapping(m_actImportKMenu, 1);
763 insertWizardMapper->setMapping(m_actImportIcon, 2);
764 insertWizardMapper->setMapping(m_actLoadFile, 3);
765
766 m_colorPicker = new DesktopColorPicker();
767
768 a = ac->addAction("insert_screen_color", this, SLOT(slotColorFromScreen()));
769 a->setText(i18n("C&olor from Screen"));
770 a->setIcon(QIcon::fromTheme("kcolorchooser"));
771 m_actColorPicker = a;
772
773 connect(m_colorPicker, SIGNAL(pickedColor(const QColor&)),
774 this, SLOT(colorPicked(const QColor&)));
775 connect(m_colorPicker, SIGNAL(canceledPick()),
776 this, SLOT(colorPickingCanceled()));
777
778 a = ac->addAction("insert_screen_capture", this, SLOT(grabScreenshot()));
779 a->setText(i18n("Grab Screen &Zone"));
780 a->setIcon(QIcon::fromTheme("ksnapshot"));
781 m_actGrabScreenshot = a;
782
783 //connect( m_actGrabScreenshot, SIGNAL(regionGrabbed(const QPixmap&)), this, SLOT(screenshotGrabbed(const QPixmap&)) );
784 //connect( m_colorPicker, SIGNAL(canceledPick()), this, SLOT(colorPickingCanceled()) );
785
786 // m_insertActions.append( m_actInsertText );
787 m_insertActions.append(m_actInsertHtml);
788 m_insertActions.append(m_actInsertLink);
789 m_insertActions.append(m_actInsertCrossReference);
790 m_insertActions.append(m_actInsertImage);
791 m_insertActions.append(m_actInsertColor);
792 m_insertActions.append(m_actImportKMenu);
793 m_insertActions.append(m_actInsertLauncher);
794 m_insertActions.append(m_actImportIcon);
795 m_insertActions.append(m_actLoadFile);
796 m_insertActions.append(m_actColorPicker);
797 m_insertActions.append(m_actGrabScreenshot);
798
799 /** Basket : **************************************************************/
800
801 // At this stage, main.cpp has not set qApp->mainWidget(), so Global::runInsideKontact()
802 // returns true. We do it ourself:
803 bool runInsideKontact = true;
804 QWidget *parentWidget = (QWidget*) parent();
805 while (parentWidget) {
806 if (parentWidget->inherits("MainWindow"))
807 runInsideKontact = false;
808 parentWidget = (QWidget*) parentWidget->parent();
809 }
810
811 // Use the "basket" incon in Kontact so it is consistent with the Kontact "New..." icon
812
813 a = ac->addAction("basket_new", this, SLOT(askNewBasket()));
814 a->setText(i18n("&New Basket..."));
815 a->setIcon(QIcon::fromTheme((runInsideKontact ? "basket" : "document-new")));
816 m_actionCollection->setDefaultShortcuts(a, KStandardShortcut::shortcut(KStandardShortcut::New));
817 actNewBasket = a;
818
819 a = ac->addAction("basket_new_sub", this, SLOT(askNewSubBasket()));
820 a->setText(i18n("New &Sub-Basket..."));
821 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+Shift+N"));
822 actNewSubBasket = a;
823
824 a = ac->addAction("basket_new_sibling", this, SLOT(askNewSiblingBasket()));
825 a->setText(i18n("New Si&bling Basket..."));
826 actNewSiblingBasket = a;
827
828 KActionMenu *newBasketMenu = new KActionMenu(i18n("&New"), ac);
829 newBasketMenu->setIcon(QIcon::fromTheme("document-new"));
830 ac->addAction("basket_new_menu", newBasketMenu);
831
832 newBasketMenu->addAction(actNewBasket);
833 newBasketMenu->addAction(actNewSubBasket);
834 newBasketMenu->addAction(actNewSiblingBasket);
835 connect(newBasketMenu, SIGNAL(triggered()), this, SLOT(askNewBasket()));
836
837 a = ac->addAction("basket_properties", this, SLOT(propBasket()));
838 a->setText(i18n("&Properties..."));
839 a->setIcon(QIcon::fromTheme("document-properties"));
840 m_actionCollection->setDefaultShortcut(a, QKeySequence("F2"));
841 m_actPropBasket = a;
842
843 a = ac->addAction("basket_sort_children_asc", this, SLOT(sortChildrenAsc()));
844 a->setText(i18n("Sort Children Ascending"));
845 a->setIcon(QIcon::fromTheme("view-sort-ascending"));
846 m_actSortChildrenAsc = a;
847
848 a = ac->addAction("basket_sort_children_desc", this, SLOT(sortChildrenDesc()));
849 a->setText(i18n("Sort Children Descending"));
850 a->setIcon(QIcon::fromTheme("view-sort-descending"));
851 m_actSortChildrenDesc = a;
852
853 a = ac->addAction("basket_sort_siblings_asc", this, SLOT(sortSiblingsAsc()));
854 a->setText(i18n("Sort Siblings Ascending"));
855 a->setIcon(QIcon::fromTheme("view-sort-ascending"));
856 m_actSortSiblingsAsc = a;
857
858 a = ac->addAction("basket_sort_siblings_desc", this, SLOT(sortSiblingsDesc()));
859 a->setText(i18n("Sort Siblings Descending"));
860 a->setIcon(QIcon::fromTheme("view-sort-descending"));
861 m_actSortSiblingsDesc = a;
862
863 a = ac->addAction("basket_remove", this, SLOT(delBasket()));
864 a->setText(i18nc("Remove Basket", "&Remove"));
865 a->setShortcut(0);
866 m_actDelBasket = a;
867
868 #ifdef HAVE_LIBGPGME
869 a = ac->addAction("basket_password", this, SLOT(password()));
870 a->setText(i18nc("Password protection", "Pass&word..."));
871 a->setShortcut(0);
872 m_actPassBasket = a;
873
874 a = ac->addAction("basket_lock", this, SLOT(lockBasket()));
875 a->setText(i18nc("Lock Basket", "&Lock"));
876 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+L"));
877 m_actLockBasket = a;
878 #endif
879
880 /** Edit : ****************************************************************/
881
882 //m_actUndo = KStandardAction::undo( this, SLOT(undo()), actionCollection() );
883 //m_actUndo->setEnabled(false); // Not yet implemented !
884 //m_actRedo = KStandardAction::redo( this, SLOT(redo()), actionCollection() );
885 //m_actRedo->setEnabled(false); // Not yet implemented !
886
887 KToggleAction *toggleAct = NULL;
888 toggleAct = new KToggleAction(i18n("&Filter"), ac);
889 ac->addAction("edit_filter", toggleAct);
890 toggleAct->setIcon(QIcon::fromTheme("view-filter"));
891 m_actionCollection->setDefaultShortcuts(toggleAct, KStandardShortcut::shortcut(KStandardShortcut::Find));
892 m_actShowFilter = toggleAct;
893
894 connect(m_actShowFilter, SIGNAL(toggled(bool)),
895 this, SLOT(showHideFilterBar(bool)));
896
897 toggleAct = new KToggleAction(ac);
898 ac->addAction("edit_filter_all_baskets", toggleAct);
899 toggleAct->setText(i18n("&Search All"));
900 toggleAct->setIcon(QIcon::fromTheme("edit-find"));
901 m_actionCollection->setDefaultShortcut(toggleAct, QKeySequence("Ctrl+Shift+F"));
902 m_actFilterAllBaskets = toggleAct;
903
904 connect(m_actFilterAllBaskets, SIGNAL(toggled(bool)),
905 this, SLOT(toggleFilterAllBaskets(bool)));
906
907 a = ac->addAction("edit_filter_reset", this, SLOT(slotResetFilter()));
908 a->setText(i18n("&Reset Filter"));
909 a->setIcon(QIcon::fromTheme("edit-clear-locationbar-rtl"));
910 m_actionCollection->setDefaultShortcut(a, QKeySequence("Ctrl+R"));
911 m_actResetFilter = a;
912
913 /** Go : ******************************************************************/
914
915 a = ac->addAction("go_basket_previous", this, SLOT(goToPreviousBasket()));
916 a->setText(i18n("&Previous Basket"));
917 a->setIcon(QIcon::fromTheme("go-previous"));
918 m_actionCollection->setDefaultShortcut(a, QKeySequence("Alt+Left"));
919 m_actPreviousBasket = a;
920
921 a = ac->addAction("go_basket_next", this, SLOT(goToNextBasket()));
922 a->setText(i18n("&Next Basket"));
923 a->setIcon(QIcon::fromTheme("go-next"));
924 m_actionCollection->setDefaultShortcut(a, QKeySequence("Alt+Right"));
925 m_actNextBasket = a;
926
927 a = ac->addAction("go_basket_fold", this, SLOT(foldBasket()));
928 a->setText(i18n("&Fold Basket"));
929 a->setIcon(QIcon::fromTheme("go-up"));
930 m_actionCollection->setDefaultShortcut(a, QKeySequence("Alt+Up"));
931 m_actFoldBasket = a;
932
933 a = ac->addAction("go_basket_expand", this, SLOT(expandBasket()));
934 a->setText(i18n("&Expand Basket"));
935 a->setIcon(QIcon::fromTheme("go-down"));
936 m_actionCollection->setDefaultShortcut(a, QKeySequence("Alt+Down"));
937 m_actExpandBasket = a;
938
939 #if 0
940 // FOR_BETA_PURPOSE:
941 a = ac->addAction("beta_convert_texts", this, SLOT(convertTexts()));
942 a->setText(i18n("Convert text notes to rich text notes"));
943 a->setIcon(QIcon::fromTheme("run-build-file"));
944 m_convertTexts = a;
945 #endif
946
947 InlineEditors::instance()->initToolBars(actionCollection());
948 /** Help : ****************************************************************/
949
950 a = ac->addAction("help_welcome_baskets", this, SLOT(addWelcomeBaskets()));
951 a->setText(i18n("&Welcome Baskets"));
952 }
953
topLevelItem(int i)954 BasketListViewItem* BNPView::topLevelItem(int i)
955 {
956 return (BasketListViewItem *)m_tree->topLevelItem(i);
957 }
958
slotShowProperties(QTreeWidgetItem * item)959 void BNPView::slotShowProperties(QTreeWidgetItem *item)
960 {
961 if (item)
962 propBasket();
963 }
964
slotContextMenu(const QPoint & pos)965 void BNPView::slotContextMenu(const QPoint &pos)
966 {
967 QTreeWidgetItem *item;
968 item = m_tree->itemAt(pos);
969 QString menuName;
970 if (item) {
971 BasketScene* basket = ((BasketListViewItem*)item)->basket();
972
973 setCurrentBasket(basket);
974 menuName = "basket_popup";
975 } else {
976 menuName = "tab_bar_popup";
977 /*
978 * "File -> New" create a new basket with the same parent basket as the the current one.
979 * But when invoked when right-clicking the empty area at the bottom of the basket tree,
980 * it is obvious the user want to create a new basket at the bottom of the tree (with no parent).
981 * So we set a temporary variable during the time the popup menu is shown,
982 * so the slot askNewBasket() will do the right thing:
983 */
984 setNewBasketPopup();
985 }
986
987 QMenu *menu = popupMenu(menuName);
988 connect(menu, SIGNAL(aboutToHide()), this, SLOT(aboutToHideNewBasketPopup()));
989 menu->exec(m_tree->mapToGlobal(pos));
990 }
991
992 /* this happens everytime we switch the basket (but not if we tell the user we save the stuff
993 */
save()994 void BNPView::save()
995 {
996 DEBUG_WIN << "Basket Tree: Saving...";
997
998
999 QString data;
1000 QXmlStreamWriter stream(&data);
1001 XMLWork::setupXmlStream(stream, "basketTree");
1002
1003 // Save Basket Tree:
1004 save(m_tree, 0, stream);
1005
1006 stream.writeEndElement();
1007 stream.writeEndDocument();
1008
1009 // Write to Disk:
1010 BasketScene::safelySaveToFile(Global::basketsFolder() + "baskets.xml", data);
1011
1012 GitWrapper::commitBasketView();
1013 }
1014
save(QTreeWidget * listView,QTreeWidgetItem * item,QXmlStreamWriter & stream)1015 void BNPView::save(QTreeWidget *listView, QTreeWidgetItem* item, QXmlStreamWriter &stream)
1016 {
1017 if (item == 0) {
1018 if (listView == NULL) {
1019 //This should not happen: we call either save(listView, 0) or save(0, item)
1020 DEBUG_WIN << "BNPView::save error: listView=NULL and item=NULL";
1021 return;
1022 }
1023
1024 // For each basket:
1025 for (int i = 0; i < listView->topLevelItemCount(); i++) {
1026 item = listView->topLevelItem(i);
1027 save(0, item, stream);
1028 }
1029 } else {
1030 saveSubHierarchy(item, stream, true);
1031 }
1032 }
1033
writeBasketElement(QTreeWidgetItem * item,QXmlStreamWriter & stream)1034 void BNPView::writeBasketElement(QTreeWidgetItem *item, QXmlStreamWriter &stream)
1035 {
1036 BasketScene* basket = ((BasketListViewItem*)item)->basket();
1037
1038 // Save Attributes:
1039 stream.writeAttribute("folderName", basket->folderName());
1040 if (item->childCount() >= 0) // If it can be expanded/folded:
1041 stream.writeAttribute("folded", XMLWork::trueOrFalse(!item->isExpanded()));
1042
1043 if (((BasketListViewItem*)item)->isCurrentBasket())
1044 stream.writeAttribute("lastOpened", "true");
1045
1046 basket->saveProperties(stream);
1047 }
1048
saveSubHierarchy(QTreeWidgetItem * item,QXmlStreamWriter & stream,bool recursive)1049 void BNPView::saveSubHierarchy(QTreeWidgetItem *item, QXmlStreamWriter &stream, bool recursive)
1050 {
1051 stream.writeStartElement("basket");
1052 writeBasketElement(item, stream); //create root <basket>
1053 if (recursive) {
1054 for (int i = 0; i < item->childCount(); i++) {
1055 saveSubHierarchy(item->child(i), stream, true);
1056 }
1057 }
1058 stream.writeEndElement();
1059 }
1060
load()1061 void BNPView::load()
1062 {
1063 QScopedPointer<QDomDocument> doc(XMLWork::openFile("basketTree", Global::basketsFolder() + "baskets.xml"));
1064 //BEGIN Compatibility with 0.6.0 Pre-Alpha versions:
1065 if (!doc)
1066 doc.reset(XMLWork::openFile("basketsTree", Global::basketsFolder() + "baskets.xml"));
1067 //END
1068 if (doc != 0) {
1069 QDomElement docElem = doc->documentElement();
1070 load(0L, docElem);
1071 }
1072 m_loading = false;
1073 }
1074
load(QTreeWidgetItem * item,const QDomElement & baskets)1075 void BNPView::load(QTreeWidgetItem *item, const QDomElement &baskets)
1076 {
1077 QDomNode n = baskets.firstChild();
1078 while (! n.isNull()) {
1079 QDomElement element = n.toElement();
1080 if ((!element.isNull()) && element.tagName() == "basket") {
1081 QString folderName = element.attribute("folderName");
1082 if (!folderName.isEmpty()) {
1083 BasketScene *basket = loadBasket(folderName);
1084 BasketListViewItem *basketItem = appendBasket(basket, item);
1085 basketItem->setExpanded(!XMLWork::trueOrFalse(element.attribute("folded", "false"), false));
1086 basket->loadProperties(XMLWork::getElement(element, "properties"));
1087 if (XMLWork::trueOrFalse(element.attribute("lastOpened", element.attribute("lastOpened", "false")), false)) // Compat with 0.6.0-Alphas
1088 setCurrentBasket(basket);
1089 // Load Sub-baskets:
1090 load(basketItem, element);
1091 }
1092 }
1093 n = n.nextSibling();
1094 }
1095 }
1096
loadBasket(const QString & folderName)1097 BasketScene* BNPView::loadBasket(const QString &folderName)
1098 {
1099 if (folderName.isEmpty())
1100 return 0;
1101
1102 DecoratedBasket *decoBasket = new DecoratedBasket(m_stack, folderName);
1103 BasketScene *basket = decoBasket->basket();
1104 m_stack->addWidget(decoBasket);
1105
1106 connect(basket, SIGNAL(countsChanged(BasketScene*)), this, SLOT(countsChanged(BasketScene*)));
1107 // Important: Create listViewItem and connect signal BEFORE loadProperties(), so we get the listViewItem updated without extra work:
1108 connect(basket, SIGNAL(propertiesChanged(BasketScene*)), this, SLOT(updateBasketListViewItem(BasketScene*)));
1109
1110 connect(basket->decoration()->filterBar(), SIGNAL(newFilter(const FilterData&)), this, SLOT(newFilterFromFilterBar()));
1111 connect(basket, SIGNAL(crossReference(QString)), this, SLOT(loadCrossReference(QString)));
1112
1113 return basket;
1114 }
1115
basketCount(QTreeWidgetItem * parent)1116 int BNPView::basketCount(QTreeWidgetItem *parent)
1117 {
1118 int count = 1;
1119 if (parent == NULL)
1120 return 0;
1121
1122 for (int i = 0; i < parent->childCount(); i++) {
1123 count += basketCount(parent->child(i));
1124 }
1125
1126 return count;
1127 }
1128
canFold()1129 bool BNPView::canFold()
1130 {
1131 BasketListViewItem *item = listViewItemForBasket(currentBasket());
1132 if (!item)
1133 return false;
1134 return (item->childCount() > 0 && item->isExpanded());
1135 }
1136
canExpand()1137 bool BNPView::canExpand()
1138 {
1139 BasketListViewItem *item = listViewItemForBasket(currentBasket());
1140 if (!item)
1141 return false;
1142 return (item->childCount() > 0 && !item->isExpanded());
1143 }
1144
appendBasket(BasketScene * basket,QTreeWidgetItem * parentItem)1145 BasketListViewItem* BNPView::appendBasket(BasketScene *basket, QTreeWidgetItem *parentItem)
1146 {
1147 BasketListViewItem *newBasketItem;
1148 if (parentItem)
1149 newBasketItem = new BasketListViewItem(parentItem, parentItem->child(parentItem->childCount() - 1), basket);
1150 else {
1151 newBasketItem = new BasketListViewItem(m_tree, m_tree->topLevelItem(m_tree->topLevelItemCount() - 1), basket);
1152 }
1153
1154 return newBasketItem;
1155 }
1156
loadNewBasket(const QString & folderName,const QDomElement & properties,BasketScene * parent)1157 void BNPView::loadNewBasket(const QString &folderName, const QDomElement &properties, BasketScene *parent)
1158 {
1159 BasketScene *basket = loadBasket(folderName);
1160 appendBasket(basket, (basket ? listViewItemForBasket(parent) : 0));
1161 basket->loadProperties(properties);
1162 setCurrentBasketInHistory(basket);
1163 // save();
1164 }
1165
topLevelItemCount()1166 int BNPView::topLevelItemCount()
1167 {
1168 return m_tree->topLevelItemCount();
1169 }
1170
goToPreviousBasket()1171 void BNPView::goToPreviousBasket()
1172 {
1173 if(m_history->canUndo())
1174 m_history->undo();
1175 }
1176
goToNextBasket()1177 void BNPView::goToNextBasket()
1178 {
1179 if(m_history->canRedo())
1180 m_history->redo();
1181 }
1182
foldBasket()1183 void BNPView::foldBasket()
1184 {
1185 BasketListViewItem *item = listViewItemForBasket(currentBasket());
1186 if (item && item->childCount() <= 0)
1187 item->setExpanded(false); // If Alt+Left is hitted and there is nothing to close, make sure the focus will go to the parent basket
1188
1189 QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Left, 0, 0);
1190 QApplication::postEvent(m_tree, keyEvent);
1191 }
1192
expandBasket()1193 void BNPView::expandBasket()
1194 {
1195 QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Right, 0, 0);
1196 QApplication::postEvent(m_tree, keyEvent);
1197 }
1198
closeAllEditors()1199 void BNPView::closeAllEditors()
1200 {
1201 QTreeWidgetItemIterator it(m_tree);
1202 while (*it) {
1203 BasketListViewItem *item = (BasketListViewItem*)(*it);
1204 item->basket()->closeEditor();
1205 ++it;
1206 }
1207 }
1208
convertTexts()1209 bool BNPView::convertTexts()
1210 {
1211 bool convertedNotes = false;
1212 QProgressDialog dialog;
1213 dialog.setWindowTitle(i18n("Plain Text Notes Conversion"));
1214 dialog.setLabelText(i18n("Converting plain text notes to rich text ones..."));
1215 dialog.setModal(true);
1216 dialog.setRange(0, basketCount());
1217 dialog.show(); //setMinimumDuration(50/*ms*/);
1218
1219 QTreeWidgetItemIterator it(m_tree);
1220 while (*it) {
1221 BasketListViewItem *item = (BasketListViewItem*)(*it);
1222 if (item->basket()->convertTexts())
1223 convertedNotes = true;
1224
1225 dialog.setValue(dialog.value() + 1);
1226
1227 if (dialog.wasCanceled())
1228 break;
1229 ++it;
1230 }
1231
1232 return convertedNotes;
1233 }
1234
toggleFilterAllBaskets(bool doFilter)1235 void BNPView::toggleFilterAllBaskets(bool doFilter)
1236 {
1237 // If the filter isn't already showing, we make sure it does.
1238 if (doFilter)
1239 m_actShowFilter->setChecked(true);
1240
1241 //currentBasket()->decoration()->filterBar()->setFilterAll(doFilter);
1242
1243
1244 if (doFilter)
1245 currentBasket()->decoration()->filterBar()->setEditFocus();
1246
1247 // Filter every baskets:
1248 newFilter();
1249 }
1250
1251 /** This function can be called recursively because we call qApp->processEvents().
1252 * If this function is called whereas another "instance" is running,
1253 * this new "instance" leave and set up a flag that is read by the first "instance"
1254 * to know it should re-begin the work.
1255 * PS: Yes, that's a very lame pseudo-threading but that works, and it's programmer-efforts cheap :-)
1256 */
newFilter()1257 void BNPView::newFilter()
1258 {
1259 static bool alreadyEntered = false;
1260 static bool shouldRestart = false;
1261
1262 if (alreadyEntered) {
1263 shouldRestart = true;
1264 return;
1265 }
1266 alreadyEntered = true;
1267 shouldRestart = false;
1268
1269 BasketScene *current = currentBasket();
1270 const FilterData &filterData = current->decoration()->filterBar()->filterData();
1271
1272 // Set the filter data for every other baskets, or reset the filter for every other baskets if we just disabled the filterInAllBaskets:
1273 QTreeWidgetItemIterator it(m_tree);
1274 while (*it) {
1275 BasketListViewItem *item = ((BasketListViewItem*) * it);
1276 if (item->basket() != current) {
1277 if (isFilteringAllBaskets())
1278 item->basket()->decoration()->filterBar()->setFilterData(filterData); // Set the new FilterData for every other baskets
1279 else
1280 item->basket()->decoration()->filterBar()->setFilterData(FilterData()); // We just disabled the global filtering: remove the FilterData
1281 }
1282 ++it;
1283 }
1284
1285 // Show/hide the "little filter icons" (during basket load)
1286 // or the "little numbers" (to show number of found notes in the baskets) is the tree:
1287 qApp->processEvents();
1288
1289 // Load every baskets for filtering, if they are not already loaded, and if necessary:
1290 if (filterData.isFiltering) {
1291 BasketScene *current = currentBasket();
1292 QTreeWidgetItemIterator it(m_tree);
1293 while (*it) {
1294 BasketListViewItem *item = ((BasketListViewItem*) * it);
1295 if (item->basket() != current) {
1296 BasketScene *basket = item->basket();
1297 if (!basket->loadingLaunched() && !basket->isLocked())
1298 basket->load();
1299 basket->filterAgain();
1300 qApp->processEvents();
1301 if (shouldRestart) {
1302 alreadyEntered = false;
1303 shouldRestart = false;
1304 newFilter();
1305 return;
1306 }
1307 }
1308 ++it;
1309 }
1310 }
1311
1312 // qApp->processEvents();
1313 m_tree->viewport()->update(); // to see the "little numbers"
1314
1315 alreadyEntered = false;
1316 shouldRestart = false;
1317 }
1318
newFilterFromFilterBar()1319 void BNPView::newFilterFromFilterBar()
1320 {
1321 if (isFilteringAllBaskets())
1322 QTimer::singleShot(0, this, SLOT(newFilter())); // Keep time for the QLineEdit to display the filtered character and refresh correctly!
1323 }
1324
isFilteringAllBaskets()1325 bool BNPView::isFilteringAllBaskets()
1326 {
1327 return m_actFilterAllBaskets->isChecked();
1328 }
1329
1330
listViewItemForBasket(BasketScene * basket)1331 BasketListViewItem* BNPView::listViewItemForBasket(BasketScene *basket)
1332 {
1333 QTreeWidgetItemIterator it(m_tree);
1334 while (*it) {
1335 BasketListViewItem *item = ((BasketListViewItem*) * it);
1336 if (item->basket() == basket)
1337 return item;
1338 ++it;
1339 }
1340 return 0L;
1341 }
1342
currentBasket()1343 BasketScene* BNPView::currentBasket()
1344 {
1345 DecoratedBasket *decoBasket = (DecoratedBasket*)m_stack->currentWidget();
1346 if (decoBasket)
1347 return decoBasket->basket();
1348 else
1349 return 0;
1350 }
1351
parentBasketOf(BasketScene * basket)1352 BasketScene* BNPView::parentBasketOf(BasketScene *basket)
1353 {
1354 BasketListViewItem *item = (BasketListViewItem*)(listViewItemForBasket(basket)->parent());
1355 if (item)
1356 return item->basket();
1357 else
1358 return 0;
1359 }
1360
setCurrentBasketInHistory(BasketScene * basket)1361 void BNPView::setCurrentBasketInHistory(BasketScene *basket)
1362 {
1363 if(!basket)
1364 return;
1365
1366 if (currentBasket() == basket)
1367 return;
1368
1369 m_history->push(new HistorySetBasket(basket));
1370 }
1371
setCurrentBasket(BasketScene * basket)1372 void BNPView::setCurrentBasket(BasketScene *basket)
1373 {
1374 if (currentBasket() == basket)
1375 return;
1376
1377 if (currentBasket())
1378 currentBasket()->closeBasket();
1379
1380 if (basket)
1381 basket->aboutToBeActivated();
1382
1383 BasketListViewItem *item = listViewItemForBasket(basket);
1384 if (item) {
1385 m_tree->setCurrentItem(item);
1386 item->ensureVisible();
1387 m_stack->setCurrentWidget(basket->decoration());
1388 // If the window has changed size, only the current basket receive the event,
1389 // the others will receive ony one just before they are shown.
1390 // But this triggers unwanted animations, so we eliminate it:
1391 basket->relayoutNotes(/*animate=*/false);
1392 basket->openBasket();
1393 setWindowTitle(item->basket()->basketName());
1394 countsChanged(basket);
1395 updateStatusBarHint();
1396 if (Global::systemTray)
1397 Global::systemTray->updateDisplay();
1398 m_tree->scrollToItem(m_tree->currentItem());
1399 item->basket()->setFocus();
1400 }
1401 m_tree->viewport()->update();
1402 emit basketChanged();
1403 }
1404
removeBasket(BasketScene * basket)1405 void BNPView::removeBasket(BasketScene *basket)
1406 {
1407 if (basket->isDuringEdit())
1408 basket->closeEditor();
1409
1410 // Find a new basket to switch to and select it.
1411 // Strategy: get the next sibling, or the previous one if not found.
1412 // If there is no such one, get the parent basket:
1413 BasketListViewItem *basketItem = listViewItemForBasket(basket);
1414 BasketListViewItem *nextBasketItem = (BasketListViewItem*)(m_tree->itemBelow(basketItem));
1415 if (!nextBasketItem)
1416 nextBasketItem = (BasketListViewItem*)m_tree->itemAbove(basketItem);
1417 if (!nextBasketItem)
1418 nextBasketItem = (BasketListViewItem*)(basketItem->parent());
1419
1420 if (nextBasketItem)
1421 setCurrentBasketInHistory(nextBasketItem->basket());
1422
1423 // Remove from the view:
1424 basket->unsubscribeBackgroundImages();
1425 m_stack->removeWidget(basket->decoration());
1426 // delete basket->decoration();
1427 delete basketItem;
1428 // delete basket;
1429
1430 // If there is no basket anymore, add a new one:
1431 if (!nextBasketItem)
1432 BasketFactory::newBasket(/*icon=*/"", /*name=*/i18n("General"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
1433 else // No need to save two times if we add a basket
1434 save();
1435 }
1436
setTreePlacement(bool onLeft)1437 void BNPView::setTreePlacement(bool onLeft)
1438 {
1439 if (onLeft)
1440 insertWidget(0, m_tree);
1441 else
1442 addWidget(m_tree);
1443 //updateGeometry();
1444 qApp->postEvent(this, new QResizeEvent(size(), size()));
1445 }
1446
relayoutAllBaskets()1447 void BNPView::relayoutAllBaskets()
1448 {
1449 QTreeWidgetItemIterator it(m_tree);
1450 while (*it) {
1451 BasketListViewItem *item = ((BasketListViewItem*) * it);
1452 //item->basket()->unbufferizeAll();
1453 item->basket()->unsetNotesWidth();
1454 item->basket()->relayoutNotes(true);
1455 ++it;
1456 }
1457 }
1458
recomputeAllStyles()1459 void BNPView::recomputeAllStyles()
1460 {
1461 QTreeWidgetItemIterator it(m_tree);
1462 while (*it) {
1463 BasketListViewItem *item = ((BasketListViewItem*) * it);
1464 item->basket()->recomputeAllStyles();
1465 item->basket()->unsetNotesWidth();
1466 item->basket()->relayoutNotes(true);
1467 ++it;
1468 }
1469 }
1470
removedStates(const QList<State * > & deletedStates)1471 void BNPView::removedStates(const QList<State*> &deletedStates)
1472 {
1473 QTreeWidgetItemIterator it(m_tree);
1474 while (*it) {
1475 BasketListViewItem *item = ((BasketListViewItem*) * it);
1476 item->basket()->removedStates(deletedStates);
1477 ++it;
1478 }
1479 }
1480
linkLookChanged()1481 void BNPView::linkLookChanged()
1482 {
1483 QTreeWidgetItemIterator it(m_tree);
1484 while (*it) {
1485 BasketListViewItem *item = ((BasketListViewItem*) * it);
1486 item->basket()->linkLookChanged();
1487 ++it;
1488 }
1489 }
1490
filterPlacementChanged(bool onTop)1491 void BNPView::filterPlacementChanged(bool onTop)
1492 {
1493 QTreeWidgetItemIterator it(m_tree);
1494 while (*it) {
1495 BasketListViewItem *item = static_cast<BasketListViewItem*>(*it);
1496 DecoratedBasket *decoration = static_cast<DecoratedBasket*>(item->basket()->parent());
1497 decoration->setFilterBarPosition(onTop);
1498 ++it;
1499 }
1500 }
1501
updateBasketListViewItem(BasketScene * basket)1502 void BNPView::updateBasketListViewItem(BasketScene *basket)
1503 {
1504 BasketListViewItem *item = listViewItemForBasket(basket);
1505 if (item)
1506 item->setup();
1507
1508 if (basket == currentBasket()) {
1509 setWindowTitle(basket->basketName());
1510 if (Global::systemTray)
1511 Global::systemTray->updateDisplay();
1512 }
1513
1514 // Don't save if we are loading!
1515 if (!m_loading)
1516 save();
1517 }
1518
needSave(QTreeWidgetItem *)1519 void BNPView::needSave(QTreeWidgetItem *)
1520 {
1521 if (!m_loading)
1522 // A basket has been collapsed/expanded or a new one is select: this is not urgent:
1523 QTimer::singleShot(500/*ms*/, this, SLOT(save()));
1524 }
1525
slotPressed(QTreeWidgetItem * item,int column)1526 void BNPView::slotPressed(QTreeWidgetItem *item, int column)
1527 {
1528 Q_UNUSED(column);
1529 BasketScene *basket = currentBasket();
1530 if (basket == 0)
1531 return;
1532
1533 // Impossible to Select no Basket:
1534 if (!item)
1535 m_tree->setCurrentItem(listViewItemForBasket(basket), true);
1536
1537 else if (dynamic_cast<BasketListViewItem*>(item) != 0 && currentBasket() != ((BasketListViewItem*)item)->basket()) {
1538 setCurrentBasketInHistory(((BasketListViewItem*)item)->basket());
1539 needSave(0);
1540 }
1541 basket->graphicsView()->viewport()->setFocus();
1542 }
1543
currentDecoratedBasket()1544 DecoratedBasket* BNPView::currentDecoratedBasket()
1545 {
1546 if (currentBasket())
1547 return currentBasket()->decoration();
1548 else
1549 return 0;
1550 }
1551
1552 // Redirected actions :
1553
exportToHTML()1554 void BNPView::exportToHTML()
1555 {
1556 HTMLExporter exporter(currentBasket());
1557 }
editNote()1558 void BNPView::editNote()
1559 {
1560 currentBasket()->noteEdit();
1561 }
cutNote()1562 void BNPView::cutNote()
1563 {
1564 currentBasket()->noteCut();
1565 }
copyNote()1566 void BNPView::copyNote()
1567 {
1568 currentBasket()->noteCopy();
1569 }
delNote()1570 void BNPView::delNote()
1571 {
1572 currentBasket()->noteDelete();
1573 }
openNote()1574 void BNPView::openNote()
1575 {
1576 currentBasket()->noteOpen();
1577 }
openNoteWith()1578 void BNPView::openNoteWith()
1579 {
1580 currentBasket()->noteOpenWith();
1581 }
saveNoteAs()1582 void BNPView::saveNoteAs()
1583 {
1584 currentBasket()->noteSaveAs();
1585 }
noteGroup()1586 void BNPView::noteGroup()
1587 {
1588 currentBasket()->noteGroup();
1589 }
noteUngroup()1590 void BNPView::noteUngroup()
1591 {
1592 currentBasket()->noteUngroup();
1593 }
moveOnTop()1594 void BNPView::moveOnTop()
1595 {
1596 currentBasket()->noteMoveOnTop();
1597 }
moveOnBottom()1598 void BNPView::moveOnBottom()
1599 {
1600 currentBasket()->noteMoveOnBottom();
1601 }
moveNoteUp()1602 void BNPView::moveNoteUp()
1603 {
1604 currentBasket()->noteMoveNoteUp();
1605 }
moveNoteDown()1606 void BNPView::moveNoteDown()
1607 {
1608 currentBasket()->noteMoveNoteDown();
1609 }
slotSelectAll()1610 void BNPView::slotSelectAll()
1611 {
1612 currentBasket()->selectAll();
1613 }
slotUnselectAll()1614 void BNPView::slotUnselectAll()
1615 {
1616 currentBasket()->unselectAll();
1617 }
slotInvertSelection()1618 void BNPView::slotInvertSelection()
1619 {
1620 currentBasket()->invertSelection();
1621 }
slotResetFilter()1622 void BNPView::slotResetFilter()
1623 {
1624 currentDecoratedBasket()->resetFilter();
1625 }
1626
importKJots()1627 void BNPView::importKJots()
1628 {
1629 SoftwareImporters::importKJots();
1630 }
importKNotes()1631 void BNPView::importKNotes()
1632 {
1633 SoftwareImporters::importKNotes();
1634 }
importKnowIt()1635 void BNPView::importKnowIt()
1636 {
1637 SoftwareImporters::importKnowIt();
1638 }
importTuxCards()1639 void BNPView::importTuxCards()
1640 {
1641 SoftwareImporters::importTuxCards();
1642 }
importStickyNotes()1643 void BNPView::importStickyNotes()
1644 {
1645 SoftwareImporters::importStickyNotes();
1646 }
importTomboy()1647 void BNPView::importTomboy()
1648 {
1649 SoftwareImporters::importTomboy();
1650 }
importJreepadFile()1651 void BNPView::importJreepadFile()
1652 {
1653 SoftwareImporters::importJreepadFile();
1654 }
importTextFile()1655 void BNPView::importTextFile()
1656 {
1657 SoftwareImporters::importTextFile();
1658 }
1659
backupRestore()1660 void BNPView::backupRestore()
1661 {
1662 BackupDialog dialog;
1663 dialog.exec();
1664 }
1665
checkNote(Note * note,QList<QString> & fileList)1666 void checkNote(Note * note, QList<QString> & fileList) {
1667 while (note) {
1668 note->finishLazyLoad();
1669 if ( note->isGroup() ) {
1670 checkNote(note->firstChild(), fileList);
1671 } else if ( note->content()->useFile() ) {
1672 QString noteFileName = note->basket()->folderName() + note->content()->fileName();
1673 int basketFileIndex = fileList.indexOf( noteFileName );
1674 if (basketFileIndex < 0) {
1675 DEBUG_WIN << "<font color='red'>" + noteFileName + " NOT FOUND!</font>";
1676 } else {
1677 fileList.removeAt(basketFileIndex);
1678 }
1679 }
1680 note = note->next();
1681 }
1682 }
1683
checkBasket(BasketListViewItem * item,QList<QString> & dirList,QList<QString> & fileList)1684 void checkBasket(BasketListViewItem * item, QList<QString> & dirList, QList<QString> & fileList) {
1685 BasketScene* basket = ((BasketListViewItem *)item)->basket();
1686 QString basketFolderName = basket->folderName();
1687 int basketFolderIndex = dirList.indexOf( basket->folderName() );
1688 if (basketFolderIndex < 0) {
1689 DEBUG_WIN << "<font color='red'>" + basketFolderName + " NOT FOUND!</font>";
1690 } else {
1691 dirList.removeAt(basketFolderIndex);
1692 }
1693 int basketFileIndex = fileList.indexOf( basket->folderName() + ".basket" );
1694 if (basketFileIndex < 0) {
1695 DEBUG_WIN << "<font color='red'>.basket file of " + basketFolderName + ".basket NOT FOUND!</font>";
1696 } else {
1697 fileList.removeAt(basketFileIndex);
1698 }
1699 if (!basket->loadingLaunched() && !basket->isLocked()) {
1700 basket->load();
1701 }
1702 DEBUG_WIN << "\t********************************************************************************";
1703 DEBUG_WIN << basket->basketName() << "(" << basketFolderName << ") loaded.";
1704 Note *note = basket->firstNote();
1705 if (! note ) {
1706 DEBUG_WIN << "\tHas NO notes!";
1707 } else {
1708 checkNote(note, fileList);
1709 }
1710 basket->save();
1711 qApp->processEvents(QEventLoop::ExcludeUserInputEvents, 100);
1712 for ( int i=0; i < item->childCount(); i++) {
1713 checkBasket((BasketListViewItem *) item->child(i), dirList, fileList);
1714 }
1715 if ( basket != Global::bnpView->currentBasket() ) {
1716 DEBUG_WIN << basket->basketName() << "(" << basketFolderName << ") unloading...";
1717 DEBUG_WIN << "\t********************************************************************************";
1718 basket->unbufferizeAll();
1719 } else {
1720 DEBUG_WIN << basket->basketName() << "(" << basketFolderName << ") is the current basket, not unloading.";
1721 DEBUG_WIN << "\t********************************************************************************";
1722 }
1723 qApp->processEvents(QEventLoop::ExcludeUserInputEvents, 100);
1724 }
1725
checkCleanup()1726 void BNPView::checkCleanup() {
1727 DEBUG_WIN << "Starting the check, cleanup and reindexing... (" + Global::basketsFolder() + ")";
1728 QList<QString> dirList;
1729 QList<QString> fileList;
1730 QString topDirEntry;
1731 QString subDirEntry;
1732 QFileInfo fileInfo;
1733 QDir topDir(Global::basketsFolder(), QString::null, QDir::Name | QDir::IgnoreCase, QDir::TypeMask | QDir::Hidden);
1734 foreach( topDirEntry, topDir.entryList() ) {
1735 if( topDirEntry != "." && topDirEntry != ".." ) {
1736 fileInfo.setFile(Global::basketsFolder() + "/" + topDirEntry);
1737 if (fileInfo.isDir()) {
1738 dirList << topDirEntry + "/";
1739 QDir basketDir(Global::basketsFolder() + "/" + topDirEntry,
1740 QString::null, QDir::Name | QDir::IgnoreCase, QDir::TypeMask | QDir::Hidden);
1741 foreach( subDirEntry, basketDir.entryList() ) {
1742 if (subDirEntry != "." && subDirEntry != "..") {
1743 fileList << topDirEntry + "/" + subDirEntry;
1744 }
1745 }
1746 } else if (topDirEntry != "." && topDirEntry != ".." && topDirEntry != "baskets.xml") {
1747 fileList << topDirEntry;
1748 }
1749 }
1750 }
1751 DEBUG_WIN << "Directories found: "+ QString::number(dirList.count());
1752 DEBUG_WIN << "Files found: "+ QString::number(fileList.count());
1753
1754 DEBUG_WIN << "Checking Baskets:";
1755 for (int i = 0; i < topLevelItemCount(); i++) {
1756 checkBasket( topLevelItem(i), dirList, fileList );
1757 }
1758 DEBUG_WIN << "Baskets checked.";
1759 DEBUG_WIN << "Directories remaining (not in any basket): "+ QString::number(dirList.count());
1760 DEBUG_WIN << "Files remaining (not in any basket): "+ QString::number(fileList.count());
1761
1762 foreach(topDirEntry, dirList) {
1763 DEBUG_WIN << "<font color='red'>" + topDirEntry + " does not belong to any basket!</font>";
1764 //Tools::deleteRecursively(Global::basketsFolder() + "/" + topDirEntry);
1765 //DEBUG_WIN << "<font color='red'>\t" + topDirEntry + " removed!</font>";
1766 Tools::trashRecursively(Global::basketsFolder() + "/" + topDirEntry);
1767 DEBUG_WIN << "<font color='red'>\t" + topDirEntry + " trashed!</font>";
1768 foreach(subDirEntry, fileList) {
1769 fileInfo.setFile(Global::basketsFolder() + "/" + subDirEntry);
1770 if ( ! fileInfo.isFile() ) {
1771 fileList.removeAll( subDirEntry );
1772 DEBUG_WIN << "<font color='red'>\t\t" + subDirEntry + " already removed!</font>";
1773 }
1774 }
1775 }
1776 foreach(subDirEntry, fileList) {
1777 DEBUG_WIN << "<font color='red'>" + subDirEntry + " does not belong to any note!</font>";
1778 //Tools::deleteRecursively(Global::basketsFolder() + "/" + subDirEntry);
1779 //DEBUG_WIN << "<font color='red'>\t" + subDirEntry + " removed!</font>";
1780 Tools::trashRecursively(Global::basketsFolder() + "/" + subDirEntry);
1781 DEBUG_WIN << "<font color='red'>\t" + subDirEntry + " trashed!</font>";
1782 }
1783 DEBUG_WIN << "Check, cleanup and reindexing completed";
1784 }
1785
countsChanged(BasketScene * basket)1786 void BNPView::countsChanged(BasketScene *basket)
1787 {
1788 if (basket == currentBasket())
1789 notesStateChanged();
1790 }
1791
notesStateChanged()1792 void BNPView::notesStateChanged()
1793 {
1794 BasketScene *basket = currentBasket();
1795
1796 // Update statusbar message :
1797 if (currentBasket()->isLocked())
1798 setSelectionStatus(i18n("Locked"));
1799 else if (!basket->isLoaded())
1800 setSelectionStatus(i18n("Loading..."));
1801 else if (basket->count() == 0)
1802 setSelectionStatus(i18n("No notes"));
1803 else {
1804 QString count = i18np("%1 note", "%1 notes", basket->count());
1805 QString selecteds = i18np("%1 selected", "%1 selected", basket->countSelecteds());
1806 QString showns = (currentDecoratedBasket()->filterData().isFiltering ? i18n("all matches") : i18n("no filter"));
1807 if (basket->countFounds() != basket->count())
1808 showns = i18np("%1 match", "%1 matches", basket->countFounds());
1809 setSelectionStatus(
1810 i18nc("e.g. '18 notes, 10 matches, 5 selected'", "%1, %2, %3", count, showns, selecteds));
1811 }
1812
1813 if (currentBasket()->redirectEditActions()) {
1814 m_actSelectAll ->setEnabled(!currentBasket()->selectedAllTextInEditor());
1815 m_actUnselectAll ->setEnabled(currentBasket()->hasSelectedTextInEditor());
1816 } else {
1817 m_actSelectAll ->setEnabled(basket->countSelecteds() < basket->countFounds());
1818 m_actUnselectAll ->setEnabled(basket->countSelecteds() > 0);
1819 }
1820 m_actInvertSelection ->setEnabled(basket->countFounds() > 0);
1821
1822 updateNotesActions();
1823 }
1824
updateNotesActions()1825 void BNPView::updateNotesActions()
1826 {
1827 bool isLocked = currentBasket()->isLocked();
1828 bool oneSelected = currentBasket()->countSelecteds() == 1;
1829 bool oneOrSeveralSelected = currentBasket()->countSelecteds() >= 1;
1830 bool severalSelected = currentBasket()->countSelecteds() >= 2;
1831
1832 // FIXME: m_actCheckNotes is also modified in void BNPView::areSelectedNotesCheckedChanged(bool checked)
1833 // bool BasketScene::areSelectedNotesChecked() should return false if bool BasketScene::showCheckBoxes() is false
1834 // m_actCheckNotes->setChecked( oneOrSeveralSelected &&
1835 // currentBasket()->areSelectedNotesChecked() &&
1836 // currentBasket()->showCheckBoxes() );
1837
1838 Note *selectedGroup = (severalSelected ? currentBasket()->selectedGroup() : 0);
1839
1840 m_actEditNote ->setEnabled(!isLocked && oneSelected && !currentBasket()->isDuringEdit());
1841 if (currentBasket()->redirectEditActions()) {
1842 m_actCutNote ->setEnabled(currentBasket()->hasSelectedTextInEditor());
1843 m_actCopyNote ->setEnabled(currentBasket()->hasSelectedTextInEditor());
1844 m_actPaste ->setEnabled(true);
1845 m_actDelNote ->setEnabled(currentBasket()->hasSelectedTextInEditor());
1846 } else {
1847 m_actCutNote ->setEnabled(!isLocked && oneOrSeveralSelected);
1848 m_actCopyNote ->setEnabled(oneOrSeveralSelected);
1849 m_actPaste ->setEnabled(!isLocked);
1850 m_actDelNote ->setEnabled(!isLocked && oneOrSeveralSelected);
1851 }
1852 m_actOpenNote ->setEnabled(oneOrSeveralSelected);
1853 m_actOpenNoteWith ->setEnabled(oneSelected); // TODO: oneOrSeveralSelected IF SAME TYPE
1854 m_actSaveNoteAs ->setEnabled(oneSelected); // IDEM?
1855 m_actGroup ->setEnabled(!isLocked && severalSelected && (!selectedGroup || selectedGroup->isColumn()));
1856 m_actUngroup ->setEnabled(!isLocked && selectedGroup && !selectedGroup->isColumn());
1857 m_actMoveOnTop ->setEnabled(!isLocked && oneOrSeveralSelected && !currentBasket()->isFreeLayout());
1858 m_actMoveNoteUp ->setEnabled(!isLocked && oneOrSeveralSelected); // TODO: Disable when unavailable!
1859 m_actMoveNoteDown ->setEnabled(!isLocked && oneOrSeveralSelected);
1860 m_actMoveOnBottom ->setEnabled(!isLocked && oneOrSeveralSelected && !currentBasket()->isFreeLayout());
1861
1862 for (QList<QAction *>::const_iterator action = m_insertActions.constBegin(); action != m_insertActions.constEnd(); ++action)
1863 (*action)->setEnabled(!isLocked);
1864
1865 // From the old Note::contextMenuEvent(...) :
1866 /* if (useFile() || m_type == Link) {
1867 m_type == Link ? i18n("&Open target") : i18n("&Open")
1868 m_type == Link ? i18n("Open target &with...") : i18n("Open &with...")
1869 m_type == Link ? i18n("&Save target as...") : i18n("&Save a copy as...")
1870 // If useFile() theire is always a file to open / open with / save, but :
1871 if (m_type == Link) {
1872 if (url().toDisplayString().isEmpty() && runCommand().isEmpty()) // no URL nor runCommand :
1873 popupMenu->setItemEnabled(7, false); // no possible Open !
1874 if (url().toDisplayString().isEmpty()) // no URL :
1875 popupMenu->setItemEnabled(8, false); // no possible Open with !
1876 if (url().toDisplayString().isEmpty() || url().path().endsWith("/")) // no URL or target a folder :
1877 popupMenu->setItemEnabled(9, false); // not possible to save target file
1878 }
1879 } else if (m_type != Color) {
1880 popupMenu->insertSeparator();
1881 popupMenu->insertItem( QIcon::fromTheme("document-save-as"), i18n("&Save a copy as..."), this, SLOT(slotSaveAs()), 0, 10 );
1882 }*/
1883 }
1884
1885 // BEGIN Color picker (code from KColorEdit):
1886
1887 /* Activate the mode
1888 */
slotColorFromScreen(bool global)1889 void BNPView::slotColorFromScreen(bool global)
1890 {
1891 m_colorPickWasGlobal = global;
1892 hideMainWindow();
1893
1894 currentBasket()->saveInsertionData();
1895 m_colorPicker->pickColor();
1896
1897 /* m_gettingColorFromScreen = true;
1898 qApp->processEvents();
1899 QTimer::singleShot( 100, this, SLOT(grabColorFromScreen()) );*/
1900 }
1901
slotColorFromScreenGlobal()1902 void BNPView::slotColorFromScreenGlobal()
1903 {
1904 slotColorFromScreen(true);
1905 }
1906
colorPicked(const QColor & color)1907 void BNPView::colorPicked(const QColor &color)
1908 {
1909 if (!currentBasket()->isLoaded()) {
1910 showPassiveLoading(currentBasket());
1911 currentBasket()->load();
1912 }
1913 currentBasket()->insertColor(color);
1914
1915 if (m_colorPickWasShown)
1916 showMainWindow();
1917
1918 if (Settings::usePassivePopup())
1919 showPassiveDropped(i18n("Picked color to basket <i>%1</i>"));
1920 }
1921
colorPickingCanceled()1922 void BNPView::colorPickingCanceled()
1923 {
1924 if (m_colorPickWasShown)
1925 showMainWindow();
1926 }
1927
slotConvertTexts()1928 void BNPView::slotConvertTexts()
1929 {
1930 /*
1931 int result = KMessageBox::questionYesNoCancel(
1932 this,
1933 i18n(
1934 "<p>This will convert every text notes into rich text notes.<br>"
1935 "The content of the notes will not change and you will be able to apply formating to those notes.</p>"
1936 "<p>This process cannot be reverted back: you will not be able to convert the rich text notes to plain text ones later.</p>"
1937 "<p>As a beta-tester, you are strongly encouraged to do the convert process because it is to test if plain text notes are still needed.<br>"
1938 "If nobody complain about not having plain text notes anymore, then the final version is likely to not support plain text notes anymore.</p>"
1939 "<p><b>Which basket notes do you want to convert?</b></p>"
1940 ),
1941 i18n("Convert Text Notes"),
1942 KGuiItem(i18n("Only in the Current Basket")),
1943 KGuiItem(i18n("In Every Baskets"))
1944 );
1945 if (result == KMessageBox::Cancel)
1946 return;
1947 */
1948
1949 bool conversionsDone;
1950 // if (result == KMessageBox::Yes)
1951 // conversionsDone = currentBasket()->convertTexts();
1952 // else
1953 conversionsDone = convertTexts();
1954
1955 if (conversionsDone)
1956 KMessageBox::information(this, i18n("The plain text notes have been converted to rich text."), i18n("Conversion Finished"));
1957 else
1958 KMessageBox::information(this, i18n("There are no plain text notes to convert."), i18n("Conversion Finished"));
1959 }
1960
popupMenu(const QString & menuName)1961 QMenu* BNPView::popupMenu(const QString &menuName)
1962 {
1963 QMenu *menu = 0;
1964 bool hack = false; // TODO fix this
1965 // When running in kontact and likeback Information message is shown
1966 // factory is 0. Don't show error then and don't crash either :-)
1967
1968 if (m_guiClient) {
1969 KXMLGUIFactory* factory = m_guiClient->factory();
1970 if (factory) {
1971 menu = (QMenu *)factory->container(menuName, m_guiClient);
1972 } else
1973 hack = isPart();
1974 }
1975 if (menu == 0) {
1976 if (!hack) {
1977 QString basketDataPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/basket/";
1978
1979 KMessageBox::error(this, i18n(
1980 "<p><b>The file basketui.rc seems to not exist or is too old.<br>"
1981 "%1 cannot run without it and will stop.</b></p>"
1982 "<p>Please check your installation of %2.</p>"
1983 "<p>If you do not have administrator access to install the application "
1984 "system wide, you can copy the file basketui.rc from the installation "
1985 "archive to the folder <a href='file://%3'>%4</a>.</p>"
1986 "<p>As last ressort, if you are sure the application is correctly installed "
1987 "but you had a preview version of it, try to remove the "
1988 "file %5basketui.rc</p>",
1989 QGuiApplication::applicationDisplayName(), QGuiApplication::applicationDisplayName(),
1990 basketDataPath, basketDataPath, basketDataPath),
1991 i18n("Resource not Found"), KMessageBox::AllowLink);
1992 }
1993 if (!isPart())
1994 exit(1); // We SHOULD exit right now and abord everything because the caller except menu != 0 to not crash.
1995 else
1996 menu = new QMenu; // When running in kpart we cannot exit
1997 }
1998 return menu;
1999 }
2000
showHideFilterBar(bool show,bool switchFocus)2001 void BNPView::showHideFilterBar(bool show, bool switchFocus)
2002 {
2003 // if (show != m_actShowFilter->isChecked())
2004 // m_actShowFilter->setChecked(show);
2005 m_actShowFilter->setChecked(show);
2006
2007 currentDecoratedBasket()->setFilterBarVisible(show, switchFocus);
2008 if (!show)
2009 currentDecoratedBasket()->resetFilter();
2010 }
2011
insertEmpty(int type)2012 void BNPView::insertEmpty(int type)
2013 {
2014 if (currentBasket()->isLocked()) {
2015 showPassiveImpossible(i18n("Cannot add note."));
2016 return;
2017 }
2018 currentBasket()->insertEmptyNote(type);
2019 }
2020
insertWizard(int type)2021 void BNPView::insertWizard(int type)
2022 {
2023 if (currentBasket()->isLocked()) {
2024 showPassiveImpossible(i18n("Cannot add note."));
2025 return;
2026 }
2027 currentBasket()->insertWizard(type);
2028 }
2029
2030 // BEGIN Screen Grabbing:
grabScreenshot(bool global)2031 void BNPView::grabScreenshot(bool global)
2032 {
2033 if (m_regionGrabber) {
2034 KWindowSystem::activateWindow(m_regionGrabber->winId());
2035 return;
2036 }
2037
2038 // Delay before to take a screenshot because if we hide the main window OR the systray popup menu,
2039 // we should wait the windows below to be repainted!!!
2040 // A special case is where the action is triggered with the global keyboard shortcut.
2041 // In this case, global is true, and we don't wait.
2042 // In the future, if global is also defined for other cases, check for
2043 // enum QAction::ActivationReason { UnknownActivation, EmulatedActivation, AccelActivation, PopupMenuActivation, ToolBarActivation };
2044 int delay = (isMainWindowActive() ? 500 : (global/*qApp->activePopupWidget()*/ ? 0 : 200));
2045
2046 m_colorPickWasGlobal = global;
2047 hideMainWindow();
2048
2049 currentBasket()->saveInsertionData();
2050 usleep(delay * 1000);
2051 m_regionGrabber = new RegionGrabber;
2052 connect(m_regionGrabber, SIGNAL(regionGrabbed(const QPixmap&)), this, SLOT(screenshotGrabbed(const QPixmap&)));
2053 }
2054
hideMainWindow()2055 void BNPView::hideMainWindow()
2056 {
2057 if (isMainWindowActive()) {
2058 if (Global::activeMainWindow()) {
2059 m_HiddenMainWindow = Global::activeMainWindow();
2060 m_HiddenMainWindow->hide();
2061 }
2062 m_colorPickWasShown = true;
2063 } else
2064 m_colorPickWasShown = false;
2065 }
2066
grabScreenshotGlobal()2067 void BNPView::grabScreenshotGlobal()
2068 {
2069 grabScreenshot(true);
2070 }
2071
screenshotGrabbed(const QPixmap & pixmap)2072 void BNPView::screenshotGrabbed(const QPixmap &pixmap)
2073 {
2074 delete m_regionGrabber;
2075 m_regionGrabber = 0;
2076
2077 // Cancelled (pressed Escape):
2078 if (pixmap.isNull()) {
2079 if (m_colorPickWasShown)
2080 showMainWindow();
2081 return;
2082 }
2083
2084 if (!currentBasket()->isLoaded()) {
2085 showPassiveLoading(currentBasket());
2086 currentBasket()->load();
2087 }
2088 currentBasket()->insertImage(pixmap);
2089
2090 if (m_colorPickWasShown)
2091 showMainWindow();
2092
2093 if (Settings::usePassivePopup())
2094 showPassiveDropped(i18n("Grabbed screen zone to basket <i>%1</i>"));
2095 }
2096
basketForFolderName(const QString & folderName)2097 BasketScene* BNPView::basketForFolderName(const QString &folderName)
2098 {
2099 /* QPtrList<Basket> basketsList = listBaskets();
2100 BasketScene *basket;
2101 for (basket = basketsList.first(); basket; basket = basketsList.next())
2102 if (basket->folderName() == folderName)
2103 return basket;
2104 */
2105
2106 QString name = folderName;
2107 if (!name.endsWith('/'))
2108 name += '/';
2109
2110 QTreeWidgetItemIterator it(m_tree);
2111 while (*it) {
2112 BasketListViewItem *item = ((BasketListViewItem*) * it);
2113 if (item->basket()->folderName() == name)
2114 return item->basket();
2115 ++it;
2116 }
2117
2118
2119 return 0;
2120 }
2121
noteForFileName(const QString & fileName,BasketScene & basket,Note * note)2122 Note* BNPView::noteForFileName(const QString &fileName, BasketScene &basket, Note* note)
2123 {
2124 if (!note)
2125 note = basket.firstNote();
2126 if (note->fullPath().endsWith(fileName))
2127 return note;
2128 Note* child = note->firstChild();
2129 Note* found;
2130 while (child) {
2131 found = noteForFileName(fileName, basket, child);
2132 if (found)
2133 return found;
2134 child = child->next();
2135 }
2136 return 0;
2137 }
2138
setFiltering(bool filtering)2139 void BNPView::setFiltering(bool filtering)
2140 {
2141 m_actShowFilter->setChecked(filtering);
2142 m_actResetFilter->setEnabled(filtering);
2143 if (!filtering)
2144 m_actFilterAllBaskets->setEnabled(false);
2145 }
2146
undo()2147 void BNPView::undo()
2148 {
2149 // TODO
2150 }
2151
redo()2152 void BNPView::redo()
2153 {
2154 // TODO
2155 }
2156
pasteToBasket(int,QClipboard::Mode)2157 void BNPView::pasteToBasket(int /*index*/, QClipboard::Mode /*mode*/)
2158 {
2159 //TODO: REMOVE!
2160 //basketAt(index)->pasteNote(mode);
2161 }
2162
propBasket()2163 void BNPView::propBasket()
2164 {
2165 BasketPropertiesDialog dialog(currentBasket(), this);
2166 dialog.exec();
2167 }
2168
delBasket()2169 void BNPView::delBasket()
2170 {
2171 // DecoratedBasket *decoBasket = currentDecoratedBasket();
2172 BasketScene *basket = currentBasket();
2173
2174 int really = KMessageBox::questionYesNo(this,
2175 i18n("<qt>Do you really want to remove the basket <b>%1</b> and its contents?</qt>",
2176 Tools::textToHTMLWithoutP(basket->basketName())),
2177 i18n("Remove Basket")
2178 , KGuiItem(i18n("&Remove Basket"), "edit-delete"), KStandardGuiItem::cancel());
2179
2180 if (really == KMessageBox::No)
2181 return;
2182
2183 QStringList basketsList = listViewItemForBasket(basket)->childNamesTree(0);
2184 if (basketsList.count() > 0) {
2185 int deleteChilds = KMessageBox::questionYesNoList(this,
2186 i18n("<qt><b>%1</b> has the following children baskets.<br>Do you want to remove them too?</qt>",
2187 Tools::textToHTMLWithoutP(basket->basketName())),
2188 basketsList,
2189 i18n("Remove Children Baskets")
2190 , KGuiItem(i18n("&Remove Children Baskets"), "edit-delete"));
2191
2192 if (deleteChilds == KMessageBox::No)
2193 return;
2194 }
2195
2196 doBasketDeletion(basket);
2197
2198 GitWrapper::commitDeleteBasket(basket);
2199 }
2200
doBasketDeletion(BasketScene * basket)2201 void BNPView::doBasketDeletion(BasketScene *basket)
2202 {
2203 basket->closeEditor();
2204
2205 QTreeWidgetItem *basketItem = listViewItemForBasket(basket);
2206 for (int i = 0; i < basketItem->childCount(); i++) {
2207 // First delete the child baskets:
2208 doBasketDeletion(((BasketListViewItem*)basketItem->child(i))->basket());
2209 }
2210 // Then, basket have no child anymore, delete it:
2211 DecoratedBasket *decoBasket = basket->decoration();
2212 basket->deleteFiles();
2213 removeBasket(basket);
2214 // Remove the action to avoir keyboard-shortcut clashes:
2215 delete basket->m_action; // FIXME: It's quick&dirty. In the future, the Basket should be deleted, and then the QAction deleted in the Basket destructor.
2216 delete decoBasket;
2217 // delete basket;
2218 }
2219
password()2220 void BNPView::password()
2221 {
2222 #ifdef HAVE_LIBGPGME
2223 QPointer<PasswordDlg> dlg = new PasswordDlg(qApp->activeWindow());
2224 BasketScene *cur = currentBasket();
2225
2226 dlg->setType(cur->encryptionType());
2227 dlg->setKey(cur->encryptionKey());
2228 if (dlg->exec()) {
2229 cur->setProtection(dlg->type(), dlg->key());
2230 if (cur->encryptionType() != BasketScene::NoEncryption) {
2231 //Clear metadata
2232 Tools::deleteMetadataRecursively(cur->fullPath());
2233 cur->lock();
2234 }
2235 }
2236 #endif
2237 }
2238
lockBasket()2239 void BNPView::lockBasket()
2240 {
2241 #ifdef HAVE_LIBGPGME
2242 BasketScene *cur = currentBasket();
2243
2244 cur->lock();
2245 #endif
2246 }
2247
saveAsArchive()2248 void BNPView::saveAsArchive()
2249 {
2250 BasketScene *basket = currentBasket();
2251
2252 QDir dir;
2253
2254 KConfigGroup config = KSharedConfig::openConfig()->group("Basket Archive");
2255 QString folder = config.readEntry("lastFolder", QDir::homePath()) + "/";
2256 QString url = folder + QString(basket->basketName()).replace("/", "_") + ".baskets";
2257
2258 QString filter = "*.baskets|" + i18n("Basket Archives") + "\n*|" + i18n("All Files");
2259 QString destination = url;
2260 for (bool askAgain = true; askAgain;) {
2261 destination = QFileDialog::getSaveFileName(NULL, i18n("Save as Basket Archive"), destination, filter);
2262 if (destination.isEmpty()) // User canceled
2263 return;
2264 if (dir.exists(destination)) {
2265 int result = KMessageBox::questionYesNoCancel(
2266 this,
2267 "<qt>" + i18n("The file <b>%1</b> already exists. Do you really want to override it?",
2268 QUrl::fromLocalFile(destination).fileName()),
2269 i18n("Override File?"),
2270 KGuiItem(i18n("&Override"), "document-save")
2271 );
2272 if (result == KMessageBox::Cancel)
2273 return;
2274 else if (result == KMessageBox::Yes)
2275 askAgain = false;
2276 } else
2277 askAgain = false;
2278 }
2279 bool withSubBaskets = true;//KMessageBox::questionYesNo(this, i18n("Do you want to export sub-baskets too?"), i18n("Save as Basket Archive")) == KMessageBox::Yes;
2280
2281 config.writeEntry("lastFolder", QUrl::fromLocalFile(destination).adjusted(QUrl::RemoveFilename).path());
2282 config.sync();
2283
2284 Archive::save(basket, withSubBaskets, destination);
2285 }
2286
2287 QString BNPView::s_fileToOpen = "";
2288
delayedOpenArchive()2289 void BNPView::delayedOpenArchive()
2290 {
2291 Archive::open(s_fileToOpen);
2292 }
2293
2294 QString BNPView::s_basketToOpen = "";
2295
delayedOpenBasket()2296 void BNPView::delayedOpenBasket()
2297 {
2298 BasketScene *bv = this->basketForFolderName(s_basketToOpen);
2299 this->setCurrentBasketInHistory(bv);
2300 }
2301
openArchive()2302 void BNPView::openArchive()
2303 {
2304 QString filter = "*.baskets|" + i18n("Basket Archives") + "\n*|" + i18n("All Files");
2305 QString path = QFileDialog::getOpenFileName(this, i18n("Open Basket Archive"), QString(), filter);
2306 if (!path.isEmpty()) // User has not canceled
2307 Archive::open(path);
2308 }
2309
activatedTagShortcut()2310 void BNPView::activatedTagShortcut()
2311 {
2312 Tag *tag = Tag::tagForKAction((QAction *)sender());
2313 currentBasket()->activatedTagShortcut(tag);
2314 }
2315
slotBasketChanged()2316 void BNPView::slotBasketChanged()
2317 {
2318 m_actFoldBasket->setEnabled(canFold());
2319 m_actExpandBasket->setEnabled(canExpand());
2320 if (currentBasket()->decoration()->filterData().isFiltering)
2321 currentBasket()->decoration()->filterBar()->show(); // especially important for Filter all
2322 setFiltering(currentBasket() && currentBasket()->decoration()->filterData().isFiltering);
2323 this->canUndoRedoChanged();
2324 }
2325
canUndoRedoChanged()2326 void BNPView::canUndoRedoChanged()
2327 {
2328 if(m_history) {
2329 m_actPreviousBasket->setEnabled(m_history->canUndo());
2330 m_actNextBasket ->setEnabled(m_history->canRedo());
2331 }
2332 }
2333
currentBasketChanged()2334 void BNPView::currentBasketChanged()
2335 {
2336 }
2337
isLockedChanged()2338 void BNPView::isLockedChanged()
2339 {
2340 bool isLocked = currentBasket()->isLocked();
2341
2342 setLockStatus(isLocked);
2343
2344 // m_actLockBasket->setChecked(isLocked);
2345 m_actPropBasket->setEnabled(!isLocked);
2346 m_actDelBasket ->setEnabled(!isLocked);
2347 updateNotesActions();
2348 }
2349
askNewBasket()2350 void BNPView::askNewBasket()
2351 {
2352 askNewBasket(0, 0);
2353
2354 GitWrapper::commitCreateBasket();
2355 }
2356
askNewBasket(BasketScene * parent,BasketScene * pickProperties)2357 void BNPView::askNewBasket(BasketScene *parent, BasketScene *pickProperties)
2358 {
2359 NewBasketDefaultProperties properties;
2360 if (pickProperties) {
2361 properties.icon = pickProperties->icon();
2362 properties.backgroundImage = pickProperties->backgroundImageName();
2363 properties.backgroundColor = pickProperties->backgroundColorSetting();
2364 properties.textColor = pickProperties->textColorSetting();
2365 properties.freeLayout = pickProperties->isFreeLayout();
2366 properties.columnCount = pickProperties->columnsCount();
2367 }
2368
2369 NewBasketDialog(parent, properties, this).exec();
2370 }
2371
askNewSubBasket()2372 void BNPView::askNewSubBasket()
2373 {
2374 askNewBasket(/*parent=*/currentBasket(), /*pickPropertiesOf=*/currentBasket());
2375 }
2376
askNewSiblingBasket()2377 void BNPView::askNewSiblingBasket()
2378 {
2379 askNewBasket(/*parent=*/parentBasketOf(currentBasket()), /*pickPropertiesOf=*/currentBasket());
2380 }
2381
globalPasteInCurrentBasket()2382 void BNPView::globalPasteInCurrentBasket()
2383 {
2384 currentBasket()->setInsertPopupMenu();
2385 pasteInCurrentBasket();
2386 currentBasket()->cancelInsertPopupMenu();
2387 }
2388
pasteInCurrentBasket()2389 void BNPView::pasteInCurrentBasket()
2390 {
2391 currentBasket()->pasteNote();
2392
2393 if (Settings::usePassivePopup())
2394 showPassiveDropped(i18n("Clipboard content pasted to basket <i>%1</i>"));
2395 }
2396
pasteSelInCurrentBasket()2397 void BNPView::pasteSelInCurrentBasket()
2398 {
2399 currentBasket()->pasteNote(QClipboard::Selection);
2400
2401 if (Settings::usePassivePopup())
2402 showPassiveDropped(i18n("Selection pasted to basket <i>%1</i>"));
2403 }
2404
showPassiveDropped(const QString & title)2405 void BNPView::showPassiveDropped(const QString &title)
2406 {
2407 if (! currentBasket()->isLocked()) {
2408 // TODO: Keep basket, so that we show the message only if something was added to a NOT visible basket
2409 m_passiveDroppedTitle = title;
2410 m_passiveDroppedSelection = currentBasket()->selectedNotes();
2411 QTimer::singleShot(c_delayTooltipTime, this, SLOT(showPassiveDroppedDelayed()));
2412 // DELAY IT BELOW:
2413 } else
2414 showPassiveImpossible(i18n("No note was added."));
2415 }
2416
showPassiveDroppedDelayed()2417 void BNPView::showPassiveDroppedDelayed()
2418 {
2419 if (isMainWindowActive() || m_passiveDroppedSelection == 0)
2420 return;
2421
2422 QString title = m_passiveDroppedTitle;
2423
2424 QImage contentsImage = NoteDrag::feedbackPixmap(m_passiveDroppedSelection).toImage();
2425 QResource::registerResource(contentsImage.bits(), ":/images/passivepopup_image");
2426
2427 if (Settings::useSystray()){
2428
2429 /*Uncomment after switching to QSystemTrayIcon or port to KStatusNotifierItem
2430 See also other occurences of Global::systemTray below*/
2431 /*KPassivePopup::message(KPassivePopup::Boxed,
2432 title.arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2433 (contentsImage.isNull() ? "" : "<img src=\":/images/passivepopup_image\">"),
2434 KIconLoader::global()->loadIcon(
2435 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2436 KIconLoader::DefaultState, QStringList(), 0L, true
2437 ),
2438 Global::systemTray);*/
2439 }
2440 else{
2441 KPassivePopup::message(KPassivePopup::Boxed,
2442 title.arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2443 (contentsImage.isNull() ? "" : "<img src=\":/images/passivepopup_image\">"),
2444 KIconLoader::global()->loadIcon(
2445 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2446 KIconLoader::DefaultState, QStringList(), 0L, true
2447 ),
2448 (QWidget*)this);
2449 }
2450 }
2451
showPassiveImpossible(const QString & message)2452 void BNPView::showPassiveImpossible(const QString &message)
2453 {
2454 if (Settings::useSystray()){
2455 /*KPassivePopup::message(KPassivePopup::Boxed,
2456 QString("<font color=red>%1</font>")
2457 .arg(i18n("Basket <i>%1</i> is locked"))
2458 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2459 message,
2460 KIconLoader::global()->loadIcon(
2461 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2462 KIconLoader::DefaultState, QStringList(), 0L, true
2463 ),
2464 Global::systemTray);*/
2465 }
2466 else{
2467 /*KPassivePopup::message(KPassivePopup::Boxed,
2468 QString("<font color=red>%1</font>")
2469 .arg(i18n("Basket <i>%1</i> is locked"))
2470 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2471 message,
2472 KIconLoader::global()->loadIcon(
2473 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2474 KIconLoader::DefaultState, QStringList(), 0L, true
2475 ),
2476 (QWidget*)this);*/
2477
2478 }
2479 }
2480
showPassiveContentForced()2481 void BNPView::showPassiveContentForced()
2482 {
2483 showPassiveContent(/*forceShow=*/true);
2484 }
2485
showPassiveContent(bool forceShow)2486 void BNPView::showPassiveContent(bool forceShow/* = false*/)
2487 {
2488 if (!forceShow && isMainWindowActive())
2489 return;
2490
2491 // FIXME: Duplicate code (2 times)
2492 QString message;
2493
2494 if(Settings::useSystray()){
2495 /*KPassivePopup::message(KPassivePopup::Boxed,
2496 "<qt>" + Tools::makeStandardCaption(
2497 currentBasket()->isLocked() ? QString("%1 <font color=gray30>%2</font>")
2498 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName()), i18n("(Locked)"))
2499 : Tools::textToHTMLWithoutP(currentBasket()->basketName())
2500 ),
2501 message,
2502 KIconLoader::global()->loadIcon(
2503 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2504 KIconLoader::DefaultState, QStringList(), 0L, true
2505 ),
2506 Global::systemTray);*/
2507 }
2508 else{
2509 KPassivePopup::message(KPassivePopup::Boxed,
2510 "<qt>" + Tools::makeStandardCaption(
2511 currentBasket()->isLocked() ? QString("%1 <font color=gray30>%2</font>")
2512 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName()), i18n("(Locked)"))
2513 : Tools::textToHTMLWithoutP(currentBasket()->basketName())
2514 ),
2515 message,
2516 KIconLoader::global()->loadIcon(
2517 currentBasket()->icon(), KIconLoader::NoGroup, 16,
2518 KIconLoader::DefaultState, QStringList(), 0L, true
2519 ),
2520 (QWidget*)this);
2521
2522 }
2523 }
2524
showPassiveLoading(BasketScene * basket)2525 void BNPView::showPassiveLoading(BasketScene *basket)
2526 {
2527 if (isMainWindowActive())
2528 return;
2529
2530 if (Settings::useSystray()){
2531 /*KPassivePopup::message(KPassivePopup::Boxed,
2532 Tools::textToHTMLWithoutP(basket->basketName()),
2533 i18n("Loading..."),
2534 KIconLoader::global()->loadIcon(
2535 basket->icon(), KIconLoader::NoGroup, 16, KIconLoader::DefaultState,
2536 QStringList(), 0L, true
2537 ),
2538 Global::systemTray);*/
2539 }
2540 else{
2541 KPassivePopup::message(KPassivePopup::Boxed,
2542 Tools::textToHTMLWithoutP(basket->basketName()),
2543 i18n("Loading..."),
2544 KIconLoader::global()->loadIcon(
2545 basket->icon(), KIconLoader::NoGroup, 16, KIconLoader::DefaultState,
2546 QStringList(), 0L, true
2547 ),
2548 (QWidget *)this);
2549 }
2550 }
2551
addNoteText()2552 void BNPView::addNoteText()
2553 {
2554 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Text);
2555 }
addNoteHtml()2556 void BNPView::addNoteHtml()
2557 {
2558 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Html);
2559 }
addNoteImage()2560 void BNPView::addNoteImage()
2561 {
2562 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Image);
2563 }
addNoteLink()2564 void BNPView::addNoteLink()
2565 {
2566 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Link);
2567 }
addNoteCrossReference()2568 void BNPView::addNoteCrossReference()
2569 {
2570 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::CrossReference);
2571 }
addNoteColor()2572 void BNPView::addNoteColor()
2573 {
2574 showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Color);
2575 }
2576
aboutToHideNewBasketPopup()2577 void BNPView::aboutToHideNewBasketPopup()
2578 {
2579 QTimer::singleShot(0, this, SLOT(cancelNewBasketPopup()));
2580 }
2581
cancelNewBasketPopup()2582 void BNPView::cancelNewBasketPopup()
2583 {
2584 m_newBasketPopup = false;
2585 }
2586
setNewBasketPopup()2587 void BNPView::setNewBasketPopup()
2588 {
2589 m_newBasketPopup = true;
2590 }
2591
setWindowTitle(QString s)2592 void BNPView::setWindowTitle(QString s)
2593 {
2594 emit setWindowCaption(s);
2595 }
2596
updateStatusBarHint()2597 void BNPView::updateStatusBarHint()
2598 {
2599 m_statusbar->updateStatusBarHint();
2600 }
2601
setSelectionStatus(QString s)2602 void BNPView::setSelectionStatus(QString s)
2603 {
2604 m_statusbar->setSelectionStatus(s);
2605 }
2606
setLockStatus(bool isLocked)2607 void BNPView::setLockStatus(bool isLocked)
2608 {
2609 m_statusbar->setLockStatus(isLocked);
2610 }
2611
postStatusbarMessage(const QString & msg)2612 void BNPView::postStatusbarMessage(const QString& msg)
2613 {
2614 m_statusbar->postStatusbarMessage(msg);
2615 }
2616
setStatusBarHint(const QString & hint)2617 void BNPView::setStatusBarHint(const QString &hint)
2618 {
2619 m_statusbar->setStatusBarHint(hint);
2620 }
2621
setUnsavedStatus(bool isUnsaved)2622 void BNPView::setUnsavedStatus(bool isUnsaved)
2623 {
2624 m_statusbar->setUnsavedStatus(isUnsaved);
2625 }
2626
setActive(bool active)2627 void BNPView::setActive(bool active)
2628 {
2629 KMainWindow* win = Global::activeMainWindow();
2630 if (!win)
2631 return;
2632
2633 if (active == isMainWindowActive())
2634 return;
2635 //qApp->updateUserTimestamp(); // If "activate on mouse hovering systray", or "on drag through systray"
2636 Global::systemTray->activate();
2637 }
2638
hideOnEscape()2639 void BNPView::hideOnEscape()
2640 {
2641 if (Settings::useSystray())
2642 setActive(false);
2643 }
2644
isPart()2645 bool BNPView::isPart()
2646 {
2647 return objectName() == "BNPViewPart";
2648 }
2649
isMainWindowActive()2650 bool BNPView::isMainWindowActive()
2651 {
2652 KMainWindow* main = Global::activeMainWindow();
2653 if (main && main->isActiveWindow())
2654 return true;
2655 return false;
2656 }
2657
newBasket()2658 void BNPView::newBasket()
2659 {
2660 askNewBasket();
2661 }
2662
createNoteHtml(const QString content,const QString basket)2663 bool BNPView::createNoteHtml(const QString content, const QString basket)
2664 {
2665 BasketScene* b = basketForFolderName(basket);
2666 if (!b)
2667 return false;
2668 Note* note = NoteFactory::createNoteHtml(content, b);
2669 if (!note)
2670 return false;
2671 b -> insertCreatedNote(note);
2672 return true;
2673 }
2674
changeNoteHtml(const QString content,const QString basket,const QString noteName)2675 bool BNPView::changeNoteHtml(const QString content, const QString basket, const QString noteName)
2676 {
2677 BasketScene* b = basketForFolderName(basket);
2678 if (!b)
2679 return false;
2680 Note* note = noteForFileName(noteName , *b);
2681 if (!note || note->content()->type() != NoteType::Html)
2682 return false;
2683 HtmlContent* noteContent = (HtmlContent*)note->content();
2684 noteContent->setHtml(content);
2685 note->saveAgain();
2686 return true;
2687 }
2688
createNoteFromFile(const QString url,const QString basket)2689 bool BNPView::createNoteFromFile(const QString url, const QString basket)
2690 {
2691 BasketScene* b = basketForFolderName(basket);
2692 if (!b)
2693 return false;
2694 QUrl kurl(url);
2695 if (url.isEmpty())
2696 return false;
2697 Note* n = NoteFactory::copyFileAndLoad(kurl, b);
2698 if (!n)
2699 return false;
2700 b->insertCreatedNote(n);
2701 return true;
2702 }
2703
listBaskets()2704 QStringList BNPView::listBaskets()
2705 {
2706 QStringList basketList;
2707
2708 QTreeWidgetItemIterator it(m_tree);
2709 while (*it) {
2710 BasketListViewItem *item = ((BasketListViewItem*) * it);
2711 basketList.append(item->basket()->basketName());
2712 basketList.append(item->basket()->folderName());
2713 ++it;
2714 }
2715 return basketList;
2716 }
2717
handleCommandLine()2718 void BNPView::handleCommandLine()
2719 {
2720 QCommandLineParser* parser = Global::commandLineOpts;
2721
2722 /* Custom data folder */
2723 QString customDataFolder = parser->value("data-folder");
2724 if (!customDataFolder.isNull() && !customDataFolder.isEmpty()) {
2725 Global::setCustomSavesFolder(customDataFolder);
2726 }
2727 /* Debug window */
2728 if (parser->isSet("debug")) {
2729 new DebugWindow();
2730 Global::debugWindow->show();
2731 }
2732
2733 /* Crash Handler to Mail Developers when Crashing: */
2734 #ifndef BASKET_USE_DRKONQI
2735 if (!parser->isSet("use-drkonqi"))
2736 KCrash::setCrashHandler(Crash::crashHandler);
2737 #endif
2738 }
2739
reloadBasket(const QString & folderName)2740 void BNPView::reloadBasket(const QString &folderName)
2741 {
2742 basketForFolderName(folderName)->reload();
2743 }
2744
2745 /** Scenario of "Hide main window to system tray icon when mouse move out of the window" :
2746 * - At enterEvent() we stop m_tryHideTimer
2747 * - After that and before next, we are SURE cursor is hovering window
2748 * - At leaveEvent() we restart m_tryHideTimer
2749 * - Every 'x' ms, timeoutTryHide() seek if cursor hover a widget of the application or not
2750 * - If yes, we musn't hide the window
2751 * - But if not, we start m_hideTimer to hide main window after a configured elapsed time
2752 * - timeoutTryHide() continue to be called and if cursor move again to one widget of the app, m_hideTimer is stopped
2753 * - If after the configured time cursor hasn't go back to a widget of the application, timeoutHide() is called
2754 * - It then hide the main window to systray icon
2755 * - When the user will show it, enterEvent() will be called the first time he enter mouse to it
2756 * - ...
2757 */
2758
2759 /** Why do as this ? Problems with the use of only enterEvent() and leaveEvent() :
2760 * - Resize window or hover titlebar isn't possible : leave/enterEvent
2761 * are
2762 * > Use the grip or Alt+rightDND to resize window
2763 * > Use Alt+DND to move window
2764 * - Each menu trigger the leavEvent
2765 */
2766
enterEvent(QEvent *)2767 void BNPView::enterEvent(QEvent*)
2768 {
2769 if (m_tryHideTimer)
2770 m_tryHideTimer->stop();
2771 if (m_hideTimer)
2772 m_hideTimer->stop();
2773 }
2774
leaveEvent(QEvent *)2775 void BNPView::leaveEvent(QEvent*)
2776 {
2777 if (Settings::useSystray() && Settings::hideOnMouseOut() && m_tryHideTimer)
2778 m_tryHideTimer->start(50);
2779 }
2780
timeoutTryHide()2781 void BNPView::timeoutTryHide()
2782 {
2783 // If a menu is displayed, do nothing for the moment
2784 if (qApp->activePopupWidget() != 0L)
2785 return;
2786
2787 if (qApp->widgetAt(QCursor::pos()) != 0L)
2788 m_hideTimer->stop();
2789 else if (! m_hideTimer->isActive()) { // Start only one time
2790 m_hideTimer->setSingleShot(true);
2791 m_hideTimer->start(Settings::timeToHideOnMouseOut() * 100);
2792 }
2793
2794 // If a sub-dialog is oppened, we musn't hide the main window:
2795 if (qApp->activeWindow() != 0L && qApp->activeWindow() != Global::activeMainWindow())
2796 m_hideTimer->stop();
2797 }
2798
timeoutHide()2799 void BNPView::timeoutHide()
2800 {
2801 // We check that because the setting can have been set to off
2802 if (Settings::useSystray() && Settings::hideOnMouseOut())
2803 setActive(false);
2804 m_tryHideTimer->stop();
2805 }
2806
changedSelectedNotes()2807 void BNPView::changedSelectedNotes()
2808 {
2809 // tabChanged(0); // FIXME: NOT OPTIMIZED
2810 }
2811
2812 /*void BNPView::areSelectedNotesCheckedChanged(bool checked)
2813 {
2814 m_actCheckNotes->setChecked(checked && currentBasket()->showCheckBoxes());
2815 }*/
2816
enableActions()2817 void BNPView::enableActions()
2818 {
2819 BasketScene *basket = currentBasket();
2820 if (!basket)
2821 return;
2822 if (m_actLockBasket)
2823 m_actLockBasket->setEnabled(!basket->isLocked() && basket->isEncrypted());
2824 if (m_actPassBasket)
2825 m_actPassBasket->setEnabled(!basket->isLocked());
2826 m_actPropBasket->setEnabled(!basket->isLocked());
2827 m_actDelBasket->setEnabled(!basket->isLocked());
2828 m_actExportToHtml->setEnabled(!basket->isLocked());
2829 m_actShowFilter->setEnabled(!basket->isLocked());
2830 m_actFilterAllBaskets->setEnabled(!basket->isLocked());
2831 m_actResetFilter->setEnabled(!basket->isLocked());
2832 basket->decoration()->filterBar()->setEnabled(!basket->isLocked());
2833 }
2834
showMainWindow()2835 void BNPView::showMainWindow()
2836 {
2837 if (m_HiddenMainWindow) {
2838 m_HiddenMainWindow->show();
2839 m_HiddenMainWindow = NULL;
2840 } else {
2841 KMainWindow *win = Global::activeMainWindow();
2842
2843 if (win) {
2844 win->show();
2845 }
2846 }
2847
2848 setActive(true);
2849 emit showPart();
2850 }
2851
populateTagsMenu()2852 void BNPView::populateTagsMenu()
2853 {
2854 QMenu *menu = (QMenu*)(popupMenu("tags"));
2855 if (menu == 0 || currentBasket() == 0) // TODO: Display a messagebox. [menu is 0, surely because on first launch, the XMLGUI does not work!]
2856 return;
2857 menu->clear();
2858
2859 Note *referenceNote;
2860 if (currentBasket()->focusedNote() && currentBasket()->focusedNote()->isSelected())
2861 referenceNote = currentBasket()->focusedNote();
2862 else
2863 referenceNote = currentBasket()->firstSelected();
2864
2865 populateTagsMenu(*menu, referenceNote);
2866
2867 m_lastOpenedTagsMenu = menu;
2868 // connect( menu, SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()) );
2869 }
2870
populateTagsMenu(QMenu & menu,Note * referenceNote)2871 void BNPView::populateTagsMenu(QMenu &menu, Note *referenceNote)
2872 {
2873 if (currentBasket() == 0)
2874 return;
2875
2876 currentBasket()->m_tagPopupNote = referenceNote;
2877 bool enable = currentBasket()->countSelecteds() > 0;
2878
2879 QList<Tag*>::iterator it;
2880 Tag *currentTag;
2881 State *currentState;
2882 int i = 10;
2883 for (it = Tag::all.begin(); it != Tag::all.end(); ++it) {
2884 // Current tag and first state of it:
2885 currentTag = *it;
2886 currentState = currentTag->states().first();
2887
2888 QKeySequence sequence;
2889 if (!currentTag->shortcut().isEmpty())
2890 sequence = currentTag->shortcut();
2891
2892 StateAction *mi = new StateAction(currentState, QKeySequence(sequence), this, true);
2893
2894 // The previously set ID will be set in the actions themselves as data.
2895 mi->setData(i);
2896
2897 if (referenceNote && referenceNote->hasTag(currentTag))
2898 mi->setChecked(true);
2899
2900 menu.addAction(mi);
2901
2902 if (!currentTag->shortcut().isEmpty())
2903 m_actionCollection->setDefaultShortcut(mi, sequence);
2904
2905 mi->setEnabled(enable);
2906 ++i;
2907 }
2908
2909 menu.addSeparator();
2910
2911 // I don't like how this is implemented; but I can't think of a better way
2912 // to do this, so I will have to leave it for now
2913 QAction *act = new QAction(i18n("&Assign new Tag..."), &menu);
2914 act->setData(1);
2915 act->setEnabled(enable);
2916 menu.addAction(act);
2917
2918 act = new QAction(QIcon::fromTheme("edit-delete"), i18n("&Remove All"), &menu);
2919 act->setData(2);
2920 if (!currentBasket()->selectedNotesHaveTags())
2921 act->setEnabled(false);
2922 menu.addAction(act);
2923
2924 act = new QAction(QIcon::fromTheme("configure"), i18n("&Customize..."), &menu);
2925 act->setData(3);
2926 menu.addAction(act);
2927
2928 connect(&menu, SIGNAL(triggered(QAction *)), currentBasket(), SLOT(toggledTagInMenu(QAction *)));
2929 connect(&menu, SIGNAL(aboutToHide()), currentBasket(), SLOT(unlockHovering()));
2930 connect(&menu, SIGNAL(aboutToHide()), currentBasket(), SLOT(disableNextClick()));
2931 }
2932
connectTagsMenu()2933 void BNPView::connectTagsMenu()
2934 {
2935 connect(popupMenu("tags"), SIGNAL(aboutToShow()), this, SLOT(populateTagsMenu()));
2936 connect(popupMenu("tags"), SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()));
2937 }
2938
2939 /*
2940 * The Tags menu is ONLY created once the BasKet KPart is first shown.
2941 * So we can use this menu only from then?
2942 * When the KPart is changed in Kontact, and then the BasKet KPart is shown again,
2943 * Kontact created a NEW Tags menu. So we should connect again.
2944 * But when Kontact main window is hidden and then re-shown, the menu does not change.
2945 * So we disconnect at hide event to ensure only one connection: the next show event will not connects another time.
2946 */
2947
showEvent(QShowEvent *)2948 void BNPView::showEvent(QShowEvent*)
2949 {
2950 if (isPart())
2951 QTimer::singleShot(0, this, SLOT(connectTagsMenu()));
2952
2953 if (m_firstShow) {
2954 m_firstShow = false;
2955 onFirstShow();
2956 }
2957 if (isPart()/*TODO: && !LikeBack::enabledBar()*/) {
2958 Global::likeBack->enableBar();
2959 }
2960 }
2961
hideEvent(QHideEvent *)2962 void BNPView::hideEvent(QHideEvent*)
2963 {
2964 if (isPart()) {
2965 disconnect(popupMenu("tags"), SIGNAL(aboutToShow()), this, SLOT(populateTagsMenu()));
2966 disconnect(popupMenu("tags"), SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()));
2967 }
2968
2969 if (isPart())
2970 Global::likeBack->disableBar();
2971 }
2972
disconnectTagsMenu()2973 void BNPView::disconnectTagsMenu()
2974 {
2975 QTimer::singleShot(0, this, SLOT(disconnectTagsMenuDelayed()));
2976 }
2977
disconnectTagsMenuDelayed()2978 void BNPView::disconnectTagsMenuDelayed()
2979 {
2980 disconnect(m_lastOpenedTagsMenu, SIGNAL(triggered(QAction *)), currentBasket(), SLOT(toggledTagInMenu(QAction *)));
2981 disconnect(m_lastOpenedTagsMenu, SIGNAL(aboutToHide()), currentBasket(), SLOT(unlockHovering()));
2982 disconnect(m_lastOpenedTagsMenu, SIGNAL(aboutToHide()), currentBasket(), SLOT(disableNextClick()));
2983 }
2984
loadCrossReference(QString link)2985 void BNPView::loadCrossReference(QString link)
2986 {
2987 //remove "basket://" and any encoding.
2988 QString folderName = link.mid(9, link.length() - 9);
2989 folderName = QUrl::fromPercentEncoding(folderName.toUtf8());
2990
2991 BasketScene* basket = this->basketForFolderName(folderName);
2992
2993 if(!basket)
2994 return;
2995
2996 this->setCurrentBasketInHistory(basket);
2997 }
2998
folderFromBasketNameLink(QStringList pages,QTreeWidgetItem * parent)2999 QString BNPView::folderFromBasketNameLink(QStringList pages, QTreeWidgetItem *parent)
3000 {
3001 QString found = "";
3002
3003 QString page = pages.first();
3004
3005 page = QUrl::fromPercentEncoding(page.toUtf8());
3006 pages.removeFirst();
3007
3008 if(page == "..") {
3009 QTreeWidgetItem *p;
3010 if(parent)
3011 p = parent->parent();
3012 else
3013 p = m_tree->currentItem()->parent();
3014 found = this->folderFromBasketNameLink(pages, p);
3015 } else if(!parent && page.isEmpty()) {
3016 parent = m_tree->invisibleRootItem();
3017 found = this->folderFromBasketNameLink(pages, parent);
3018 } else {
3019 if(!parent && (page == "." || !page.isEmpty())) {
3020 parent = m_tree->currentItem();
3021 }
3022 QRegExp re(":\\{([0-9]+)\\}");
3023 re.setMinimal(true);
3024 int pos = 0;
3025
3026 pos = re.indexIn(page, pos);
3027 int basketNum = 1;
3028
3029 if(pos != -1)
3030 basketNum = re.cap(1).toInt();
3031
3032 page = page.left(page.length() - re.matchedLength());
3033
3034 for(int i = 0; i < parent->childCount(); i++) {
3035 QTreeWidgetItem *child = parent->child(i);
3036
3037 if(child->text(0).toLower() == page.toLower()) {
3038 basketNum--;
3039 if(basketNum == 0) {
3040 if(pages.count() > 0) {
3041 found = this->folderFromBasketNameLink(pages, child);
3042 break;
3043 } else {
3044 found = ((BasketListViewItem*)child)->basket()->folderName();
3045 break;
3046 }
3047 }
3048 } else
3049 found = "";
3050 }
3051 }
3052
3053 return found;
3054 }
3055
sortChildrenAsc()3056 void BNPView::sortChildrenAsc()
3057 {
3058 m_tree->currentItem()->sortChildren(0, Qt::AscendingOrder);
3059 }
3060
sortChildrenDesc()3061 void BNPView::sortChildrenDesc()
3062 {
3063 m_tree->currentItem()->sortChildren(0, Qt::DescendingOrder);
3064 }
3065
sortSiblingsAsc()3066 void BNPView::sortSiblingsAsc()
3067 {
3068 QTreeWidgetItem *parent = m_tree->currentItem()->parent();
3069 if(!parent)
3070 m_tree->sortItems(0, Qt::AscendingOrder);
3071 else
3072 parent->sortChildren(0, Qt::AscendingOrder);
3073 }
3074
sortSiblingsDesc()3075 void BNPView::sortSiblingsDesc()
3076 {
3077 QTreeWidgetItem *parent = m_tree->currentItem()->parent();
3078 if(!parent)
3079 m_tree->sortItems(0, Qt::DescendingOrder);
3080 else
3081 parent->sortChildren(0, Qt::DescendingOrder);
3082 }
3083