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