Fix crash if key bindings specified in profile cannot be found. Improve
[personal-kdebase.git] / apps / keditbookmarks / toplevel.cpp
blobd4e1a467ef6cc71f2268601901e434a3ab0a0885
1 /* This file is part of the KDE project
2 Copyright (C) 2000 David Faure <faure@kde.org>
3 Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License version 2 or at your option version 3 as published by
8 the Free Software Foundation.
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 GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "toplevel.h"
23 #include "bookmarkmodel.h"
25 #include "bookmarkinfo.h"
26 #include "actionsimpl.h"
27 #include "exporters.h"
28 #include "settings.h"
29 #include "commands.h"
30 #include "kebsearchline.h"
31 #include "bookmarklistview.h"
33 #include <stdlib.h>
35 #include <QtGui/QClipboard>
36 #include <QtGui/QSplitter>
37 #include <QtGui/QLayout>
38 #include <QtGui/QLabel>
40 #include <kaction.h>
41 #include <kactioncollection.h>
42 #include <ktoggleaction.h>
43 #include <kapplication.h>
44 #include <kbookmark.h>
45 #include <kbookmarkmanager.h>
46 #include <kdebug.h>
47 #include <kedittoolbar.h>
48 #include <kfiledialog.h>
49 #include <klineedit.h>
50 #include <klocale.h>
51 #include <kmessagebox.h>
52 #include <kstandardaction.h>
54 #include <assert.h>
55 #include <QtCore/QBool>
59 CmdHistory* CmdHistory::s_self = 0;
61 CmdHistory::CmdHistory(KActionCollection *collection)
62 : m_commandHistory(collection) {
63 connect(&m_commandHistory, SIGNAL( commandExecuted(K3Command *) ),
64 SLOT( slotCommandExecuted(K3Command *) ));
65 assert(!s_self);
66 s_self = this; // this is hacky
69 CmdHistory* CmdHistory::self() {
70 assert(s_self);
71 return s_self;
74 void CmdHistory::slotCommandExecuted(K3Command *k) {
75 KEBApp::self()->notifyCommandExecuted();
77 IKEBCommand * cmd = dynamic_cast<IKEBCommand *>(k);
78 Q_ASSERT(cmd);
80 KBookmark bk = CurrentMgr::bookmarkAt(cmd->affectedBookmarks());
81 Q_ASSERT(bk.isGroup());
82 CurrentMgr::self()->notifyManagers(bk.toGroup());
85 void CmdHistory::notifyDocSaved() {
86 m_commandHistory.documentSaved();
89 void CmdHistory::didCommand(K3Command *cmd) {
90 if (!cmd)
91 return;
92 m_commandHistory.addCommand(cmd, false);
93 CmdHistory::slotCommandExecuted(cmd);
96 void CmdHistory::addCommand(K3Command *cmd) {
97 if (!cmd)
98 return;
99 m_commandHistory.addCommand(cmd);
102 void CmdHistory::addInFlightCommand(K3Command *cmd)
104 if(!cmd)
105 return;
106 m_commandHistory.addCommand(cmd, false);
109 void CmdHistory::clearHistory() {
110 m_commandHistory.clear();
113 /* -------------------------- */
115 CurrentMgr *CurrentMgr::s_mgr = 0;
117 CurrentMgr::CurrentMgr()
118 : QObject(0),
119 m_mgr(0), m_model(0), ignorenext(0)
123 CurrentMgr::~CurrentMgr()
125 delete m_model;
127 //TESTING
128 m_model=0;
131 KBookmarkGroup CurrentMgr::root()
133 return mgr()->root();
136 KBookmark CurrentMgr::bookmarkAt(const QString &a)
138 return self()->mgr()->findByAddress(a);
141 bool CurrentMgr::managerSave() { return mgr()->save(); }
142 void CurrentMgr::saveAs(const QString &fileName) { mgr()->saveAs(fileName); }
143 void CurrentMgr::setUpdate(bool update) { mgr()->setUpdate(update); }
144 QString CurrentMgr::path() const { return mgr()->path(); }
146 void CurrentMgr::createManager(const QString &filename, const QString &dbusObjectName) {
147 if (m_mgr) {
148 kDebug()<<"ERROR calling createManager twice";
149 disconnect(m_mgr, 0, 0, 0);
150 // still todo - delete old m_mgr
153 kDebug()<<"DBus Object name: "<<dbusObjectName;
154 m_mgr = KBookmarkManager::managerForFile(filename, dbusObjectName);
156 if ( m_model ) {
157 m_model->setRoot(root());
158 } else {
159 m_model = new KBookmarkModel(root());
162 connect(m_mgr, SIGNAL( changed(const QString &, const QString &) ),
163 SLOT( slotBookmarksChanged(const QString &, const QString &) ));
166 void CurrentMgr::slotBookmarksChanged(const QString &, const QString &) {
167 if(ignorenext > 0) //We ignore the first changed signal after every change we did
169 --ignorenext;
170 return;
173 m_model->setRoot(m_mgr->root());
175 CmdHistory::self()->clearHistory();
176 KEBApp::self()->updateActions();
177 KEBApp::self()->expandAll();
180 void CurrentMgr::notifyManagers(const KBookmarkGroup& grp)
182 ++ignorenext;
183 mgr()->emitChanged(grp);
186 void CurrentMgr::notifyManagers() {
187 notifyManagers( root() );
190 void CurrentMgr::reloadConfig() {
191 mgr()->emitConfigChanged();
194 QString CurrentMgr::makeTimeStr(const QString & in)
196 int secs;
197 bool ok;
198 secs = in.toInt(&ok);
199 if (!ok)
200 return QString();
201 return makeTimeStr(secs);
204 QString CurrentMgr::makeTimeStr(int b)
206 QDateTime dt;
207 dt.setTime_t(b);
208 return (dt.daysTo(QDateTime::currentDateTime()) > 31)
209 ? KGlobal::locale()->formatDate(dt.date(), KLocale::LongDate)
210 : KGlobal::locale()->formatDateTime(dt, KLocale::LongDate);
213 /* -------------------------- */
214 #include <QtDBus/QDBusConnection>
215 KEBApp *KEBApp::s_topLevel = 0;
217 KEBApp::KEBApp(
218 const QString &bookmarksFile, bool readonly,
219 const QString &address, bool browser, const QString &caption,
220 const QString &dbusObjectName
221 ) : KXmlGuiWindow(), m_bookmarksFilename(bookmarksFile),
222 m_caption(caption),
223 m_dbusObjectName(dbusObjectName), m_readOnly(readonly),m_browser(browser)
225 QDBusConnection::sessionBus().registerObject("/keditbookmarks", this, QDBusConnection::ExportScriptableSlots);
226 Q_UNUSED(address);//FIXME sets the current item
228 m_cmdHistory = new CmdHistory(actionCollection());
230 s_topLevel = this;
232 createActions();
233 if (m_browser)
234 createGUI();
235 else
236 createGUI("keditbookmarks-genui.rc");
238 connect(qApp->clipboard(), SIGNAL( dataChanged() ),
239 SLOT( slotClipboardDataChanged() ));
241 KGlobal::locale()->insertCatalog("libkonq");
243 m_canPaste = false;
245 CurrentMgr::self()->createManager(m_bookmarksFilename, m_dbusObjectName);
247 mBookmarkListView = new BookmarkListView();
248 mBookmarkListView->setModel( CurrentMgr::self()->model() );
249 mBookmarkListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
250 mBookmarkListView->loadColumnSetting();
252 KViewSearchLineWidget *searchline = new KViewSearchLineWidget(mBookmarkListView);
254 mBookmarkFolderView = new BookmarkFolderView(mBookmarkListView);
257 QWidget * rightSide = new QWidget;
258 QVBoxLayout *listLayout = new QVBoxLayout(rightSide);
259 rightSide->setLayout(listLayout);
260 listLayout->addWidget(searchline);
261 listLayout->addWidget(mBookmarkListView);
263 m_bkinfo = new BookmarkInfoWidget(mBookmarkListView);
265 listLayout->addWidget(m_bkinfo);
267 QSplitter *hsplitter = new QSplitter(this);
268 hsplitter->setOrientation(Qt::Horizontal);
269 hsplitter->addWidget(mBookmarkFolderView);
270 hsplitter->addWidget(rightSide);
271 hsplitter->setStretchFactor(1,1);
273 setCentralWidget(hsplitter);
275 mBookmarkListView->expandAll();
277 slotClipboardDataChanged();
278 setAutoSaveSettings();
280 connect(mBookmarkListView->selectionModel(), SIGNAL(selectionChanged( const QItemSelection &, const QItemSelection & )),
281 this, SLOT(selectionChanged()));
283 connect(mBookmarkFolderView->selectionModel(), SIGNAL(selectionChanged( const QItemSelection &, const QItemSelection & )),
284 this, SLOT(selectionChanged()));
286 setCancelFavIconUpdatesEnabled(false);
287 setCancelTestsEnabled(false);
288 updateActions();
291 void KEBApp::expandAll()
293 mBookmarkListView->expandAll();
296 void KEBApp::collapseAll()
298 mBookmarkListView->collapseAll();
301 QString KEBApp::bookmarkFilename()
303 return m_bookmarksFilename;
306 void KEBApp::reset(const QString & caption, const QString & bookmarksFileName)
308 //FIXME check this code, probably should be model()->setRoot instead of resetModel()
309 m_caption = caption;
310 m_bookmarksFilename = bookmarksFileName;
311 CurrentMgr::self()->createManager(m_bookmarksFilename, m_dbusObjectName); //FIXME this is still a memory leak (iff called by slotLoad)
312 CurrentMgr::self()->model()->resetModel();
313 mBookmarkListView->expandAll();
314 updateActions();
317 void KEBApp::startEdit( Column c )
319 const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
320 QModelIndexList::const_iterator it, end;
321 end = list.constEnd();
322 for(it = list.constBegin(); it != end; ++it)
323 if( (*it).column() == int(c) && (mBookmarkListView->model()->flags(*it) & Qt::ItemIsEditable) )
324 return mBookmarkListView->edit( *it );
327 //FIXME clean up and remove unneeded things
328 SelcAbilities KEBApp::getSelectionAbilities() const
330 SelcAbilities selctionAbilities;
331 selctionAbilities.itemSelected = false;
332 selctionAbilities.group = false;
333 selctionAbilities.separator = false;
334 selctionAbilities.urlIsEmpty = false;
335 selctionAbilities.root = false;
336 selctionAbilities.multiSelect = false;
337 selctionAbilities.singleSelect = false;
338 selctionAbilities.notEmpty = false;
339 selctionAbilities.deleteEnabled = false;
341 KBookmark nbk;
342 QModelIndexList sel = mBookmarkListView->selectionModel()->selectedIndexes();
343 int columnCount;
344 if(sel.count())
346 nbk = mBookmarkListView->bookmarkForIndex(sel.first());
347 columnCount = mBookmarkListView->model()->columnCount();
349 else
351 sel = mBookmarkFolderView->selectionModel()->selectedIndexes();
352 if(sel.count())
353 nbk = mBookmarkFolderView->bookmarkForIndex(sel.first());
354 columnCount = mBookmarkFolderView->model()->columnCount();
357 if ( sel.count() > 0)
359 selctionAbilities.deleteEnabled = true;
360 selctionAbilities.itemSelected = true;
361 selctionAbilities.group = nbk.isGroup();
362 selctionAbilities.separator = nbk.isSeparator();
363 selctionAbilities.urlIsEmpty = nbk.url().isEmpty();
364 selctionAbilities.root = nbk.address() == CurrentMgr::self()->root().address();
365 selctionAbilities.multiSelect = (sel.count() > columnCount);
366 selctionAbilities.singleSelect = (!selctionAbilities.multiSelect && selctionAbilities.itemSelected);
368 //FIXME check next line, if it actually works
369 selctionAbilities.notEmpty = CurrentMgr::self()->root().first().hasParent();
371 /* kDebug()
372 <<"\nsa.itemSelected "<<selctionAbilities.itemSelected
373 <<"\nsa.group "<<selctionAbilities.group
374 <<"\nsa.separator "<<selctionAbilities.separator
375 <<"\nsa.urlIsEmpty "<<selctionAbilities.urlIsEmpty
376 <<"\nsa.root "<<selctionAbilities.root
377 <<"\nsa.multiSelect "<<selctionAbilities.multiSelect
378 <<"\nsa.singleSelect "<<selctionAbilities.singleSelect
379 <<"\nsa.deleteEnabled"<<selctionAbilities.deleteEnabled
380 <<endl;
382 return selctionAbilities;
385 void KEBApp::setActionsEnabled(SelcAbilities sa) {
386 KActionCollection * coll = actionCollection();
388 QStringList toEnable;
390 if (sa.multiSelect || (sa.singleSelect && !sa.root))
391 toEnable << "edit_copy";
393 if (sa.multiSelect || (sa.singleSelect && !sa.root && !sa.urlIsEmpty && !sa.group && !sa.separator))
394 toEnable << "openlink";
396 if (!m_readOnly) {
397 if (sa.notEmpty)
398 toEnable << "testall" << "updateallfavicons";
400 if ( sa.deleteEnabled && (sa.multiSelect || (sa.singleSelect && !sa.root)) )
401 toEnable << "delete" << "edit_cut";
403 if( sa.singleSelect)
404 if (m_canPaste)
405 toEnable << "edit_paste";
407 if( sa.multiSelect || (sa.singleSelect && !sa.root && !sa.urlIsEmpty && !sa.group && !sa.separator))
408 toEnable << "testlink" << "updatefavicon";
410 if (sa.singleSelect && !sa.root && !sa.separator) {
411 toEnable << "rename" << "changeicon" << "changecomment";
412 if (!sa.group)
413 toEnable << "changeurl";
416 if (sa.singleSelect) {
417 toEnable << "newfolder" << "newbookmark" << "insertseparator";
418 if (sa.group)
419 toEnable << "sort" << "recursivesort" << "setastoolbar";
423 for ( QStringList::const_iterator it = toEnable.constBegin();
424 it != toEnable.constEnd(); ++it )
426 //kDebug() <<" enabling action "<<(*it);
427 coll->action((*it).toAscii().data())->setEnabled(true);
431 KBookmark KEBApp::firstSelected() const
433 QModelIndex index;
434 const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
435 if(list.count()) // selection in main listview, return bookmark for firstSelected
436 return mBookmarkListView->bookmarkForIndex(*list.constBegin());
438 // no selection in main listview, fall back to selection in left tree
439 const QModelIndexList & list2 = mBookmarkFolderView->selectionModel()->selectedIndexes();
440 return mBookmarkFolderView->bookmarkForIndex(*list2.constBegin());
443 QString KEBApp::insertAddress() const
445 KBookmark current = firstSelected();
446 return (current.isGroup())
447 ? (current.address() + "/0") //FIXME internal represantation used
448 : KBookmark::nextAddress(current.address());
451 bool lessAddress(const QString& first, const QString& second)
453 QString a = first;
454 QString b = second;
456 if(a == b)
457 return false;
459 QString error("ERROR");
460 if(a == error)
461 return false;
462 if(b == error)
463 return true;
465 a += '/';
466 b += '/';
468 uint aLast = 0;
469 uint bLast = 0;
470 uint aEnd = a.length();
471 uint bEnd = b.length();
472 // Each iteration checks one "/"-delimeted part of the address
473 // "" is treated correctly
474 while(true)
476 // Invariant: a[0 ... aLast] == b[0 ... bLast]
477 if(aLast + 1 == aEnd) //The last position was the last slash
478 return true; // That means a is shorter than b
479 if(bLast +1 == bEnd)
480 return false;
482 uint aNext = a.indexOf("/", aLast + 1);
483 uint bNext = b.indexOf("/", bLast + 1);
485 bool okay;
486 uint aNum = a.mid(aLast + 1, aNext - aLast - 1).toUInt(&okay);
487 if(!okay)
488 return false;
489 uint bNum = b.mid(bLast + 1, bNext - bLast - 1).toUInt(&okay);
490 if(!okay)
491 return true;
493 if(aNum != bNum)
494 return aNum < bNum;
496 aLast = aNext;
497 bLast = bNext;
501 bool lessBookmark(const KBookmark & first, const KBookmark & second) //FIXME Using internal represantation
503 return lessAddress(first.address(), second.address());
506 KBookmark::List KEBApp::allBookmarks() const
508 KBookmark::List bookmarks;
509 selectedBookmarksExpandedHelper(CurrentMgr::self()->root(), bookmarks);
510 return bookmarks;
513 KBookmark::List KEBApp::selectedBookmarks() const
515 KBookmark::List bookmarks;
516 const QModelIndexList & list = mBookmarkListView->selectionModel()->selectedIndexes();
517 if (!list.isEmpty()) {
518 QModelIndexList::const_iterator it, end;
519 end = list.constEnd();
520 for( it = list.constBegin(); it != end; ++it) {
521 if((*it).column() != 0)
522 continue;
523 KBookmark bk = mBookmarkListView->bookmarkModel()->bookmarkForIndex(*it);;
524 if(bk.address() != CurrentMgr::self()->root().address())
525 bookmarks.push_back( bk );
527 qSort(bookmarks.begin(), bookmarks.end(), lessBookmark);
528 } else {
529 bookmarks.push_back(firstSelected());
532 return bookmarks;
535 KBookmark::List KEBApp::selectedBookmarksExpanded() const
537 KBookmark::List bookmarks = selectedBookmarks();
538 KBookmark::List result;
539 KBookmark::List::const_iterator it, end;
540 end = bookmarks.constEnd();
541 for(it = bookmarks.constBegin(); it != end; ++it)
543 selectedBookmarksExpandedHelper( *it, result );
545 return result;
548 void KEBApp::selectedBookmarksExpandedHelper(const KBookmark& bk, KBookmark::List & bookmarks) const
550 //FIXME in which order parents should ideally be: parent then child
551 // or child and then parents
552 if(bk.isGroup())
554 KBookmarkGroup parent = bk.toGroup();
555 KBookmark child = parent.first();
556 while(!child.isNull())
558 selectedBookmarksExpandedHelper(child, bookmarks);
559 child = parent.next(child);
562 else
564 bookmarks.push_back( bk );
568 void KEBApp::updateStatus(const QString &url)
570 if(m_bkinfo->bookmark().url() == url)
571 m_bkinfo->updateStatus();
574 KEBApp::~KEBApp() {
575 s_topLevel = 0;
576 delete m_cmdHistory;
577 delete ActionsImpl::self();
578 delete mBookmarkListView;
579 delete CurrentMgr::self();
582 KToggleAction* KEBApp::getToggleAction(const char *action) const {
583 return static_cast<KToggleAction*>(actionCollection()->action(action));
586 void KEBApp::resetActions() {
587 stateChanged("disablestuff");
588 stateChanged("normal");
590 if (!m_readOnly)
591 stateChanged("notreadonly");
594 void KEBApp::selectionChanged()
596 updateActions();
599 void KEBApp::updateActions() {
600 resetActions();
601 setActionsEnabled(getSelectionAbilities());
604 void KEBApp::slotClipboardDataChanged() {
605 // kDebug() << "KEBApp::slotClipboardDataChanged";
606 if (!m_readOnly) {
607 m_canPaste = KBookmark::List::canDecode(
608 QApplication::clipboard()->mimeData());
609 updateActions();
613 /* -------------------------- */
615 void KEBApp::notifyCommandExecuted() {
616 // kDebug() << "KEBApp::notifyCommandExecuted()";
617 updateActions();
620 /* -------------------------- */
622 void KEBApp::slotConfigureToolbars() {
623 saveMainWindowSettings(KConfigGroup( KGlobal::config(), "MainWindow") );
624 KEditToolBar dlg(actionCollection(), this);
625 connect(&dlg, SIGNAL( newToolBarConfig() ),
626 SLOT( slotNewToolbarConfig() ));
627 dlg.exec();
630 void KEBApp::slotNewToolbarConfig() {
631 // called when OK or Apply is clicked
632 createGUI();
633 applyMainWindowSettings(KConfigGroup(KGlobal::config(), "MainWindow") );
636 /* -------------------------- */
638 #include "toplevel.moc"