Ran am2cmake.
[basket4.git] / src / bnpview.cpp
blob3a3f91e08c0b890e868c980ce374cffd47412229
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 ***************************************************************************/
21 /// NEW:
23 #include <q3widgetstack.h>
24 #include <qregexp.h>
25 #include <qpixmap.h>
26 #include <qpainter.h>
27 #include <qimage.h>
28 #include <qbitmap.h>
29 #include <q3whatsthis.h>
30 //Added by qt3to4:
31 #include <QResizeEvent>
32 #include <QShowEvent>
33 #include <Q3ValueList>
34 #include <QKeyEvent>
35 #include <QEvent>
36 #include <QHideEvent>
37 #include <Q3CString>
38 #include <Q3PopupMenu>
39 #include <kpopupmenu.h>
40 #include <qsignalmapper.h>
41 #include <qdir.h>
42 #include <kicontheme.h>
43 #include <kiconloader.h>
44 #include <klocale.h>
45 #include <kstringhandler.h>
46 #include <kmessagebox.h>
47 #include <kfiledialog.h>
48 #include <kprogress.h>
49 #include <kstandarddirs.h>
50 #include <kaboutdata.h>
51 #include <kwin.h>
52 #include <kaccel.h>
53 #include <kpassivepopup.h>
54 #include <kxmlguifactory.h>
55 #include <kcmdlineargs.h>
56 #include <kglobalaccel.h>
57 #include <kapplication.h>
58 #include <kkeydialog.h>
59 #include <dcopclient.h>
60 #include <kdebug.h>
61 #include <iostream>
62 #include "bnpview.h"
63 #include "basket.h"
64 #include "tools.h"
65 #include "settings.h"
66 #include "debugwindow.h"
67 #include "xmlwork.h"
68 #include "basketfactory.h"
69 #include "softwareimporters.h"
70 #include "colorpicker.h"
71 #include "regiongrabber.h"
72 #include "basketlistview.h"
73 #include "basketproperties.h"
74 #include "password.h"
75 #include "newbasketdialog.h"
76 #include "notedrag.h"
77 #include "formatimporter.h"
78 #include "basketstatusbar.h"
79 #include "backgroundmanager.h"
80 #include "noteedit.h" // To launch InlineEditors::initToolBars()
81 #include "archive.h"
82 #include "htmlexporter.h"
83 #include "crashhandler.h"
84 #include "likeback.h"
85 #include "backup.h"
86 #include "notefactory.h"
87 #include "notecontent.h"
89 /** class BNPView: */
91 const int BNPView::c_delayTooltipTime = 275;
93 BNPView::BNPView(QWidget *parent, const char *name, KXMLGUIClient *aGUIClient,
94 KActionCollection *actionCollection, BasketStatusBar *bar)
95 : DCOPObject("BasketIface"), QSplitter(Qt::Horizontal, parent, name), m_actLockBasket(0), m_actPassBasket(0),
96 m_loading(true), m_newBasketPopup(false), m_firstShow(true),
97 m_regionGrabber(0), m_passiveDroppedSelection(0), m_passivePopup(0), m_actionCollection(actionCollection),
98 m_guiClient(aGUIClient), m_statusbar(bar), m_tryHideTimer(0), m_hideTimer(0)
100 /* Settings */
101 Settings::loadConfig();
103 Global::bnpView = this;
105 // Needed when loading the baskets:
106 Global::globalAccel = new KGlobalAccel(this); // FIXME: might be null (KPart case)!
107 Global::backgroundManager = new BackgroundManager();
109 setupGlobalShortcuts();
110 initialize();
111 QTimer::singleShot(0, this, SLOT(lateInit()));
114 BNPView::~BNPView()
116 int treeWidth = Global::bnpView->sizes()[Settings::treeOnLeft() ? 0 : 1];
118 Settings::setBasketTreeWidth(treeWidth);
120 if (currentBasket() && currentBasket()->isDuringEdit())
121 currentBasket()->closeEditor();
123 Settings::saveConfig();
125 Global::bnpView = 0;
127 delete Global::systemTray;
128 Global::systemTray = 0;
129 delete m_colorPicker;
130 delete m_statusbar;
132 NoteDrag::createAndEmptyCuttingTmpFolder(); // Clean the temporary folder we used
135 void BNPView::lateInit()
138 InlineEditors* instance = InlineEditors::instance();
140 if(instance)
142 KToolBar* toolbar = instance->richTextToolBar();
144 if(toolbar)
145 toolbar->hide();
148 if(!isPart())
150 if (Settings::useSystray() && KCmdLineArgs::parsedArgs() && KCmdLineArgs::parsedArgs()->isSet("start-hidden"))
151 if(Global::mainWindow()) Global::mainWindow()->hide();
152 else if (Settings::useSystray() && kapp->isRestored())
153 if(Global::mainWindow()) Global::mainWindow()->setShown(!Settings::startDocked());
154 else
155 showMainWindow();
158 // If the main window is hidden when session is saved, Container::queryClose()
159 // isn't called and the last value would be kept
160 Settings::setStartDocked(true);
161 Settings::saveConfig();
163 /* System tray icon */
164 Global::systemTray = new SystemTray(Global::mainWindow());
165 connect( Global::systemTray, SIGNAL(showPart()), this, SIGNAL(showPart()) );
166 if (Settings::useSystray())
167 Global::systemTray->show();
169 // Load baskets
170 DEBUG_WIN << "Baskets are loaded from " + Global::basketsFolder();
172 NoteDrag::createAndEmptyCuttingTmpFolder(); // If last exec hasn't done it: clean the temporary folder we will use
173 Tag::loadTags(); // Tags should be ready before loading baskets, but tags need the mainContainer to be ready to create KActions!
174 load();
176 // If no basket has been found, try to import from an older version,
177 if (!firstListViewItem()) {
178 QDir dir;
179 dir.mkdir(Global::basketsFolder());
180 if (FormatImporter::shouldImportBaskets()) {
181 FormatImporter::importBaskets();
182 load();
184 if (!firstListViewItem()) {
185 // Create first basket:
186 BasketFactory::newBasket(/*icon=*/"", /*name=*/i18n("General"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
190 // Load the Welcome Baskets if it is the First Time:
191 if (!Settings::welcomeBasketsAdded()) {
192 addWelcomeBaskets();
193 Settings::setWelcomeBasketsAdded(true);
194 Settings::saveConfig();
197 m_tryHideTimer = new QTimer(this);
198 m_hideTimer = new QTimer(this);
199 connect( m_tryHideTimer, SIGNAL(timeout()), this, SLOT(timeoutTryHide()) );
200 connect( m_hideTimer, SIGNAL(timeout()), this, SLOT(timeoutHide()) );
202 // Preload every baskets for instant filtering:
203 /*StopWatch::start(100);
204 QListViewItemIterator it(m_tree);
205 while (it.current()) {
206 BasketListViewItem *item = ((BasketListViewItem*)it.current());
207 item->basket()->load();
208 kapp->processEvents();
209 ++it;
211 StopWatch::check(100);*/
214 void BNPView::addWelcomeBaskets()
216 // Possible paths where to find the welcome basket archive, trying the translated one, and falling back to the English one:
217 QStringList possiblePaths;
218 if (QString(KGlobal::locale()->encoding()) == QString("UTF-8")) { // Welcome baskets are encoded in UTF-8. If the system is not, then use the English version:
219 possiblePaths.append(KGlobal::dirs()->findResource("data", "basket/welcome/Welcome_" + KGlobal::locale()->language() + ".baskets"));
220 possiblePaths.append(KGlobal::dirs()->findResource("data", "basket/welcome/Welcome_" + QStringList::split("_", KGlobal::locale()->language())[0] + ".baskets"));
222 possiblePaths.append(KGlobal::dirs()->findResource("data", "basket/welcome/Welcome_en_US.baskets"));
224 // Take the first EXISTING basket archive found:
225 QDir dir;
226 QString path;
227 for (QStringList::Iterator it = possiblePaths.begin(); it != possiblePaths.end(); ++it) {
228 if (dir.exists(*it)) {
229 path = *it;
230 break;
234 // Extract:
235 if (!path.isEmpty())
236 Archive::open(path);
239 void BNPView::onFirstShow()
241 // Don't enable LikeBack until bnpview is shown. This way it works better with kontact.
242 /* LikeBack */
243 /* Global::likeBack = new LikeBack(LikeBack::AllButtons, / *showBarByDefault=* /true, Global::config(), Global::about());
244 Global::likeBack->setServer("basket.linux62.org", "/likeback/send.php");
245 Global:likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Only english and french languages are accepted."));
246 if (isPart())
247 Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
250 if (isPart())
251 Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
254 LikeBack::init(Global::config(), Global::about(), LikeBack::AllButtons);
255 LikeBack::setServer("basket.linux62.org", "/likeback/send.php");
256 // LikeBack::setServer("localhost", "/~seb/basket/likeback/send.php");
257 LikeBack::setCustomLanguageMessage(i18n("Only english and french languages are accepted."));
258 // LikeBack::setWindowNamesListing(LikeBack:: / *NoListing* / / *WarnUnnamedWindows* / AllWindows);
261 // In late init, because we need kapp->mainWidget() to be set!
262 if (!isPart())
263 connectTagsMenu();
265 m_statusbar->setupStatusBar();
267 int treeWidth = Settings::basketTreeWidth();
268 if (treeWidth < 0)
269 treeWidth = m_tree->fontMetrics().maxWidth() * 11;
270 Q3ValueList<int> splitterSizes;
271 splitterSizes.append(treeWidth);
272 setSizes(splitterSizes);
275 void BNPView::setupGlobalShortcuts()
277 /* Global shortcuts */
278 KGlobalAccel *globalAccel = Global::globalAccel; // Better for the following lines
280 // Ctrl+Shift+W only works when started standalone:
281 QWidget *basketMainWindow = (QWidget*) (Global::bnpView->parent()->inherits("MainWindow") ? Global::bnpView->parent() : 0);
283 if (basketMainWindow) {
284 globalAccel->insert( "global_show_hide_main_window", i18n("Show/hide main window"),
285 i18n("Allows you to show main Window if it is hidden, and to hide it if it is shown."),
286 Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_W, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_W,
287 basketMainWindow, SLOT(changeActive()), true, true );
289 globalAccel->insert( "global_paste", i18n("Paste clipboard contents in current basket"),
290 i18n("Allows you to paste clipboard contents in the current basket without having to open the main window."),
291 Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_V, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_V,
292 Global::bnpView, SLOT(globalPasteInCurrentBasket()), true, true );
293 globalAccel->insert( "global_show_current_basket", i18n("Show current basket name"),
294 i18n("Allows you to know basket is current without opening the main window."),
295 "", "",
296 Global::bnpView, SLOT(showPassiveContentForced()), true, true );
297 globalAccel->insert( "global_paste_selection", i18n("Paste selection in current basket"),
298 i18n("Allows you to paste clipboard selection in the current basket without having to open the main window."),
299 Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_S, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_S,
300 Global::bnpView, SLOT(pasteSelInCurrentBasket()), true, true );
301 globalAccel->insert( "global_new_basket", i18n("Create a new basket"),
302 i18n("Allows you to create a new basket without having to open the main window (you then can use the other global shortcuts to add a note, paste clipboard or paste selection in this new basket)."),
303 "", "",
304 Global::bnpView, SLOT(askNewBasket()), true, true );
305 globalAccel->insert( "global_previous_basket", i18n("Go to previous basket"),
306 i18n("Allows you to change current basket to the previous one without having to open the main window."),
307 "", "",
308 Global::bnpView, SLOT(goToPreviousBasket()), true, true );
309 globalAccel->insert( "global_next_basket", i18n("Go to next basket"),
310 i18n("Allows you to change current basket to the next one without having to open the main window."),
311 "", "",
312 Global::bnpView, SLOT(goToNextBasket()), true, true );
313 // globalAccel->insert( "global_note_add_text", i18n("Insert plain text note"),
314 // i18n("Add a plain text note to the current basket without having to open the main window."),
315 // "", "", //Qt::CTRL+Qt::ALT+Qt::Key_T, Qt::CTRL+Qt::ALT+Qt::Key_T,
316 // Global::bnpView, SLOT(addNoteText()), true, true );
317 globalAccel->insert( "global_note_add_html", i18n("Insert text note"),
318 i18n("Add a text note to the current basket without having to open the main window."),
319 Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_T, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_T, //"", "",
320 Global::bnpView, SLOT(addNoteHtml()), true, true );
321 globalAccel->insert( "global_note_add_image", i18n("Insert image note"),
322 i18n("Add an image note to the current basket without having to open the main window."),
323 "", "",
324 Global::bnpView, SLOT(addNoteImage()), true, true );
325 globalAccel->insert( "global_note_add_link", i18n("Insert link note"),
326 i18n("Add a link note to the current basket without having to open the main window."),
327 "", "",
328 Global::bnpView, SLOT(addNoteLink()), true, true );
329 globalAccel->insert( "global_note_add_color", i18n("Insert color note"),
330 i18n("Add a color note to the current basket without having to open the main window."),
331 "", "",
332 Global::bnpView, SLOT(addNoteColor()), true, true );
333 globalAccel->insert( "global_note_pick_color", i18n("Pick color from screen"),
334 i18n("Add a color note picked from one pixel on screen to the current basket without "
335 "having to open the main window."),
336 "", "",
337 Global::bnpView, SLOT(slotColorFromScreenGlobal()), true, true );
338 globalAccel->insert( "global_note_grab_screenshot", i18n("Grab screen zone"),
339 i18n("Grab a screen zone as an image in the current basket without "
340 "having to open the main window."),
341 "", "",
342 Global::bnpView, SLOT(grabScreenshotGlobal()), true, true );
343 globalAccel->readSettings();
344 globalAccel->updateConnections();
347 void BNPView::initialize()
349 /// Configure the List View Columns:
350 m_tree = new BasketTreeListView(this);
351 m_tree->addColumn(i18n("Baskets"));
352 m_tree->setColumnWidthMode(0, Q3ListView::Maximum);
353 m_tree->setFullWidth(true);
354 m_tree->setSorting(-1/*Disabled*/);
355 m_tree->setRootIsDecorated(true);
356 m_tree->setTreeStepSize(16);
357 m_tree->setLineWidth(1);
358 m_tree->setMidLineWidth(0);
359 m_tree->setFocusPolicy(QWidget::NoFocus);
361 /// Configure the List View Drag and Drop:
362 m_tree->setDragEnabled(true);
363 m_tree->setAcceptDrops(true);
364 m_tree->setItemsMovable(true);
365 m_tree->setDragAutoScroll(true);
366 m_tree->setDropVisualizer(true);
367 m_tree->setDropHighlighter(true);
369 /// Configure the Splitter:
370 m_stack = new Q3WidgetStack(this);
372 setOpaqueResize(true);
374 setCollapsible(m_tree, true);
375 setCollapsible(m_stack, false);
376 setResizeMode(m_tree, QSplitter::KeepSize);
377 setResizeMode(m_stack, QSplitter::Stretch);
379 /// Configure the List View Signals:
380 connect( m_tree, SIGNAL(returnPressed(Q3ListViewItem*)), this, SLOT(slotPressed(Q3ListViewItem*)) );
381 connect( m_tree, SIGNAL(selectionChanged(Q3ListViewItem*)), this, SLOT(slotPressed(Q3ListViewItem*)) );
382 connect( m_tree, SIGNAL(pressed(Q3ListViewItem*)), this, SLOT(slotPressed(Q3ListViewItem*)) );
383 connect( m_tree, SIGNAL(expanded(Q3ListViewItem*)), this, SLOT(needSave(Q3ListViewItem*)) );
384 connect( m_tree, SIGNAL(collapsed(Q3ListViewItem*)), this, SLOT(needSave(Q3ListViewItem*)) );
385 connect( m_tree, SIGNAL(contextMenu(KListView*, Q3ListViewItem*, const QPoint&)), this, SLOT(slotContextMenu(KListView*, Q3ListViewItem*, const QPoint&)) );
386 connect( m_tree, SIGNAL(mouseButtonPressed(int, Q3ListViewItem*, const QPoint&, int)), this, SLOT(slotMouseButtonPressed(int, Q3ListViewItem*, const QPoint&, int)) );
387 connect( m_tree, SIGNAL(doubleClicked(Q3ListViewItem*, const QPoint&, int)), this, SLOT(slotShowProperties(Q3ListViewItem*, const QPoint&, int)) );
389 connect( m_tree, SIGNAL(expanded(Q3ListViewItem*)), this, SIGNAL(basketChanged()) );
390 connect( m_tree, SIGNAL(collapsed(Q3ListViewItem*)), this, SIGNAL(basketChanged()) );
391 connect( this, SIGNAL(basketNumberChanged(int)), this, SIGNAL(basketChanged()) );
393 connect( this, SIGNAL(basketNumberChanged(int)), this, SLOT(slotBasketNumberChanged(int)) );
394 connect( this, SIGNAL(basketChanged()), this, SLOT(slotBasketChanged()) );
396 /* LikeBack */
397 Global::likeBack = new LikeBack(LikeBack::AllButtons, /*showBarByDefault=*/false, Global::config(), Global::about());
398 Global::likeBack->setServer("basket.linux62.org", "/likeback/send.php");
400 // There are too much comments, and people reading comments are more and more international, so we accept only English:
401 // Global::likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Please write in English or French."));
403 // if (isPart())
404 // Global::likeBack->disableBar(); // See BNPView::shown() and BNPView::hide().
406 Global::likeBack->sendACommentAction(actionCollection()); // Just create it!
407 setupActions();
409 /// What's This Help for the tree:
410 Q3WhatsThis::add(m_tree, i18n(
411 "<h2>Basket Tree</h2>"
412 "Here is the list of your baskets. "
413 "You can organize your data by putting them in different baskets. "
414 "You can group baskets by subject by creating new baskets inside others. "
415 "You can browse between them by clicking a basket to open it, or reorganize them using drag and drop."));
417 setTreePlacement(Settings::treeOnLeft());
420 void BNPView::setupActions()
422 m_actSaveAsArchive = new KAction( i18n("&Basket Archive..."), "baskets", 0,
423 this, SLOT(saveAsArchive()), actionCollection(), "basket_export_basket_archive" );
424 m_actOpenArchive = new KAction( i18n("&Basket Archive..."), "baskets", 0,
425 this, SLOT(openArchive()), actionCollection(), "basket_import_basket_archive" );
427 m_actHideWindow = new KAction( i18n("&Hide Window"), "", KStdAccel::shortcut(KStdAccel::Close),
428 this, SLOT(hideOnEscape()), actionCollection(), "window_hide" );
429 m_actHideWindow->setEnabled(Settings::useSystray()); // Init here !
431 m_actExportToHtml = new KAction( i18n("&HTML Web Page..."), "html", 0,
432 this, SLOT(exportToHTML()), actionCollection(), "basket_export_html" );
433 new KAction( i18n("K&Notes"), "knotes", 0,
434 this, SLOT(importKNotes()), actionCollection(), "basket_import_knotes" );
435 new KAction( i18n("K&Jots"), "kjots", 0,
436 this, SLOT(importKJots()), actionCollection(), "basket_import_kjots" );
437 new KAction( i18n("&KnowIt..."), "knowit", 0,
438 this, SLOT(importKnowIt()), actionCollection(), "basket_import_knowit" );
439 new KAction( i18n("Tux&Cards..."), "tuxcards", 0,
440 this, SLOT(importTuxCards()), actionCollection(), "basket_import_tuxcards" );
441 new KAction( i18n("&Sticky Notes"), "gnome", 0,
442 this, SLOT(importStickyNotes()), actionCollection(), "basket_import_sticky_notes" );
443 new KAction( i18n("&Tomboy"), "tintin", 0,
444 this, SLOT(importTomboy()), actionCollection(), "basket_import_tomboy" );
445 new KAction( i18n("Text &File..."), "txt", 0,
446 this, SLOT(importTextFile()), actionCollection(), "basket_import_text_file" );
448 new KAction( i18n("&Backup && Restore..."), "", 0,
449 this, SLOT(backupRestore()), actionCollection(), "basket_backup_restore" );
451 /** Note : ****************************************************************/
453 m_actDelNote = new KAction( i18n("D&elete"), "editdelete", "Delete",
454 this, SLOT(delNote()), actionCollection(), "edit_delete" );
455 m_actCutNote = KStdAction::cut( this, SLOT(cutNote()), actionCollection() );
456 m_actCopyNote = KStdAction::copy( this, SLOT(copyNote()), actionCollection() );
458 m_actSelectAll = KStdAction::selectAll( this, SLOT( slotSelectAll() ), actionCollection() );
459 m_actSelectAll->setStatusText( i18n( "Selects all notes" ) );
460 m_actUnselectAll = new KAction( i18n( "U&nselect All" ), "", this, SLOT( slotUnselectAll() ),
461 actionCollection(), "edit_unselect_all" );
462 m_actUnselectAll->setStatusText( i18n( "Unselects all selected notes" ) );
463 m_actInvertSelection = new KAction( i18n( "&Invert Selection" ), CTRL+Key_Asterisk,
464 this, SLOT( slotInvertSelection() ),
465 actionCollection(), "edit_invert_selection" );
466 m_actInvertSelection->setStatusText( i18n( "Inverts the current selection of notes" ) );
468 m_actEditNote = new KAction( i18n("Verb; not Menu", "&Edit..."), "edit", "Return",
469 this, SLOT(editNote()), actionCollection(), "note_edit" );
471 m_actOpenNote = KStdAction::open( this, SLOT(openNote()), actionCollection(), "note_open" );
472 m_actOpenNote->setIcon("window_new");
473 m_actOpenNote->setText(i18n("&Open"));
474 m_actOpenNote->setShortcut("F9");
476 m_actOpenNoteWith = new KAction( i18n("Open &With..."), "", "Shift+F9",
477 this, SLOT(openNoteWith()), actionCollection(), "note_open_with" );
478 m_actSaveNoteAs = KStdAction::saveAs( this, SLOT(saveNoteAs()), actionCollection(), "note_save_to_file" );
479 m_actSaveNoteAs->setIcon("");
480 m_actSaveNoteAs->setText(i18n("&Save to File..."));
481 m_actSaveNoteAs->setShortcut("F10");
483 m_actGroup = new KAction( i18n("&Group"), "attach", "Ctrl+G",
484 this, SLOT(noteGroup()), actionCollection(), "note_group" );
485 m_actUngroup = new KAction( i18n("U&ngroup"), "", "Ctrl+Shift+G",
486 this, SLOT(noteUngroup()), actionCollection(), "note_ungroup" );
488 m_actMoveOnTop = new KAction( i18n("Move on &Top"), "2uparrow", "Ctrl+Shift+Home",
489 this, SLOT(moveOnTop()), actionCollection(), "note_move_top" );
490 m_actMoveNoteUp = new KAction( i18n("Move &Up"), "1uparrow", "Ctrl+Shift+Up",
491 this, SLOT(moveNoteUp()), actionCollection(), "note_move_up" );
492 m_actMoveNoteDown = new KAction( i18n("Move &Down"), "1downarrow", "Ctrl+Shift+Down",
493 this, SLOT(moveNoteDown()), actionCollection(), "note_move_down" );
494 m_actMoveOnBottom = new KAction( i18n("Move on &Bottom"), "2downarrow", "Ctrl+Shift+End",
495 this, SLOT(moveOnBottom()), actionCollection(), "note_move_bottom" );
496 #if KDE_IS_VERSION( 3, 1, 90 ) // KDE 3.2.x
497 m_actPaste = KStdAction::pasteText( this, SLOT(pasteInCurrentBasket()), actionCollection() );
498 #else
499 m_actPaste = KStdAction::paste( this, SLOT(pasteInCurrentBasket()), actionCollection() );
500 #endif
502 /** Insert : **************************************************************/
504 QSignalMapper *insertEmptyMapper = new QSignalMapper(this);
505 QSignalMapper *insertWizardMapper = new QSignalMapper(this);
506 connect( insertEmptyMapper, SIGNAL(mapped(int)), this, SLOT(insertEmpty(int)) );
507 connect( insertWizardMapper, SIGNAL(mapped(int)), this, SLOT(insertWizard(int)) );
509 // m_actInsertText = new KAction( i18n("Plai&n Text"), "text", "Ctrl+T", actionCollection(), "insert_text" );
510 m_actInsertHtml = new KAction( i18n("&Text"), "html", "Insert", actionCollection(), "insert_html" );
511 m_actInsertLink = new KAction( i18n("&Link"), "link", "Ctrl+Y", actionCollection(), "insert_link" );
512 m_actInsertImage = new KAction( i18n("&Image"), "image", "", actionCollection(), "insert_image" );
513 m_actInsertColor = new KAction( i18n("&Color"), "colorset", "", actionCollection(), "insert_color" );
514 m_actInsertLauncher=new KAction( i18n("L&auncher"), "launch", "", actionCollection(), "insert_launcher" );
516 m_actImportKMenu = new KAction( i18n("Import Launcher from &KDE Menu..."), "kmenu", "", actionCollection(), "insert_kmenu" );
517 m_actImportIcon = new KAction( i18n("Im&port Icon..."), "icons", "", actionCollection(), "insert_icon" );
518 m_actLoadFile = new KAction( i18n("Load From &File..."), "fileimport", "", actionCollection(), "insert_from_file" );
520 // connect( m_actInsertText, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
521 connect( m_actInsertHtml, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
522 connect( m_actInsertImage, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
523 connect( m_actInsertLink, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
524 connect( m_actInsertColor, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
525 connect( m_actInsertLauncher, SIGNAL(activated()), insertEmptyMapper, SLOT(map()) );
526 // insertEmptyMapper->setMapping(m_actInsertText, NoteType::Text );
527 insertEmptyMapper->setMapping(m_actInsertHtml, NoteType::Html );
528 insertEmptyMapper->setMapping(m_actInsertImage, NoteType::Image );
529 insertEmptyMapper->setMapping(m_actInsertLink, NoteType::Link );
530 insertEmptyMapper->setMapping(m_actInsertColor, NoteType::Color );
531 insertEmptyMapper->setMapping(m_actInsertLauncher, NoteType::Launcher);
533 connect( m_actImportKMenu, SIGNAL(activated()), insertWizardMapper, SLOT(map()) );
534 connect( m_actImportIcon, SIGNAL(activated()), insertWizardMapper, SLOT(map()) );
535 connect( m_actLoadFile, SIGNAL(activated()), insertWizardMapper, SLOT(map()) );
536 insertWizardMapper->setMapping(m_actImportKMenu, 1 );
537 insertWizardMapper->setMapping(m_actImportIcon, 2 );
538 insertWizardMapper->setMapping(m_actLoadFile, 3 );
540 m_colorPicker = new DesktopColorPicker();
541 m_actColorPicker = new KAction( i18n("C&olor from Screen"), "kcolorchooser", "",
542 this, SLOT(slotColorFromScreen()), actionCollection(), "insert_screen_color" );
543 connect( m_colorPicker, SIGNAL(pickedColor(const QColor&)), this, SLOT(colorPicked(const QColor&)) );
544 connect( m_colorPicker, SIGNAL(canceledPick()), this, SLOT(colorPickingCanceled()) );
546 m_actGrabScreenshot = new KAction( i18n("Grab Screen &Zone"), "ksnapshot", "",
547 this, SLOT(grabScreenshot()), actionCollection(), "insert_screen_capture" );
548 //connect( m_actGrabScreenshot, SIGNAL(regionGrabbed(const QPixmap&)), this, SLOT(screenshotGrabbed(const QPixmap&)) );
549 //connect( m_colorPicker, SIGNAL(canceledPick()), this, SLOT(colorPickingCanceled()) );
551 // m_insertActions.append( m_actInsertText );
552 m_insertActions.append( m_actInsertHtml );
553 m_insertActions.append( m_actInsertLink );
554 m_insertActions.append( m_actInsertImage );
555 m_insertActions.append( m_actInsertColor );
556 m_insertActions.append( m_actImportKMenu );
557 m_insertActions.append( m_actInsertLauncher );
558 m_insertActions.append( m_actImportIcon );
559 m_insertActions.append( m_actLoadFile );
560 m_insertActions.append( m_actColorPicker );
561 m_insertActions.append( m_actGrabScreenshot );
563 /** Basket : **************************************************************/
565 // At this stage, main.cpp has not set kapp->mainWidget(), so Global::runInsideKontact()
566 // returns true. We do it ourself:
567 bool runInsideKontact = true;
568 QWidget *parentWidget = (QWidget*) parent();
569 while (parentWidget) {
570 if (parentWidget->inherits("MainWindow"))
571 runInsideKontact = false;
572 parentWidget = (QWidget*) parentWidget->parent();
575 // Use the "basket" incon in Kontact so it is consistent with the Kontact "New..." icon
576 actNewBasket = new KAction( i18n("&New Basket..."), (runInsideKontact ? "basket" : "filenew"), KStdAccel::shortcut(KStdAccel::New),
577 this, SLOT(askNewBasket()), actionCollection(), "basket_new" );
578 actNewSubBasket = new KAction( i18n("New &Sub-Basket..."), "", "Ctrl+Shift+N",
579 this, SLOT(askNewSubBasket()), actionCollection(), "basket_new_sub" );
580 actNewSiblingBasket = new KAction( i18n("New Si&bling Basket..."), "", "",
581 this, SLOT(askNewSiblingBasket()), actionCollection(), "basket_new_sibling" );
583 KActionMenu *newBasketMenu = new KActionMenu(i18n("&New"), "filenew", actionCollection(), "basket_new_menu");
584 newBasketMenu->insert(actNewBasket);
585 newBasketMenu->insert(actNewSubBasket);
586 newBasketMenu->insert(actNewSiblingBasket);
587 connect( newBasketMenu, SIGNAL(activated()), this, SLOT(askNewBasket()) );
589 m_actPropBasket = new KAction( i18n("&Properties..."), "misc", "F2",
590 this, SLOT(propBasket()), actionCollection(), "basket_properties" );
591 m_actDelBasket = new KAction( i18n("Remove Basket", "&Remove"), "", 0,
592 this, SLOT(delBasket()), actionCollection(), "basket_remove" );
593 #ifdef HAVE_LIBGPGME
594 m_actPassBasket = new KAction( i18n("Password protection", "Pass&word..."), "", 0,
595 this, SLOT(password()), actionCollection(), "basket_password" );
596 m_actLockBasket = new KAction( i18n("Lock Basket", "&Lock"), "", "Ctrl+L",
597 this, SLOT(lockBasket()), actionCollection(), "basket_lock" );
598 #endif
599 /** Edit : ****************************************************************/
601 //m_actUndo = KStdAction::undo( this, SLOT(undo()), actionCollection() );
602 //m_actUndo->setEnabled(false); // Not yet implemented !
603 //m_actRedo = KStdAction::redo( this, SLOT(redo()), actionCollection() );
604 //m_actRedo->setEnabled(false); // Not yet implemented !
606 m_actShowFilter = new KToggleAction( i18n("&Filter"), "filter", KStdAccel::shortcut(KStdAccel::Find),
607 actionCollection(), "edit_filter" );
608 connect( m_actShowFilter, SIGNAL(toggled(bool)), this, SLOT(showHideFilterBar(bool)) );
610 m_actFilterAllBaskets = new KToggleAction( i18n("Filter all &Baskets"), "find", "Ctrl+Shift+F",
611 actionCollection(), "edit_filter_all_baskets" );
612 connect( m_actFilterAllBaskets, SIGNAL(toggled(bool)), this, SLOT(toggleFilterAllBaskets(bool)) );
614 m_actResetFilter = new KAction( i18n( "&Reset Filter" ), "locationbar_erase", "Ctrl+R",
615 this, SLOT( slotResetFilter() ), actionCollection(), "edit_filter_reset" );
617 /** Go : ******************************************************************/
619 m_actPreviousBasket = new KAction( i18n( "&Previous Basket" ), "up", "Alt+Up",
620 this, SLOT(goToPreviousBasket()), actionCollection(), "go_basket_previous" );
621 m_actNextBasket = new KAction( i18n( "&Next Basket" ), "down", "Alt+Down",
622 this, SLOT(goToNextBasket()), actionCollection(), "go_basket_next" );
623 m_actFoldBasket = new KAction( i18n( "&Fold Basket" ), "back", "Alt+Left",
624 this, SLOT(foldBasket()), actionCollection(), "go_basket_fold" );
625 m_actExpandBasket = new KAction( i18n( "&Expand Basket" ), "forward", "Alt+Right",
626 this, SLOT(expandBasket()), actionCollection(), "go_basket_expand" );
627 // FOR_BETA_PURPOSE:
628 // m_convertTexts = new KAction( i18n("Convert text notes to rich text notes"), "compfile", "",
629 // this, SLOT(convertTexts()), actionCollection(), "beta_convert_texts" );
631 InlineEditors::instance()->initToolBars(actionCollection());
633 actConfigGlobalShortcuts = KStdAction::keyBindings(this, SLOT(showGlobalShortcutsSettingsDialog()),
634 actionCollection(), "options_configure_global_keybinding");
635 actConfigGlobalShortcuts->setText(i18n("Configure &Global Shortcuts..."));
637 /** Help : ****************************************************************/
639 new KAction( i18n("&Welcome Baskets"), "", "", this, SLOT(addWelcomeBaskets()), actionCollection(), "help_welcome_baskets" );
642 Q3ListViewItem* BNPView::firstListViewItem()
644 return m_tree->firstChild();
647 void BNPView::slotShowProperties(Q3ListViewItem *item, const QPoint&, int)
649 if (item)
650 propBasket();
653 void BNPView::slotMouseButtonPressed(int button, Q3ListViewItem *item, const QPoint &/*pos*/, int /*column*/)
655 if (item && (button & Qt::MidButton)) {
656 // TODO: Paste into ((BasketListViewItem*)listViewItem)->basket()
660 void BNPView::slotContextMenu(KListView */*listView*/, Q3ListViewItem *item, const QPoint &pos)
662 QString menuName;
663 if (item) {
664 Basket* basket = ((BasketListViewItem*)item)->basket();
666 setCurrentBasket(basket);
667 menuName = "basket_popup";
668 } else {
669 menuName = "tab_bar_popup";
671 * "File -> New" create a new basket with the same parent basket as the the current one.
672 * But when invoked when right-clicking the empty area at the bottom of the basket tree,
673 * it is obvious the user want to create a new basket at the bottom of the tree (with no parent).
674 * So we set a temporary variable during the time the popup menu is shown,
675 * so the slot askNewBasket() will do the right thing:
677 setNewBasketPopup();
680 Q3PopupMenu *menu = popupMenu(menuName);
681 connect( menu, SIGNAL(aboutToHide()), this, SLOT(aboutToHideNewBasketPopup()) );
682 menu->exec(pos);
685 void BNPView::save()
687 DEBUG_WIN << "Basket Tree: Saving...";
689 // Create Document:
690 QDomDocument document("basketTree");
691 QDomElement root = document.createElement("basketTree");
692 document.appendChild(root);
694 // Save Basket Tree:
695 save(m_tree->firstChild(), document, root);
697 // Write to Disk:
698 Basket::safelySaveToFile(Global::basketsFolder() + "baskets.xml", "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString());
699 // QFile file(Global::basketsFolder() + "baskets.xml");
700 // if (file.open(IO_WriteOnly)) {
701 // QTextStream stream(&file);
702 // stream.setEncoding(QTextStream::UnicodeUTF8);
703 // QString xml = document.toString();
704 // stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
705 // stream << xml;
706 // file.close();
707 // }
710 void BNPView::save(Q3ListViewItem *firstItem, QDomDocument &document, QDomElement &parentElement)
712 Q3ListViewItem *item = firstItem;
713 while (item) {
714 // Basket *basket = ((BasketListViewItem*)item)->basket();
715 QDomElement basketElement = this->basketElement(item, document, parentElement);
717 QDomElement basketElement = document.createElement("basket");
718 parentElement.appendChild(basketElement);
719 // Save Attributes:
720 basketElement.setAttribute("folderName", basket->folderName());
721 if (item->firstChild()) // If it can be expanded/folded:
722 basketElement.setAttribute("folded", XMLWork::trueOrFalse(!item->isOpen()));
723 if (((BasketListViewItem*)item)->isCurrentBasket())
724 basketElement.setAttribute("lastOpened", "true");
725 // Save Properties:
726 QDomElement properties = document.createElement("properties");
727 basketElement.appendChild(properties);
728 basket->saveProperties(document, properties);
730 // Save Child Basket:
731 if (item->firstChild())
732 save(item->firstChild(), document, basketElement);
733 // Next Basket:
734 item = item->nextSibling();
738 QDomElement BNPView::basketElement(Q3ListViewItem *item, QDomDocument &document, QDomElement &parentElement)
740 Basket *basket = ((BasketListViewItem*)item)->basket();
741 QDomElement basketElement = document.createElement("basket");
742 parentElement.appendChild(basketElement);
743 // Save Attributes:
744 basketElement.setAttribute("folderName", basket->folderName());
745 if (item->firstChild()) // If it can be expanded/folded:
746 basketElement.setAttribute("folded", XMLWork::trueOrFalse(!item->isOpen()));
747 if (((BasketListViewItem*)item)->isCurrentBasket())
748 basketElement.setAttribute("lastOpened", "true");
749 // Save Properties:
750 QDomElement properties = document.createElement("properties");
751 basketElement.appendChild(properties);
752 basket->saveProperties(document, properties);
753 return basketElement;
756 void BNPView::saveSubHierarchy(Q3ListViewItem *item, QDomDocument &document, QDomElement &parentElement, bool recursive)
758 QDomElement element = basketElement(item, document, parentElement);
759 if (recursive && item->firstChild())
760 save(item->firstChild(), document, element);
763 void BNPView::load()
765 QDomDocument *doc = XMLWork::openFile("basketTree", Global::basketsFolder() + "baskets.xml");
766 //BEGIN Compatibility with 0.6.0 Pre-Alpha versions:
767 if (!doc)
768 doc = XMLWork::openFile("basketsTree", Global::basketsFolder() + "baskets.xml");
769 //END
770 if (doc != 0) {
771 QDomElement docElem = doc->documentElement();
772 load(m_tree, 0L, docElem);
774 m_loading = false;
777 void BNPView::load(KListView */*listView*/, Q3ListViewItem *item, const QDomElement &baskets)
779 QDomNode n = baskets.firstChild();
780 while ( ! n.isNull() ) {
781 QDomElement element = n.toElement();
782 if ( (!element.isNull()) && element.tagName() == "basket" ) {
783 QString folderName = element.attribute("folderName");
784 if (!folderName.isEmpty()) {
785 Basket *basket = loadBasket(folderName);
786 BasketListViewItem *basketItem = appendBasket(basket, item);
787 basketItem->setOpen(!XMLWork::trueOrFalse(element.attribute("folded", "false"), false));
788 basket->loadProperties(XMLWork::getElement(element, "properties"));
789 if (XMLWork::trueOrFalse(element.attribute("lastOpened", element.attribute("lastOpenned", "false")), false)) // Compat with 0.6.0-Alphas
790 setCurrentBasket(basket);
791 // Load Sub-baskets:
792 load(/*(QListView*)*/0L, basketItem, element);
795 n = n.nextSibling();
799 Basket* BNPView::loadBasket(const QString &folderName)
801 if (folderName.isEmpty())
802 return 0;
804 DecoratedBasket *decoBasket = new DecoratedBasket(m_stack, folderName);
805 Basket *basket = decoBasket->basket();
806 m_stack->addWidget(decoBasket);
807 connect( basket, SIGNAL(countsChanged(Basket*)), this, SLOT(countsChanged(Basket*)) );
808 // Important: Create listViewItem and connect signal BEFORE loadProperties(), so we get the listViewItem updated without extra work:
809 connect( basket, SIGNAL(propertiesChanged(Basket*)), this, SLOT(updateBasketListViewItem(Basket*)) );
811 connect( basket->decoration()->filterBar(), SIGNAL(newFilter(const FilterData&)), this, SLOT(newFilterFromFilterBar()) );
813 return basket;
816 int BNPView::basketCount(Q3ListViewItem *parent)
818 int count = 0;
820 Q3ListViewItem *item = (parent ? parent->firstChild() : m_tree->firstChild());
821 while (item) {
822 count += 1 + basketCount(item);
823 item = item->nextSibling();
826 return count;
829 bool BNPView::canFold()
831 BasketListViewItem *item = listViewItemForBasket(currentBasket());
832 if (!item)
833 return false;
834 return item->parent() || (item->firstChild() && item->isOpen());
837 bool BNPView::canExpand()
839 BasketListViewItem *item = listViewItemForBasket(currentBasket());
840 if (!item)
841 return false;
842 return item->firstChild();
845 BasketListViewItem* BNPView::appendBasket(Basket *basket, Q3ListViewItem *parentItem)
847 BasketListViewItem *newBasketItem;
848 if (parentItem)
849 newBasketItem = new BasketListViewItem(parentItem, ((BasketListViewItem*)parentItem)->lastChild(), basket);
850 else {
851 Q3ListViewItem *child = m_tree->firstChild();
852 Q3ListViewItem *lastChild = 0;
853 while (child) {
854 lastChild = child;
855 child = child->nextSibling();
857 newBasketItem = new BasketListViewItem(m_tree, lastChild, basket);
860 emit basketNumberChanged(basketCount());
862 return newBasketItem;
865 void BNPView::loadNewBasket(const QString &folderName, const QDomElement &properties, Basket *parent)
867 Basket *basket = loadBasket(folderName);
868 appendBasket(basket, (basket ? listViewItemForBasket(parent) : 0));
869 basket->loadProperties(properties);
870 setCurrentBasket(basket);
871 // save();
874 BasketListViewItem* BNPView::lastListViewItem()
876 Q3ListViewItem *child = m_tree->firstChild();
877 Q3ListViewItem *lastChild = 0;
878 // Set lastChild to the last primary child of the list view:
879 while (child) {
880 lastChild = child;
881 child = child->nextSibling();
883 // If this child have child(s), recursivly browse through them to find the real last one:
884 while (lastChild && lastChild->firstChild()) {
885 child = lastChild->firstChild();
886 while (child) {
887 lastChild = child;
888 child = child->nextSibling();
891 return (BasketListViewItem*)lastChild;
894 void BNPView::goToPreviousBasket()
896 if (!m_tree->firstChild())
897 return;
899 BasketListViewItem *item = listViewItemForBasket(currentBasket());
900 BasketListViewItem *toSwitch = item->shownItemAbove();
901 if (!toSwitch) {
902 toSwitch = lastListViewItem();
903 if (toSwitch && !toSwitch->isShown())
904 toSwitch = toSwitch->shownItemAbove();
907 if (toSwitch)
908 setCurrentBasket(toSwitch->basket());
910 if (Settings::usePassivePopup())
911 showPassiveContent();
914 void BNPView::goToNextBasket()
916 if (!m_tree->firstChild())
917 return;
919 BasketListViewItem *item = listViewItemForBasket(currentBasket());
920 BasketListViewItem *toSwitch = item->shownItemBelow();
921 if (!toSwitch)
922 toSwitch = ((BasketListViewItem*)m_tree->firstChild());
924 if (toSwitch)
925 setCurrentBasket(toSwitch->basket());
927 if (Settings::usePassivePopup())
928 showPassiveContent();
931 void BNPView::foldBasket()
933 BasketListViewItem *item = listViewItemForBasket(currentBasket());
934 if (item && !item->firstChild())
935 item->setOpen(false); // If Alt+Left is hitted and there is nothing to close, make sure the focus will go to the parent basket
937 QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Left, 0, 0);
938 QApplication::postEvent(m_tree, keyEvent);
941 void BNPView::expandBasket()
943 QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Right, 0, 0);
944 QApplication::postEvent(m_tree, keyEvent);
947 void BNPView::closeAllEditors()
949 Q3ListViewItemIterator it(m_tree);
950 while (it.current()) {
951 BasketListViewItem *item = (BasketListViewItem*)(it.current());
952 item->basket()->closeEditor();
953 ++it;
957 bool BNPView::convertTexts()
959 bool convertedNotes = false;
960 KProgressDialog dialog(
961 /*parent=*/0,
962 /*name=*/"",
963 /*caption=*/i18n("Plain Text Notes Conversion"),
964 /*text=*/i18n("Converting plain text notes to rich text ones..."),
965 /*modal=*/true);
966 dialog.progressBar()->setTotalSteps(basketCount());
967 dialog.show(); //setMinimumDuration(50/*ms*/);
969 Q3ListViewItemIterator it(m_tree);
970 while (it.current()) {
971 BasketListViewItem *item = (BasketListViewItem*)(it.current());
972 if (item->basket()->convertTexts())
973 convertedNotes = true;
974 dialog.progressBar()->advance(1);
975 if (dialog.wasCancelled())
976 break;
977 ++it;
980 return convertedNotes;
983 /** isRunning is to avoid recursive calls because this method can be called
984 * when clicking the menu action or when using the filter-bar icon... either of those calls
985 * call the other to be checked... and it can cause recursive calls.
986 * PS: Uggly hack? Yes, I think so :-)
988 void BNPView::toggleFilterAllBaskets(bool doFilter)
990 static bool isRunning = false;
991 if (isRunning)
992 return;
993 isRunning = true;
995 // Set the state:
996 m_actFilterAllBaskets->setChecked(doFilter);
997 //currentBasket()->decoration()->filterBar()->setFilterAll(doFilter);
999 // Basket *current = currentBasket();
1000 Q3ListViewItemIterator it(m_tree);
1001 while (it.current()) {
1002 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1003 item->basket()->decoration()->filterBar()->setFilterAll(doFilter);
1004 ++it;
1007 // Protection is not necessary anymore:
1008 isRunning = false;
1010 if (doFilter)
1011 currentBasket()->decoration()->filterBar()->setEditFocus();
1013 // Filter every baskets:
1014 newFilter();
1017 /** This function can be called recursively because we call kapp->processEvents().
1018 * If this function is called whereas another "instance" is running,
1019 * this new "instance" leave and set up a flag that is read by the first "instance"
1020 * to know it should re-begin the work.
1021 * PS: Yes, that's a very lame pseudo-threading but that works, and it's programmer-efforts cheap :-)
1023 void BNPView::newFilter()
1025 static bool alreadyEntered = false;
1026 static bool shouldRestart = false;
1028 if (alreadyEntered) {
1029 shouldRestart = true;
1030 return;
1032 alreadyEntered = true;
1033 shouldRestart = false;
1035 Basket *current = currentBasket();
1036 const FilterData &filterData = current->decoration()->filterBar()->filterData();
1038 // Set the filter data for every other baskets, or reset the filter for every other baskets if we just disabled the filterInAllBaskets:
1039 Q3ListViewItemIterator it(m_tree);
1040 while (it.current()) {
1041 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1042 if (item->basket() != current)
1043 if (isFilteringAllBaskets())
1044 item->basket()->decoration()->filterBar()->setFilterData(filterData); // Set the new FilterData for every other baskets
1045 else
1046 item->basket()->decoration()->filterBar()->setFilterData(FilterData()); // We just disabled the global filtering: remove the FilterData
1047 ++it;
1050 // Show/hide the "little filter icons" (during basket load)
1051 // or the "little numbers" (to show number of found notes in the baskets) is the tree:
1052 m_tree->triggerUpdate();
1053 kapp->processEvents();
1055 // Load every baskets for filtering, if they are not already loaded, and if necessary:
1056 if (filterData.isFiltering) {
1057 Basket *current = currentBasket();
1058 Q3ListViewItemIterator it(m_tree);
1059 while (it.current()) {
1060 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1061 if (item->basket() != current) {
1062 Basket *basket = item->basket();
1063 if (!basket->loadingLaunched() && !basket->isLocked())
1064 basket->load();
1065 basket->filterAgain();
1066 m_tree->triggerUpdate();
1067 kapp->processEvents();
1068 if (shouldRestart) {
1069 alreadyEntered = false;
1070 shouldRestart = false;
1071 newFilter();
1072 return;
1075 ++it;
1079 m_tree->triggerUpdate();
1080 // kapp->processEvents();
1082 alreadyEntered = false;
1083 shouldRestart = false;
1086 void BNPView::newFilterFromFilterBar()
1088 if (isFilteringAllBaskets())
1089 QTimer::singleShot(0, this, SLOT(newFilter())); // Keep time for the QLineEdit to display the filtered character and refresh correctly!
1092 bool BNPView::isFilteringAllBaskets()
1094 return m_actFilterAllBaskets->isChecked();
1098 BasketListViewItem* BNPView::listViewItemForBasket(Basket *basket)
1100 Q3ListViewItemIterator it(m_tree);
1101 while (it.current()) {
1102 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1103 if (item->basket() == basket)
1104 return item;
1105 ++it;
1107 return 0L;
1110 Basket* BNPView::currentBasket()
1112 DecoratedBasket *decoBasket = (DecoratedBasket*)m_stack->visibleWidget();
1113 if (decoBasket)
1114 return decoBasket->basket();
1115 else
1116 return 0;
1119 Basket* BNPView::parentBasketOf(Basket *basket)
1121 BasketListViewItem *item = (BasketListViewItem*)(listViewItemForBasket(basket)->parent());
1122 if (item)
1123 return item->basket();
1124 else
1125 return 0;
1128 void BNPView::setCurrentBasket(Basket *basket)
1130 if (currentBasket() == basket)
1131 return;
1133 if (currentBasket())
1134 currentBasket()->closeBasket();
1136 if (basket)
1137 basket->aboutToBeActivated();
1139 BasketListViewItem *item = listViewItemForBasket(basket);
1140 if (item) {
1141 m_tree->setSelected(item, true);
1142 item->ensureVisible();
1143 m_stack->raiseWidget(basket->decoration());
1144 // If the window has changed size, only the current basket receive the event,
1145 // the others will receive ony one just before they are shown.
1146 // But this triggers unwanted animations, so we eliminate it:
1147 basket->relayoutNotes(/*animate=*/false);
1148 basket->openBasket();
1149 setCaption(item->basket()->basketName());
1150 countsChanged(basket);
1151 updateStatusBarHint();
1152 if (Global::systemTray)
1153 Global::systemTray->updateToolTip();
1154 m_tree->ensureItemVisible(m_tree->currentItem());
1155 item->basket()->setFocus();
1157 m_tree->viewport()->update();
1158 emit basketChanged();
1161 void BNPView::removeBasket(Basket *basket)
1163 if (basket->isDuringEdit())
1164 basket->closeEditor();
1166 // Find a new basket to switch to and select it.
1167 // Strategy: get the next sibling, or the previous one if not found.
1168 // If there is no such one, get the parent basket:
1169 BasketListViewItem *basketItem = listViewItemForBasket(basket);
1170 BasketListViewItem *nextBasketItem = (BasketListViewItem*)(basketItem->nextSibling());
1171 if (!nextBasketItem)
1172 nextBasketItem = basketItem->prevSibling();
1173 if (!nextBasketItem)
1174 nextBasketItem = (BasketListViewItem*)(basketItem->parent());
1176 if (nextBasketItem)
1177 setCurrentBasket(nextBasketItem->basket());
1179 // Remove from the view:
1180 basket->unsubscribeBackgroundImages();
1181 m_stack->removeWidget(basket->decoration());
1182 // delete basket->decoration();
1183 delete basketItem;
1184 // delete basket;
1186 // If there is no basket anymore, add a new one:
1187 if (!nextBasketItem)
1188 BasketFactory::newBasket(/*icon=*/"", /*name=*/i18n("General"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
1189 else // No need to save two times if we add a basket
1190 save();
1192 emit basketNumberChanged(basketCount());
1195 void BNPView::setTreePlacement(bool onLeft)
1197 if (onLeft)
1198 moveToFirst(m_tree);
1199 else
1200 moveToLast(m_tree);
1201 //updateGeometry();
1202 kapp->postEvent( this, new QResizeEvent(size(), size()) );
1205 void BNPView::relayoutAllBaskets()
1207 Q3ListViewItemIterator it(m_tree);
1208 while (it.current()) {
1209 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1210 //item->basket()->unbufferizeAll();
1211 item->basket()->unsetNotesWidth();
1212 item->basket()->relayoutNotes(true);
1213 ++it;
1217 void BNPView::recomputeAllStyles()
1219 Q3ListViewItemIterator it(m_tree);
1220 while (it.current()) {
1221 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1222 item->basket()->recomputeAllStyles();
1223 item->basket()->unsetNotesWidth();
1224 item->basket()->relayoutNotes(true);
1225 ++it;
1229 void BNPView::removedStates(const Q3ValueList<State*> &deletedStates)
1231 Q3ListViewItemIterator it(m_tree);
1232 while (it.current()) {
1233 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1234 item->basket()->removedStates(deletedStates);
1235 ++it;
1239 void BNPView::linkLookChanged()
1241 Q3ListViewItemIterator it(m_tree);
1242 while (it.current()) {
1243 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1244 item->basket()->linkLookChanged();
1245 ++it;
1249 void BNPView::filterPlacementChanged(bool onTop)
1251 Q3ListViewItemIterator it(m_tree);
1252 while (it.current()) {
1253 BasketListViewItem *item = static_cast<BasketListViewItem*>(it.current());
1254 DecoratedBasket *decoration = static_cast<DecoratedBasket*>(item->basket()->parent());
1255 decoration->setFilterBarPosition(onTop);
1256 ++it;
1260 void BNPView::updateBasketListViewItem(Basket *basket)
1262 BasketListViewItem *item = listViewItemForBasket(basket);
1263 if (item)
1264 item->setup();
1266 if (basket == currentBasket()) {
1267 setCaption(basket->basketName());
1268 if (Global::systemTray)
1269 Global::systemTray->updateToolTip();
1272 // Don't save if we are loading!
1273 if (!m_loading)
1274 save();
1277 void BNPView::needSave(Q3ListViewItem*)
1279 if (!m_loading)
1280 // A basket has been collapsed/expanded or a new one is select: this is not urgent:
1281 QTimer::singleShot(500/*ms*/, this, SLOT(save()));
1284 void BNPView::slotPressed(Q3ListViewItem *item, const QPoint &/*pos*/, int /*column*/)
1286 Basket *basket = currentBasket();
1287 if (basket == 0)
1288 return;
1290 // Impossible to Select no Basket:
1291 if (!item)
1292 m_tree->setSelected(listViewItemForBasket(basket), true);
1293 else if (dynamic_cast<BasketListViewItem*>(item) != 0 && currentBasket() != ((BasketListViewItem*)item)->basket()) {
1294 setCurrentBasket( ((BasketListViewItem*)item)->basket() );
1295 needSave(0);
1297 basket->setFocus();
1300 DecoratedBasket* BNPView::currentDecoratedBasket()
1302 if (currentBasket())
1303 return currentBasket()->decoration();
1304 else
1305 return 0;
1308 // Redirected actions :
1310 void BNPView::exportToHTML() { HTMLExporter exporter(currentBasket()); }
1311 void BNPView::editNote() { currentBasket()->noteEdit(); }
1312 void BNPView::cutNote() { currentBasket()->noteCut(); }
1313 void BNPView::copyNote() { currentBasket()->noteCopy(); }
1314 void BNPView::delNote() { currentBasket()->noteDelete(); }
1315 void BNPView::openNote() { currentBasket()->noteOpen(); }
1316 void BNPView::openNoteWith() { currentBasket()->noteOpenWith(); }
1317 void BNPView::saveNoteAs() { currentBasket()->noteSaveAs(); }
1318 void BNPView::noteGroup() { currentBasket()->noteGroup(); }
1319 void BNPView::noteUngroup() { currentBasket()->noteUngroup(); }
1320 void BNPView::moveOnTop() { currentBasket()->noteMoveOnTop(); }
1321 void BNPView::moveOnBottom() { currentBasket()->noteMoveOnBottom(); }
1322 void BNPView::moveNoteUp() { currentBasket()->noteMoveNoteUp(); }
1323 void BNPView::moveNoteDown() { currentBasket()->noteMoveNoteDown(); }
1324 void BNPView::slotSelectAll() { currentBasket()->selectAll(); }
1325 void BNPView::slotUnselectAll() { currentBasket()->unselectAll(); }
1326 void BNPView::slotInvertSelection() { currentBasket()->invertSelection(); }
1327 void BNPView::slotResetFilter() { currentDecoratedBasket()->resetFilter(); }
1329 void BNPView::importKJots() { SoftwareImporters::importKJots(); }
1330 void BNPView::importKNotes() { SoftwareImporters::importKNotes(); }
1331 void BNPView::importKnowIt() { SoftwareImporters::importKnowIt(); }
1332 void BNPView::importTuxCards() { SoftwareImporters::importTuxCards(); }
1333 void BNPView::importStickyNotes() { SoftwareImporters::importStickyNotes(); }
1334 void BNPView::importTomboy() { SoftwareImporters::importTomboy(); }
1335 void BNPView::importTextFile() { SoftwareImporters::importTextFile(); }
1337 void BNPView::backupRestore()
1339 BackupDialog dialog;
1340 dialog.exec();
1343 void BNPView::countsChanged(Basket *basket)
1345 if (basket == currentBasket())
1346 notesStateChanged();
1349 void BNPView::notesStateChanged()
1351 Basket *basket = currentBasket();
1353 // Update statusbar message :
1354 if (currentBasket()->isLocked())
1355 setSelectionStatus(i18n("Locked"));
1356 else if (!basket->isLoaded())
1357 setSelectionStatus(i18n("Loading..."));
1358 else if (basket->count() == 0)
1359 setSelectionStatus(i18n("No notes"));
1360 else {
1361 QString count = i18n("%n note", "%n notes", basket->count() );
1362 QString selecteds = i18n("%n selected", "%n selected", basket->countSelecteds());
1363 QString showns = (currentDecoratedBasket()->filterData().isFiltering ? i18n("all matches") : i18n("no filter"));
1364 if (basket->countFounds() != basket->count())
1365 showns = i18n("%n match", "%n matches", basket->countFounds());
1366 setSelectionStatus(
1367 i18n("e.g. '18 notes, 10 matches, 5 selected'", "%1, %2, %3").arg(count, showns, selecteds) );
1370 // If we added a note that match the global filter, update the count number in the tree:
1371 if (isFilteringAllBaskets())
1372 listViewItemForBasket(basket)->listView()->triggerUpdate();
1374 if (currentBasket()->redirectEditActions()) {
1375 m_actSelectAll ->setEnabled( !currentBasket()->selectedAllTextInEditor() );
1376 m_actUnselectAll ->setEnabled( currentBasket()->hasSelectedTextInEditor() );
1377 } else {
1378 m_actSelectAll ->setEnabled( basket->countSelecteds() < basket->countFounds() );
1379 m_actUnselectAll ->setEnabled( basket->countSelecteds() > 0 );
1381 m_actInvertSelection ->setEnabled( basket->countFounds() > 0 );
1383 updateNotesActions();
1386 void BNPView::updateNotesActions()
1388 bool isLocked = currentBasket()->isLocked();
1389 bool oneSelected = currentBasket()->countSelecteds() == 1;
1390 bool oneOrSeveralSelected = currentBasket()->countSelecteds() >= 1;
1391 bool severalSelected = currentBasket()->countSelecteds() >= 2;
1393 // FIXME: m_actCheckNotes is also modified in void BNPView::areSelectedNotesCheckedChanged(bool checked)
1394 // bool Basket::areSelectedNotesChecked() should return false if bool Basket::showCheckBoxes() is false
1395 // m_actCheckNotes->setChecked( oneOrSeveralSelected &&
1396 // currentBasket()->areSelectedNotesChecked() &&
1397 // currentBasket()->showCheckBoxes() );
1399 Note *selectedGroup = (severalSelected ? currentBasket()->selectedGroup() : 0);
1401 m_actEditNote ->setEnabled( !isLocked && oneSelected && !currentBasket()->isDuringEdit() );
1402 if (currentBasket()->redirectEditActions()) {
1403 m_actCutNote ->setEnabled( currentBasket()->hasSelectedTextInEditor() );
1404 m_actCopyNote ->setEnabled( currentBasket()->hasSelectedTextInEditor() );
1405 m_actPaste ->setEnabled( true );
1406 m_actDelNote ->setEnabled( currentBasket()->hasSelectedTextInEditor() );
1407 } else {
1408 m_actCutNote ->setEnabled( !isLocked && oneOrSeveralSelected );
1409 m_actCopyNote ->setEnabled( oneOrSeveralSelected );
1410 m_actPaste ->setEnabled( !isLocked );
1411 m_actDelNote ->setEnabled( !isLocked && oneOrSeveralSelected );
1413 m_actOpenNote ->setEnabled( oneOrSeveralSelected );
1414 m_actOpenNoteWith ->setEnabled( oneSelected ); // TODO: oneOrSeveralSelected IF SAME TYPE
1415 m_actSaveNoteAs ->setEnabled( oneSelected ); // IDEM?
1416 m_actGroup ->setEnabled( !isLocked && severalSelected && (!selectedGroup || selectedGroup->isColumn()) );
1417 m_actUngroup ->setEnabled( !isLocked && selectedGroup && !selectedGroup->isColumn() );
1418 m_actMoveOnTop ->setEnabled( !isLocked && oneOrSeveralSelected && !currentBasket()->isFreeLayout() );
1419 m_actMoveNoteUp ->setEnabled( !isLocked && oneOrSeveralSelected ); // TODO: Disable when unavailable!
1420 m_actMoveNoteDown ->setEnabled( !isLocked && oneOrSeveralSelected );
1421 m_actMoveOnBottom ->setEnabled( !isLocked && oneOrSeveralSelected && !currentBasket()->isFreeLayout() );
1423 for (KAction *action = m_insertActions.first(); action; action = m_insertActions.next())
1424 action->setEnabled( !isLocked );
1426 // From the old Note::contextMenuEvent(...) :
1427 /* if (useFile() || m_type == Link) {
1428 m_type == Link ? i18n("&Open target") : i18n("&Open")
1429 m_type == Link ? i18n("Open target &with...") : i18n("Open &with...")
1430 m_type == Link ? i18n("&Save target as...") : i18n("&Save a copy as...")
1431 // If useFile() theire is always a file to open / open with / save, but :
1432 if (m_type == Link) {
1433 if (url().prettyURL().isEmpty() && runCommand().isEmpty()) // no URL nor runCommand :
1434 popupMenu->setItemEnabled(7, false); // no possible Open !
1435 if (url().prettyURL().isEmpty()) // no URL :
1436 popupMenu->setItemEnabled(8, false); // no possible Open with !
1437 if (url().prettyURL().isEmpty() || url().path().endsWith("/")) // no URL or target a folder :
1438 popupMenu->setItemEnabled(9, false); // not possible to save target file
1440 } else if (m_type != Color) {
1441 popupMenu->insertSeparator();
1442 popupMenu->insertItem( SmallIconSet("filesaveas"), i18n("&Save a copy as..."), this, SLOT(slotSaveAs()), 0, 10 );
1446 // BEGIN Color picker (code from KColorEdit):
1448 /* Activate the mode
1450 void BNPView::slotColorFromScreen(bool global)
1452 m_colorPickWasGlobal = global;
1453 if (isMainWindowActive()) {
1454 if(Global::mainWindow()) Global::mainWindow()->hide();
1455 m_colorPickWasShown = true;
1456 } else
1457 m_colorPickWasShown = false;
1459 currentBasket()->saveInsertionData();
1460 m_colorPicker->pickColor();
1462 /* m_gettingColorFromScreen = true;
1463 kapp->processEvents();
1464 QTimer::singleShot( 100, this, SLOT(grabColorFromScreen()) );*/
1467 void BNPView::slotColorFromScreenGlobal()
1469 slotColorFromScreen(true);
1472 void BNPView::colorPicked(const QColor &color)
1474 if (!currentBasket()->isLoaded()) {
1475 showPassiveLoading(currentBasket());
1476 currentBasket()->load();
1478 currentBasket()->insertColor(color);
1480 if (m_colorPickWasShown)
1481 showMainWindow();
1483 if (Settings::usePassivePopup())
1484 showPassiveDropped(i18n("Picked color to basket <i>%1</i>"));
1487 void BNPView::colorPickingCanceled()
1489 if (m_colorPickWasShown)
1490 showMainWindow();
1493 void BNPView::slotConvertTexts()
1496 int result = KMessageBox::questionYesNoCancel(
1497 this,
1498 i18n(
1499 "<p>This will convert every text notes into rich text notes.<br>"
1500 "The content of the notes will not change and you will be able to apply formating to those notes.</p>"
1501 "<p>This process cannot be reverted back: you will not be able to convert the rich text notes to plain text ones later.</p>"
1502 "<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>"
1503 "If nobody complain about not having plain text notes anymore, then the final version is likely to not support plain text notes anymore.</p>"
1504 "<p><b>Which basket notes do you want to convert?</b></p>"
1506 i18n("Convert Text Notes"),
1507 KGuiItem(i18n("Only in the Current Basket")),
1508 KGuiItem(i18n("In Every Baskets"))
1510 if (result == KMessageBox::Cancel)
1511 return;
1514 bool conversionsDone;
1515 // if (result == KMessageBox::Yes)
1516 // conversionsDone = currentBasket()->convertTexts();
1517 // else
1518 conversionsDone = convertTexts();
1520 if (conversionsDone)
1521 KMessageBox::information(this, i18n("The plain text notes have been converted to rich text."), i18n("Conversion Finished"));
1522 else
1523 KMessageBox::information(this, i18n("There are no plain text notes to convert."), i18n("Conversion Finished"));
1526 Q3PopupMenu* BNPView::popupMenu(const QString &menuName)
1528 Q3PopupMenu *menu = 0;
1529 bool hack = false; // TODO fix this
1530 // When running in kontact and likeback Information message is shown
1531 // factory is 0. Don't show error then and don't crash either :-)
1533 if(m_guiClient)
1535 KXMLGUIFactory* factory = m_guiClient->factory();
1536 if(factory)
1538 menu = (Q3PopupMenu *)factory->container(menuName, m_guiClient);
1540 else
1541 hack = isPart();
1543 if (menu == 0) {
1544 if(!hack)
1546 KStandardDirs stdDirs;
1547 KMessageBox::error( this, i18n(
1548 "<p><b>The file basketui.rc seems to not exist or is too old.<br>"
1549 "%1 cannot run without it and will stop.</b></p>"
1550 "<p>Please check your installation of %2.</p>"
1551 "<p>If you do not have administrator access to install the application "
1552 "system wide, you can copy the file basketui.rc from the installation "
1553 "archive to the folder <a href='file://%3'>%4</a>.</p>"
1554 "<p>As last ressort, if you are sure the application is correctly installed "
1555 "but you had a preview version of it, try to remove the "
1556 "file %5basketui.rc</p>")
1557 .arg(kapp->aboutData()->programName(), kapp->aboutData()->programName(),
1558 stdDirs.saveLocation("data", "basket/")).arg(stdDirs.saveLocation("data", "basket/"), stdDirs.saveLocation("data", "basket/")),
1559 i18n("Ressource not Found"), KMessageBox::AllowLink );
1561 if(!isPart())
1562 exit(1); // We SHOULD exit right now and abord everything because the caller except menu != 0 to not crash.
1563 else
1564 menu = new KPopupMenu; // When running in kpart we cannot exit
1566 return menu;
1569 void BNPView::showHideFilterBar(bool show, bool switchFocus)
1571 // if (show != m_actShowFilter->isChecked())
1572 // m_actShowFilter->setChecked(show);
1573 m_actShowFilter->setChecked(currentDecoratedBasket()->filterData().isFiltering);
1575 currentDecoratedBasket()->setFilterBarShown(show, switchFocus);
1576 currentDecoratedBasket()->resetFilter();
1579 void BNPView::insertEmpty(int type)
1581 if (currentBasket()->isLocked()) {
1582 showPassiveImpossible(i18n("Cannot add note."));
1583 return;
1585 currentBasket()->insertEmptyNote(type);
1588 void BNPView::insertWizard(int type)
1590 if (currentBasket()->isLocked()) {
1591 showPassiveImpossible(i18n("Cannot add note."));
1592 return;
1594 currentBasket()->insertWizard(type);
1597 // BEGIN Screen Grabbing: // FIXME
1599 void BNPView::grabScreenshot(bool global)
1601 if (m_regionGrabber) {
1602 KWin::activateWindow(m_regionGrabber->winId());
1603 return;
1606 // Delay before to take a screenshot because if we hide the main window OR the systray popup menu,
1607 // we should wait the windows below to be repainted!!!
1608 // A special case is where the action is triggered with the global keyboard shortcut.
1609 // In this case, global is true, and we don't wait.
1610 // In the future, if global is also defined for other cases, check for
1611 // enum KAction::ActivationReason { UnknownActivation, EmulatedActivation, AccelActivation, PopupMenuActivation, ToolBarActivation };
1612 int delay = (isMainWindowActive() ? 500 : (global/*kapp->activePopupWidget()*/ ? 0 : 200));
1614 m_colorPickWasGlobal = global;
1615 if (isMainWindowActive()) {
1616 if(Global::mainWindow()) Global::mainWindow()->hide();
1617 m_colorPickWasShown = true;
1618 } else
1619 m_colorPickWasShown = false;
1621 currentBasket()->saveInsertionData();
1622 m_regionGrabber = new RegionGrabber(delay);
1623 connect( m_regionGrabber, SIGNAL(regionGrabbed(const QPixmap&)), this, SLOT(screenshotGrabbed(const QPixmap&)) );
1626 void BNPView::grabScreenshotGlobal()
1628 grabScreenshot(true);
1631 void BNPView::screenshotGrabbed(const QPixmap &pixmap)
1633 delete m_regionGrabber;
1634 m_regionGrabber = 0;
1636 // Cancelled (pressed Escape):
1637 if (pixmap.isNull()) {
1638 if (m_colorPickWasShown)
1639 showMainWindow();
1640 return;
1643 if (!currentBasket()->isLoaded()) {
1644 showPassiveLoading(currentBasket());
1645 currentBasket()->load();
1647 currentBasket()->insertImage(pixmap);
1649 if (m_colorPickWasShown)
1650 showMainWindow();
1652 if (Settings::usePassivePopup())
1653 showPassiveDropped(i18n("Grabbed screen zone to basket <i>%1</i>"));
1656 Basket* BNPView::basketForFolderName(const QString &folderName)
1658 /* QPtrList<Basket> basketsList = listBaskets();
1659 Basket *basket;
1660 for (basket = basketsList.first(); basket; basket = basketsList.next())
1661 if (basket->folderName() == folderName)
1662 return basket;
1665 QString name = folderName;
1666 if (!name.endsWith("/"))
1667 name += "/";
1669 Q3ListViewItemIterator it(m_tree);
1670 while (it.current()) {
1671 BasketListViewItem *item = ((BasketListViewItem*)it.current());
1672 if (item->basket()->folderName() == name)
1673 return item->basket();
1674 ++it;
1678 return 0;
1681 Note* BNPView::noteForFileName(const QString &fileName, Basket &basket, Note* note)
1683 if (!note)
1684 note = basket.firstNote();
1685 if (note->fullPath().endsWith(fileName))
1686 return note;
1687 Note* child = note->firstChild();
1688 Note* found;
1689 while(child)
1691 found = noteForFileName(fileName, basket, child);
1692 if (found)
1693 return found;
1694 child = child->next();
1696 return 0;
1699 void BNPView::setFiltering(bool filtering)
1701 m_actShowFilter->setChecked(filtering);
1702 m_actResetFilter->setEnabled(filtering);
1705 void BNPView::undo()
1707 // TODO
1710 void BNPView::redo()
1712 // TODO
1715 void BNPView::pasteToBasket(int /*index*/, QClipboard::Mode /*mode*/)
1717 //TODO: REMOVE!
1718 //basketAt(index)->pasteNote(mode);
1721 void BNPView::propBasket()
1723 BasketPropertiesDialog dialog(currentBasket(), this);
1724 dialog.exec();
1727 void BNPView::delBasket()
1729 // DecoratedBasket *decoBasket = currentDecoratedBasket();
1730 Basket *basket = currentBasket();
1732 #if 0
1733 KDialogBase *dialog = new KDialogBase(this, /*name=*/0, /*modal=*/true, /*caption=*/i18n("Delete Basket"),
1734 KDialogBase::User1 | KDialogBase::User2 | KDialogBase::No, KDialogBase::User1,
1735 /*separator=*/false,
1736 /*user1=*/KGuiItem(i18n("Delete Only that Basket")/*, icon=""*/),
1737 /*user2=*/KGuiItem(i18n("Delete Note & Children")/*, icon=""*/) );
1738 QStringList basketsList;
1739 basketsList.append("Basket 1");
1740 basketsList.append(" Basket 2");
1741 basketsList.append(" Basket 3");
1742 basketsList.append(" Basket 4");
1743 KMessageBox::createKMessageBox(
1744 dialog, QMessageBox::Information,
1745 i18n("<qt>Do you really want to remove the basket <b>%1</b> and its contents?</qt>")
1746 .arg(Tools::textToHTMLWithoutP(basket->basketName())),
1747 basketsList, /*ask=*/"", /*checkboxReturn=*/0, /*options=*/KMessageBox::Notify/*, const QString &details=QString::null*/);
1748 #endif
1750 int really = KMessageBox::questionYesNo( this,
1751 i18n("<qt>Do you really want to remove the basket <b>%1</b> and its contents?</qt>")
1752 .arg(Tools::textToHTMLWithoutP(basket->basketName())),
1753 i18n("Remove Basket")
1754 #if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
1755 , KGuiItem(i18n("&Remove Basket"), "editdelete"), KStdGuiItem::cancel());
1756 #else
1758 #endif
1760 if (really == KMessageBox::No)
1761 return;
1763 QStringList basketsList = listViewItemForBasket(basket)->childNamesTree();
1764 if (basketsList.count() > 0) {
1765 int deleteChilds = KMessageBox::questionYesNoList( this,
1766 i18n("<qt><b>%1</b> have the following children baskets.<br>Do you want to remove them too?</qt>")
1767 .arg(Tools::textToHTMLWithoutP(basket->basketName())),
1768 basketsList,
1769 i18n("Remove Children Baskets")
1770 #if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
1771 , KGuiItem(i18n("&Remove Children Baskets"), "editdelete"));
1772 #else
1774 #endif
1776 if (deleteChilds == KMessageBox::No)
1777 listViewItemForBasket(basket)->moveChildsBaskets();
1780 doBasketDeletion(basket);
1782 // basketNumberChanged();
1783 // rebuildBasketsMenu();
1786 void BNPView::doBasketDeletion(Basket *basket)
1788 basket->closeEditor();
1790 Q3ListViewItem *basketItem = listViewItemForBasket(basket);
1791 Q3ListViewItem *nextOne;
1792 for (Q3ListViewItem *child = basketItem->firstChild(); child; child = nextOne) {
1793 nextOne = child->nextSibling();
1794 // First delete the child baskets:
1795 doBasketDeletion(((BasketListViewItem*)child)->basket());
1797 // Then, basket have no child anymore, delete it:
1798 DecoratedBasket *decoBasket = basket->decoration();
1799 basket->deleteFiles();
1800 removeBasket(basket);
1801 // Remove the action to avoir keyboard-shortcut clashes:
1802 delete basket->m_action; // FIXME: It's quick&dirty. In the future, the Basket should be deleted, and then the KAction deleted in the Basket destructor.
1803 delete decoBasket;
1804 // delete basket;
1807 void BNPView::password()
1809 #ifdef HAVE_LIBGPGME
1810 PasswordDlg dlg(kapp->activeWindow(), "Password");
1811 Basket *cur = currentBasket();
1813 dlg.setType(cur->encryptionType());
1814 dlg.setKey(cur->encryptionKey());
1815 if(dlg.exec()) {
1816 cur->setProtection(dlg.type(), dlg.key());
1817 if (cur->encryptionType() != Basket::NoEncryption)
1818 cur->lock();
1820 #endif
1823 void BNPView::lockBasket()
1825 #ifdef HAVE_LIBGPGME
1826 Basket *cur = currentBasket();
1828 cur->lock();
1829 #endif
1832 void BNPView::saveAsArchive()
1834 Basket *basket = currentBasket();
1836 QDir dir;
1838 KConfig *config = KGlobal::config();
1839 config->setGroup("Basket Archive");
1840 QString folder = config->readEntry("lastFolder", QDir::homeDirPath()) + "/";
1841 QString url = folder + QString(basket->basketName()).replace("/", "_") + ".baskets";
1843 QString filter = "*.baskets|" + i18n("Basket Archives") + "\n*|" + i18n("All Files");
1844 QString destination = url;
1845 for (bool askAgain = true; askAgain; ) {
1846 destination = KFileDialog::getSaveFileName(destination, filter, this, i18n("Save as Basket Archive"));
1847 if (destination.isEmpty()) // User canceled
1848 return;
1849 if (dir.exists(destination)) {
1850 int result = KMessageBox::questionYesNoCancel(
1851 this,
1852 "<qt>" + i18n("The file <b>%1</b> already exists. Do you really want to override it?")
1853 .arg(KURL(destination).fileName()),
1854 i18n("Override File?"),
1855 KGuiItem(i18n("&Override"), "filesave")
1857 if (result == KMessageBox::Cancel)
1858 return;
1859 else if (result == KMessageBox::Yes)
1860 askAgain = false;
1861 } else
1862 askAgain = false;
1864 bool withSubBaskets = true;//KMessageBox::questionYesNo(this, i18n("Do you want to export sub-baskets too?"), i18n("Save as Basket Archive")) == KMessageBox::Yes;
1866 config->writeEntry("lastFolder", KURL(destination).directory());
1867 config->sync();
1869 Archive::save(basket, withSubBaskets, destination);
1872 QString BNPView::s_fileToOpen = "";
1874 void BNPView::delayedOpenArchive()
1876 Archive::open(s_fileToOpen);
1879 void BNPView::openArchive()
1881 QString filter = "*.baskets|" + i18n("Basket Archives") + "\n*|" + i18n("All Files");
1882 QString path = KFileDialog::getOpenFileName(QString::null, filter, this, i18n("Open Basket Archive"));
1883 if (!path.isEmpty()) // User has not canceled
1884 Archive::open(path);
1888 void BNPView::activatedTagShortcut()
1890 Tag *tag = Tag::tagForKAction((KAction*)sender());
1891 currentBasket()->activatedTagShortcut(tag);
1894 void BNPView::slotBasketNumberChanged(int number)
1896 m_actPreviousBasket->setEnabled(number > 1);
1897 m_actNextBasket ->setEnabled(number > 1);
1900 void BNPView::slotBasketChanged()
1902 m_actFoldBasket->setEnabled(canFold());
1903 m_actExpandBasket->setEnabled(canExpand());
1904 setFiltering(currentBasket() && currentBasket()->decoration()->filterData().isFiltering);
1907 void BNPView::currentBasketChanged()
1911 void BNPView::isLockedChanged()
1913 bool isLocked = currentBasket()->isLocked();
1915 setLockStatus(isLocked);
1917 // m_actLockBasket->setChecked(isLocked);
1918 m_actPropBasket->setEnabled(!isLocked);
1919 m_actDelBasket ->setEnabled(!isLocked);
1920 updateNotesActions();
1923 void BNPView::askNewBasket()
1925 askNewBasket(0, 0);
1928 void BNPView::askNewBasket(Basket *parent, Basket *pickProperties)
1930 NewBasketDefaultProperties properties;
1931 if (pickProperties) {
1932 properties.icon = pickProperties->icon();
1933 properties.backgroundImage = pickProperties->backgroundImageName();
1934 properties.backgroundColor = pickProperties->backgroundColorSetting();
1935 properties.textColor = pickProperties->textColorSetting();
1936 properties.freeLayout = pickProperties->isFreeLayout();
1937 properties.columnCount = pickProperties->columnsCount();
1940 NewBasketDialog(parent, properties, this).exec();
1943 void BNPView::askNewSubBasket()
1945 askNewBasket( /*parent=*/currentBasket(), /*pickPropertiesOf=*/currentBasket() );
1948 void BNPView::askNewSiblingBasket()
1950 askNewBasket( /*parent=*/parentBasketOf(currentBasket()), /*pickPropertiesOf=*/currentBasket() );
1953 void BNPView::globalPasteInCurrentBasket()
1955 currentBasket()->setInsertPopupMenu();
1956 pasteInCurrentBasket();
1957 currentBasket()->cancelInsertPopupMenu();
1960 void BNPView::pasteInCurrentBasket()
1962 currentBasket()->pasteNote();
1964 if (Settings::usePassivePopup())
1965 showPassiveDropped(i18n("Clipboard content pasted to basket <i>%1</i>"));
1968 void BNPView::pasteSelInCurrentBasket()
1970 currentBasket()->pasteNote(QClipboard::Selection);
1972 if (Settings::usePassivePopup())
1973 showPassiveDropped(i18n("Selection pasted to basket <i>%1</i>"));
1976 void BNPView::showPassiveDropped(const QString &title)
1978 if ( ! currentBasket()->isLocked() ) {
1979 // TODO: Keep basket, so that we show the message only if something was added to a NOT visible basket
1980 m_passiveDroppedTitle = title;
1981 m_passiveDroppedSelection = currentBasket()->selectedNotes();
1982 QTimer::singleShot( c_delayTooltipTime, this, SLOT(showPassiveDroppedDelayed()) );
1983 // DELAY IT BELOW:
1984 } else
1985 showPassiveImpossible(i18n("No note was added."));
1988 void BNPView::showPassiveDroppedDelayed()
1990 if (isMainWindowActive() || m_passiveDroppedSelection == 0)
1991 return;
1993 QString title = m_passiveDroppedTitle;
1995 delete m_passivePopup; // Delete previous one (if exists): it will then hide it (only one at a time)
1996 m_passivePopup = new KPassivePopup(Settings::useSystray() ? (QWidget*)Global::systemTray : this);
1997 QPixmap contentsPixmap = NoteDrag::feedbackPixmap(m_passiveDroppedSelection);
1998 Q3MimeSourceFactory::defaultFactory()->setPixmap("_passivepopup_image_", contentsPixmap);
1999 m_passivePopup->setView(
2000 title.arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2001 (contentsPixmap.isNull() ? "" : "<img src=\"_passivepopup_image_\">"),
2002 kapp->iconLoader()->loadIcon(currentBasket()->icon(), KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true));
2003 m_passivePopup->show();
2006 void BNPView::showPassiveImpossible(const QString &message)
2008 delete m_passivePopup; // Delete previous one (if exists): it will then hide it (only one at a time)
2009 m_passivePopup = new KPassivePopup(Settings::useSystray() ? (QWidget*)Global::systemTray : (QWidget*)this);
2010 m_passivePopup->setView(
2011 QString("<font color=red>%1</font>")
2012 .arg(i18n("Basket <i>%1</i> is locked"))
2013 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName())),
2014 message,
2015 kapp->iconLoader()->loadIcon(currentBasket()->icon(), KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true));
2016 m_passivePopup->show();
2019 void BNPView::showPassiveContentForced()
2021 showPassiveContent(/*forceShow=*/true);
2024 void BNPView::showPassiveContent(bool forceShow/* = false*/)
2026 if (!forceShow && isMainWindowActive())
2027 return;
2029 // FIXME: Duplicate code (2 times)
2030 QString message;
2032 delete m_passivePopup; // Delete previous one (if exists): it will then hide it (only one at a time)
2033 m_passivePopup = new KPassivePopup(Settings::useSystray() ? (QWidget*)Global::systemTray : (QWidget*)this);
2034 m_passivePopup->setView(
2035 "<qt>" + kapp->makeStdCaption( currentBasket()->isLocked()
2036 ? QString("%1 <font color=gray30>%2</font>")
2037 .arg(Tools::textToHTMLWithoutP(currentBasket()->basketName()), i18n("(Locked)"))
2038 : Tools::textToHTMLWithoutP(currentBasket()->basketName()) ),
2039 message,
2040 kapp->iconLoader()->loadIcon(currentBasket()->icon(), KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true));
2041 m_passivePopup->show();
2044 void BNPView::showPassiveLoading(Basket *basket)
2046 if (isMainWindowActive())
2047 return;
2049 delete m_passivePopup; // Delete previous one (if exists): it will then hide it (only one at a time)
2050 m_passivePopup = new KPassivePopup(Settings::useSystray() ? (QWidget*)Global::systemTray : (QWidget*)this);
2051 m_passivePopup->setView(
2052 Tools::textToHTMLWithoutP(basket->basketName()),
2053 i18n("Loading..."),
2054 kapp->iconLoader()->loadIcon(basket->icon(), KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true));
2055 m_passivePopup->show();
2058 void BNPView::addNoteText() { showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Text); }
2059 void BNPView::addNoteHtml() { showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Html); }
2060 void BNPView::addNoteImage() { showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Image); }
2061 void BNPView::addNoteLink() { showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Link); }
2062 void BNPView::addNoteColor() { showMainWindow(); currentBasket()->insertEmptyNote(NoteType::Color); }
2064 void BNPView::aboutToHideNewBasketPopup()
2066 QTimer::singleShot(0, this, SLOT(cancelNewBasketPopup()));
2069 void BNPView::cancelNewBasketPopup()
2071 m_newBasketPopup = false;
2074 void BNPView::setNewBasketPopup()
2076 m_newBasketPopup = true;
2079 void BNPView::setCaption(QString s)
2081 emit setWindowCaption(s);
2084 void BNPView::updateStatusBarHint()
2086 m_statusbar->updateStatusBarHint();
2089 void BNPView::setSelectionStatus(QString s)
2091 m_statusbar->setSelectionStatus(s);
2094 void BNPView::setLockStatus(bool isLocked)
2096 m_statusbar->setLockStatus(isLocked);
2099 void BNPView::postStatusbarMessage(const QString& msg)
2101 m_statusbar->postStatusbarMessage(msg);
2104 void BNPView::setStatusBarHint(const QString &hint)
2106 m_statusbar->setStatusBarHint(hint);
2109 void BNPView::setUnsavedStatus(bool isUnsaved)
2111 m_statusbar->setUnsavedStatus(isUnsaved);
2114 void BNPView::setActive(bool active)
2116 // std::cout << "Main Window Position: setActive(" << (active ? "true" : "false") << ")" << std::endl;
2117 KMainWindow* win = Global::mainWindow();
2118 if(!win)
2119 return;
2121 #if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
2122 if (active) {
2123 kapp->updateUserTimestamp(); // If "activate on mouse hovering systray", or "on drag throught systray"
2124 Global::systemTray->setActive(); // FIXME: add this in the places it need
2125 } else
2126 Global::systemTray->setInactive();
2127 #elif KDE_IS_VERSION( 3, 1, 90 ) // KDE 3.2.x
2128 // Code from Kopete (that seem to work, in waiting KSystemTray make puplic the toggleSHown) :
2129 if (active) {
2130 win->show();
2131 //raise() and show() should normaly deIconify the window. but it doesn't do here due
2132 // to a bug in Qt or in KDE (qt3.1.x or KDE 3.1.x) then, i have to call KWin's method
2133 if (win->isMinimized())
2134 KWin::deIconifyWindow(winId());
2136 if ( ! KWin::windowInfo(winId(), NET::WMDesktop).onAllDesktops() )
2137 KWin::setOnDesktop(winId(), KWin::currentDesktop());
2138 win->raise();
2139 // Code from me: expected and correct behavviour:
2140 kapp->updateUserTimestamp(); // If "activate on mouse hovering systray", or "on drag throught systray"
2141 KWin::activateWindow(win->winId());
2142 } else
2143 win->hide();
2144 #else // KDE 3.1.x and lower
2145 if (win->active) {
2146 if (win->isMinimized())
2147 win->hide(); // If minimized, show() doesn't work !
2148 win->show(); // Show it
2149 // showNormal(); // If it was minimized
2150 win->raise(); // Raise it on top
2151 win->setActiveWindow(); // And set it the active window
2152 } else
2153 win->hide();
2154 #endif
2157 void BNPView::hideOnEscape()
2159 if (Settings::useSystray())
2160 setActive(false);
2163 bool BNPView::isPart()
2165 return (strcmp(name(), "BNPViewPart") == 0);
2168 bool BNPView::isMainWindowActive()
2170 KMainWindow* main = Global::mainWindow();
2171 if (main && main->isActiveWindow())
2172 return true;
2173 return false;
2176 void BNPView::newBasket()
2178 askNewBasket();
2181 bool BNPView::createNoteHtml(const QString content, const QString basket)
2183 Basket* b = basketForFolderName(basket);
2184 if (!b)
2185 return false;
2186 Note* note = NoteFactory::createNoteHtml(content, b);
2187 if (!note)
2188 return false;
2189 b -> insertCreatedNote(note);
2190 return true;
2193 bool BNPView::changeNoteHtml(const QString content, const QString basket, const QString noteName)
2195 Basket* b = basketForFolderName(basket);
2196 if (!b)
2197 return false;
2198 Note* note = noteForFileName(noteName , *b);
2199 if (!note || note->content()->type()!=NoteType::Html)
2200 return false;
2201 HtmlContent* noteContent = (HtmlContent*)note->content();
2202 noteContent->setHtml(content);
2203 note->saveAgain();
2204 return true;
2207 bool BNPView::createNoteFromFile(const QString url, const QString basket)
2209 Basket* b = basketForFolderName(basket);
2210 if (!b)
2211 return false;
2212 KURL kurl(url);
2213 if ( url.isEmpty() )
2214 return false;
2215 Note* n = NoteFactory::copyFileAndLoad(kurl, b);
2216 if (!n)
2217 return false;
2218 b->insertCreatedNote(n);
2219 return true;
2222 QStringList BNPView::listBaskets()
2224 QStringList basketList;
2226 Q3ListViewItemIterator it(m_tree);
2227 while (it.current()) {
2228 BasketListViewItem *item = ((BasketListViewItem*)it.current());
2229 basketList.append(item->basket()->basketName());
2230 basketList.append(item->basket()->folderName());
2231 ++it;
2233 return basketList;
2236 void BNPView::handleCommandLine()
2238 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
2240 /* Custom data folder */
2241 Q3CString customDataFolder = args->getOption("data-folder");
2242 if (customDataFolder != 0 && !customDataFolder.isEmpty())
2244 Global::setCustomSavesFolder(customDataFolder);
2246 /* Debug window */
2247 if (args->isSet("debug")) {
2248 new DebugWindow();
2249 Global::debugWindow->show();
2252 /* Crash Handler to Mail Developers when Crashing: */
2253 #ifndef BASKET_USE_DRKONQI
2254 if (!args->isSet("use-drkonquy"))
2255 KCrash::setCrashHandler(Crash::crashHandler);
2256 #endif
2259 void BNPView::reloadBasket(const QString &folderName)
2261 basketForFolderName(folderName)->reload();
2264 /** Scenario of "Hide main window to system tray icon when mouse move out of the window" :
2265 * - At enterEvent() we stop m_tryHideTimer
2266 * - After that and before next, we are SURE cursor is hovering window
2267 * - At leaveEvent() we restart m_tryHideTimer
2268 * - Every 'x' ms, timeoutTryHide() seek if cursor hover a widget of the application or not
2269 * - If yes, we musn't hide the window
2270 * - But if not, we start m_hideTimer to hide main window after a configured elapsed time
2271 * - timeoutTryHide() continue to be called and if cursor move again to one widget of the app, m_hideTimer is stopped
2272 * - If after the configured time cursor hasn't go back to a widget of the application, timeoutHide() is called
2273 * - It then hide the main window to systray icon
2274 * - When the user will show it, enterEvent() will be called the first time he enter mouse to it
2275 * - ...
2278 /** Why do as this ? Problems with the use of only enterEvent() and leaveEvent() :
2279 * - Resize window or hover titlebar isn't possible : leave/enterEvent
2280 * are
2281 * > Use the grip or Alt+rightDND to resize window
2282 * > Use Alt+DND to move window
2283 * - Each menu trigger the leavEvent
2286 void BNPView::enterEvent(QEvent*)
2288 if(m_tryHideTimer)
2289 m_tryHideTimer->stop();
2290 if(m_hideTimer)
2291 m_hideTimer->stop();
2294 void BNPView::leaveEvent(QEvent*)
2296 if (Settings::useSystray() && Settings::hideOnMouseOut() && m_tryHideTimer)
2297 m_tryHideTimer->start(50);
2300 void BNPView::timeoutTryHide()
2302 // If a menu is displayed, do nothing for the moment
2303 if (kapp->activePopupWidget() != 0L)
2304 return;
2306 if (kapp->widgetAt(QCursor::pos()) != 0L)
2307 m_hideTimer->stop();
2308 else if ( ! m_hideTimer->isActive() ) // Start only one time
2309 m_hideTimer->start(Settings::timeToHideOnMouseOut() * 100, true);
2311 // If a sub-dialog is oppened, we musn't hide the main window:
2312 if (kapp->activeWindow() != 0L && kapp->activeWindow() != Global::mainWindow())
2313 m_hideTimer->stop();
2316 void BNPView::timeoutHide()
2318 // We check that because the setting can have been set to off
2319 if (Settings::useSystray() && Settings::hideOnMouseOut())
2320 setActive(false);
2321 m_tryHideTimer->stop();
2324 void BNPView::changedSelectedNotes()
2326 // tabChanged(0); // FIXME: NOT OPTIMIZED
2329 /*void BNPView::areSelectedNotesCheckedChanged(bool checked)
2331 m_actCheckNotes->setChecked(checked && currentBasket()->showCheckBoxes());
2334 void BNPView::enableActions()
2336 Basket *basket = currentBasket();
2337 if(!basket)
2338 return;
2339 if(m_actLockBasket)
2340 m_actLockBasket->setEnabled(!basket->isLocked() && basket->isEncrypted());
2341 if(m_actPassBasket)
2342 m_actPassBasket->setEnabled(!basket->isLocked());
2343 m_actPropBasket->setEnabled(!basket->isLocked());
2344 m_actDelBasket->setEnabled(!basket->isLocked());
2345 m_actExportToHtml->setEnabled(!basket->isLocked());
2346 m_actShowFilter->setEnabled(!basket->isLocked());
2347 m_actFilterAllBaskets->setEnabled(!basket->isLocked());
2348 m_actResetFilter->setEnabled(!basket->isLocked());
2349 basket->decoration()->filterBar()->setEnabled(!basket->isLocked());
2352 void BNPView::showMainWindow()
2354 KMainWindow *win = Global::mainWindow();
2356 if (win)
2358 win->show();
2360 setActive(true);
2361 emit showPart();
2364 void BNPView::populateTagsMenu()
2366 KPopupMenu *menu = (KPopupMenu*)(popupMenu("tags"));
2367 if (menu == 0 || currentBasket() == 0) // TODO: Display a messagebox. [menu is 0, surely because on first launch, the XMLGUI does not work!]
2368 return;
2369 menu->clear();
2371 Note *referenceNote;
2372 if (currentBasket()->focusedNote() && currentBasket()->focusedNote()->isSelected())
2373 referenceNote = currentBasket()->focusedNote();
2374 else
2375 referenceNote = currentBasket()->firstSelected();
2377 populateTagsMenu(*menu, referenceNote);
2379 m_lastOpenedTagsMenu = menu;
2380 // connect( menu, SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()) );
2383 void BNPView::populateTagsMenu(KPopupMenu &menu, Note *referenceNote)
2385 if (currentBasket() == 0)
2386 return;
2388 currentBasket()->m_tagPopupNote = referenceNote;
2389 bool enable = currentBasket()->countSelecteds() > 0;
2391 Q3ValueList<Tag*>::iterator it;
2392 Tag *currentTag;
2393 State *currentState;
2394 int i = 10;
2395 for (it = Tag::all.begin(); it != Tag::all.end(); ++it) {
2396 // Current tag and first state of it:
2397 currentTag = *it;
2398 currentState = currentTag->states().first();
2399 QKeySequence sequence;
2400 if (!currentTag->shortcut().isNull())
2401 sequence = currentTag->shortcut().operator QKeySequence();
2402 menu.insertItem(StateMenuItem::checkBoxIconSet(
2403 (referenceNote ? referenceNote->hasTag(currentTag) : false),
2404 menu.colorGroup()),
2405 new StateMenuItem(currentState, sequence, true),
2408 if (!currentTag->shortcut().isNull())
2409 menu.setAccel(sequence, i);
2410 menu.setItemEnabled(i, enable);
2411 ++i;
2414 menu.insertSeparator();
2415 // menu.insertItem( /*SmallIconSet("editdelete"),*/ "&Assign new Tag...", 1 );
2416 //id = menu.insertItem( SmallIconSet("editdelete"), "&Remove All", -2 );
2417 //if (referenceNote->states().isEmpty())
2418 // menu.setItemEnabled(id, false);
2419 // menu.insertItem( SmallIconSet("configure"), "&Customize...", 3 );
2420 menu.insertItem( new IndentedMenuItem(i18n("&Assign new Tag...")), 1 );
2421 menu.insertItem( new IndentedMenuItem(i18n("&Remove All"), "editdelete"), 2 );
2422 menu.insertItem( new IndentedMenuItem(i18n("&Customize..."), "configure"), 3 );
2424 menu.setItemEnabled(1, enable);
2425 if (!currentBasket()->selectedNotesHaveTags())
2426 menu.setItemEnabled(2, false);
2428 connect( &menu, SIGNAL(activated(int)), currentBasket(), SLOT(toggledTagInMenu(int)) );
2429 connect( &menu, SIGNAL(aboutToHide()), currentBasket(), SLOT(unlockHovering()) );
2430 connect( &menu, SIGNAL(aboutToHide()), currentBasket(), SLOT(disableNextClick()) );
2433 void BNPView::connectTagsMenu()
2435 connect( popupMenu("tags"), SIGNAL(aboutToShow()), this, SLOT(populateTagsMenu()) );
2436 connect( popupMenu("tags"), SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()) );
2440 * The Tags menu is ONLY created once the BasKet KPart is first shown.
2441 * So we can use this menu only from then?
2442 * When the KPart is changed in Kontact, and then the BasKet KPart is shown again,
2443 * Kontact created a NEW Tags menu. So we should connect again.
2444 * But when Kontact main window is hidden and then re-shown, the menu does not change.
2445 * So we disconnect at hide event to ensure only one connection: the next show event will not connects another time.
2448 void BNPView::showEvent(QShowEvent*)
2450 if (isPart())
2451 QTimer::singleShot( 0, this, SLOT(connectTagsMenu()) );
2453 if (m_firstShow) {
2454 m_firstShow = false;
2455 onFirstShow();
2457 if (isPart()/*TODO: && !LikeBack::enabledBar()*/) {
2458 Global::likeBack->enableBar();
2462 void BNPView::hideEvent(QHideEvent*)
2464 if (isPart()) {
2465 disconnect( popupMenu("tags"), SIGNAL(aboutToShow()), this, SLOT(populateTagsMenu()) );
2466 disconnect( popupMenu("tags"), SIGNAL(aboutToHide()), this, SLOT(disconnectTagsMenu()) );
2469 if (isPart())
2470 Global::likeBack->disableBar();
2473 void BNPView::disconnectTagsMenu()
2475 QTimer::singleShot( 0, this, SLOT(disconnectTagsMenuDelayed()) );
2478 void BNPView::disconnectTagsMenuDelayed()
2480 disconnect( m_lastOpenedTagsMenu, SIGNAL(activated(int)), currentBasket(), SLOT(toggledTagInMenu(int)) );
2481 disconnect( m_lastOpenedTagsMenu, SIGNAL(aboutToHide()), currentBasket(), SLOT(unlockHovering()) );
2482 disconnect( m_lastOpenedTagsMenu, SIGNAL(aboutToHide()), currentBasket(), SLOT(disableNextClick()) );
2485 void BNPView::showGlobalShortcutsSettingsDialog()
2487 KKeyDialog::configure(Global::globalAccel);
2488 //.setCaption(..)
2489 Global::globalAccel->writeSettings();
2492 #include "bnpview.moc"