File indexing completed on 2024-04-21 05:50:23
0001 /* This file is part of the KDE project 0002 Copyright (C) 2000 David Faure <faure@kde.org> 0003 Copyright (C) 2002-2003 Alexander Kellett <lypanov@kde.org> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU General Public 0007 License version 2 or at your option version 3 as published by 0008 the Free Software Foundation. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; see the file COPYING. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "toplevel.h" 0022 #include "globalbookmarkmanager.h" 0023 #include <QVBoxLayout> 0024 0025 #include "kbookmarkmodel/model.h" 0026 0027 #include "actionsimpl.h" 0028 #include "bookmarkinfowidget.h" 0029 #include "kbookmarkmodel/commandhistory.h" 0030 #include "kebsearchline.h" 0031 0032 #include <stdlib.h> 0033 0034 #include <QApplication> 0035 #include <QClipboard> 0036 #include <QSplitter> 0037 0038 #include <KActionCollection> 0039 #include <KConfigGroup> 0040 #include <KEditToolBar> 0041 #include <KLocalizedString> 0042 #include <KMessageBox> 0043 #include <KSharedConfig> 0044 0045 #include <QDBusConnection> 0046 KEBApp *KEBApp::s_topLevel = nullptr; 0047 0048 KEBApp::KEBApp(const QString &bookmarksFile, bool readonly, const QString &address, bool browser, const QString &caption, const QString &dbusObjectName) 0049 : KXmlGuiWindow() 0050 , m_bookmarksFilename(bookmarksFile) 0051 , m_caption(caption) 0052 , m_dbusObjectName(dbusObjectName) 0053 , m_readOnly(readonly) 0054 , m_browser(browser) 0055 { 0056 QDBusConnection::sessionBus().registerObject(QStringLiteral("/keditbookmarks"), this, QDBusConnection::ExportScriptableSlots); 0057 Q_UNUSED(address); // FIXME sets the current item 0058 0059 m_cmdHistory = new CommandHistory(this); 0060 m_cmdHistory->createActions(actionCollection()); 0061 connect(m_cmdHistory, &CommandHistory::notifyCommandExecuted, this, &KEBApp::notifyCommandExecuted); 0062 0063 GlobalBookmarkManager::self()->createManager(m_bookmarksFilename, m_dbusObjectName, m_cmdHistory); 0064 connect(GlobalBookmarkManager::self(), &GlobalBookmarkManager::error, this, &KEBApp::slotManagerError); 0065 0066 s_topLevel = this; 0067 0068 createActions(); 0069 if (m_browser) 0070 createGUI(); 0071 else 0072 createGUI(QStringLiteral("keditbookmarks-genui.rc")); 0073 0074 connect(qApp->clipboard(), &QClipboard::dataChanged, this, &KEBApp::slotClipboardDataChanged); 0075 0076 m_canPaste = false; 0077 0078 mBookmarkListView = new BookmarkListView(); 0079 mBookmarkListView->setModel(GlobalBookmarkManager::self()->model()); 0080 mBookmarkListView->setSelectionMode(QAbstractItemView::ExtendedSelection); 0081 mBookmarkListView->loadColumnSetting(); 0082 mBookmarkListView->loadFoldedState(); 0083 0084 KViewSearchLineWidget *searchline = new KViewSearchLineWidget(mBookmarkListView, this); 0085 0086 mBookmarkFolderView = new BookmarkFolderView(mBookmarkListView, this); 0087 mBookmarkFolderView->expandAll(); 0088 0089 QWidget *rightSide = new QWidget; 0090 QVBoxLayout *listLayout = new QVBoxLayout(rightSide); 0091 listLayout->setContentsMargins(0, 0, 0, 0); 0092 listLayout->addWidget(searchline); 0093 listLayout->addWidget(mBookmarkListView); 0094 0095 m_bkinfo = new BookmarkInfoWidget(mBookmarkListView, GlobalBookmarkManager::self()->model()); 0096 0097 listLayout->addWidget(m_bkinfo); 0098 0099 QSplitter *hsplitter = new QSplitter(this); 0100 hsplitter->setOrientation(Qt::Horizontal); 0101 hsplitter->addWidget(mBookmarkFolderView); 0102 hsplitter->addWidget(rightSide); 0103 hsplitter->setStretchFactor(1, 1); 0104 0105 setCentralWidget(hsplitter); 0106 0107 slotClipboardDataChanged(); 0108 setAutoSaveSettings(); 0109 0110 connect(mBookmarkListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KEBApp::selectionChanged); 0111 0112 connect(mBookmarkFolderView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KEBApp::selectionChanged); 0113 0114 setCancelFavIconUpdatesEnabled(false); 0115 setCancelTestsEnabled(false); 0116 updateActions(); 0117 } 0118 0119 void KEBApp::expandAll() 0120 { 0121 mBookmarkListView->expandAll(); 0122 } 0123 0124 void KEBApp::collapseAll() 0125 { 0126 mBookmarkListView->collapseAll(); 0127 } 0128 0129 QString KEBApp::bookmarkFilename() 0130 { 0131 return m_bookmarksFilename; 0132 } 0133 0134 void KEBApp::reset(const QString &caption, const QString &bookmarksFileName) 0135 { 0136 // FIXME check this code, probably should be model()->setRoot instead of resetModel() 0137 m_caption = caption; 0138 m_bookmarksFilename = bookmarksFileName; 0139 GlobalBookmarkManager::self()->createManager(m_bookmarksFilename, 0140 m_dbusObjectName, 0141 m_cmdHistory); // FIXME this is still a memory leak (iff called by slotLoad) 0142 GlobalBookmarkManager::self()->model()->resetModel(); 0143 updateActions(); 0144 } 0145 0146 void KEBApp::startEdit(Column c) 0147 { 0148 const QModelIndexList &list = mBookmarkListView->selectionModel()->selectedIndexes(); 0149 QModelIndexList::const_iterator it, end; 0150 end = list.constEnd(); 0151 for (it = list.constBegin(); it != end; ++it) 0152 if ((*it).column() == int(c) && (mBookmarkListView->model()->flags(*it) & Qt::ItemIsEditable)) 0153 mBookmarkListView->edit(*it); 0154 } 0155 0156 // FIXME clean up and remove unneeded things 0157 SelcAbilities KEBApp::getSelectionAbilities() const 0158 { 0159 SelcAbilities selctionAbilities; 0160 selctionAbilities.itemSelected = false; 0161 selctionAbilities.group = false; 0162 selctionAbilities.separator = false; 0163 selctionAbilities.urlIsEmpty = false; 0164 selctionAbilities.root = false; 0165 selctionAbilities.multiSelect = false; 0166 selctionAbilities.singleSelect = false; 0167 selctionAbilities.notEmpty = false; 0168 selctionAbilities.deleteEnabled = false; 0169 0170 KBookmark nbk; 0171 QModelIndexList sel = mBookmarkListView->selectionModel()->selectedIndexes(); 0172 int columnCount; 0173 if (sel.count()) { 0174 nbk = mBookmarkListView->bookmarkForIndex(sel.first()); 0175 columnCount = mBookmarkListView->model()->columnCount(); 0176 } else { 0177 sel = mBookmarkFolderView->selectionModel()->selectedIndexes(); 0178 if (sel.count()) 0179 nbk = mBookmarkFolderView->bookmarkForIndex(sel.first()); 0180 columnCount = mBookmarkFolderView->model()->columnCount(); 0181 } 0182 0183 if (sel.count() > 0) { 0184 selctionAbilities.deleteEnabled = true; 0185 selctionAbilities.itemSelected = true; 0186 selctionAbilities.group = nbk.isGroup(); 0187 selctionAbilities.separator = nbk.isSeparator(); 0188 selctionAbilities.urlIsEmpty = nbk.url().isEmpty(); 0189 selctionAbilities.root = nbk.address() == GlobalBookmarkManager::self()->root().address(); 0190 selctionAbilities.multiSelect = (sel.count() > columnCount); 0191 selctionAbilities.singleSelect = (!selctionAbilities.multiSelect && selctionAbilities.itemSelected); 0192 } 0193 // FIXME check next line, if it actually works 0194 selctionAbilities.notEmpty = GlobalBookmarkManager::self()->root().first().hasParent(); 0195 0196 /* //qCDebug(KEDITBOOKMARKS_LOG) 0197 <<"\nsa.itemSelected "<<selctionAbilities.itemSelected 0198 <<"\nsa.group "<<selctionAbilities.group 0199 <<"\nsa.separator "<<selctionAbilities.separator 0200 <<"\nsa.urlIsEmpty "<<selctionAbilities.urlIsEmpty 0201 <<"\nsa.root "<<selctionAbilities.root 0202 <<"\nsa.multiSelect "<<selctionAbilities.multiSelect 0203 <<"\nsa.singleSelect "<<selctionAbilities.singleSelect 0204 <<"\nsa.deleteEnabled"<<selctionAbilities.deleteEnabled; 0205 */ 0206 return selctionAbilities; 0207 } 0208 0209 void KEBApp::setActionsEnabled(SelcAbilities sa) 0210 { 0211 KActionCollection *coll = actionCollection(); 0212 0213 QStringList toEnable; 0214 0215 if (sa.multiSelect || (sa.singleSelect && !sa.root)) 0216 toEnable << QStringLiteral("edit_copy"); 0217 0218 if (sa.multiSelect || (sa.singleSelect && !sa.root && !sa.urlIsEmpty && !sa.group && !sa.separator)) 0219 toEnable << QStringLiteral("openlink"); 0220 0221 if (!m_readOnly) { 0222 if (sa.notEmpty) 0223 toEnable << QStringLiteral("testall") << QStringLiteral("updateallfavicons"); 0224 0225 if (sa.deleteEnabled && (sa.multiSelect || (sa.singleSelect && !sa.root))) 0226 toEnable << QStringLiteral("delete") << QStringLiteral("edit_cut"); 0227 0228 if (sa.singleSelect) 0229 if (m_canPaste) 0230 toEnable << QStringLiteral("edit_paste"); 0231 0232 if (sa.multiSelect || (sa.singleSelect && !sa.root && !sa.urlIsEmpty && !sa.group && !sa.separator)) 0233 toEnable << QStringLiteral("testlink") << QStringLiteral("updatefavicon"); 0234 0235 if (sa.singleSelect && !sa.root && !sa.separator) { 0236 toEnable << QStringLiteral("rename") << QStringLiteral("changeicon") << QStringLiteral("changecomment"); 0237 if (!sa.group) 0238 toEnable << QStringLiteral("changeurl"); 0239 } 0240 0241 if (sa.singleSelect) { 0242 toEnable << QStringLiteral("newfolder") << QStringLiteral("newbookmark") << QStringLiteral("insertseparator"); 0243 if (sa.group) 0244 toEnable << QStringLiteral("sort") << QStringLiteral("recursivesort") << QStringLiteral("setastoolbar"); 0245 } 0246 } 0247 0248 for (QStringList::const_iterator it = toEnable.constBegin(); it != toEnable.constEnd(); ++it) { 0249 ////qCDebug(KEDITBOOKMARKS_LOG) <<" enabling action "<<(*it); 0250 coll->action(*it)->setEnabled(true); 0251 } 0252 } 0253 0254 KBookmark KEBApp::firstSelected() const 0255 { 0256 const QModelIndexList &list = mBookmarkListView->selectionModel()->selectedIndexes(); 0257 if (list.count()) // selection in main listview, return bookmark for firstSelected 0258 return mBookmarkListView->bookmarkForIndex(*list.constBegin()); 0259 0260 // no selection in main listview, fall back to selection in left tree 0261 const QModelIndexList &list2 = mBookmarkFolderView->selectionModel()->selectedIndexes(); 0262 return mBookmarkFolderView->bookmarkForIndex(*list2.constBegin()); 0263 } 0264 0265 QString KEBApp::insertAddress() const 0266 { 0267 KBookmark current = firstSelected(); 0268 return (current.isGroup()) ? (current.address() + QStringLiteral("/0")) // FIXME internal representation used 0269 : KBookmark::nextAddress(current.address()); 0270 } 0271 0272 static bool lessAddress(const QString &first, const QString &second) 0273 { 0274 QString a = first; 0275 QString b = second; 0276 0277 if (a == b) 0278 return false; 0279 0280 QString error(QStringLiteral("ERROR")); 0281 if (a == error) 0282 return false; 0283 if (b == error) 0284 return true; 0285 0286 a += QLatin1Char('/'); 0287 b += QLatin1Char('/'); 0288 0289 uint aLast = 0; 0290 uint bLast = 0; 0291 uint aEnd = a.length(); 0292 uint bEnd = b.length(); 0293 // Each iteration checks one "/"-delimeted part of the address 0294 // "" is treated correctly 0295 while (true) { 0296 // Invariant: a[0 ... aLast] == b[0 ... bLast] 0297 if (aLast + 1 == aEnd) // The last position was the last slash 0298 return true; // That means a is shorter than b 0299 if (bLast + 1 == bEnd) 0300 return false; 0301 0302 uint aNext = a.indexOf(QLatin1String("/"), aLast + 1); 0303 uint bNext = b.indexOf(QLatin1String("/"), bLast + 1); 0304 0305 bool okay; 0306 uint aNum = QStringView(a).mid(aLast + 1, aNext - aLast - 1).toUInt(&okay); 0307 if (!okay) 0308 return false; 0309 uint bNum = QStringView(b).mid(bLast + 1, bNext - bLast - 1).toUInt(&okay); 0310 if (!okay) 0311 return true; 0312 0313 if (aNum != bNum) 0314 return aNum < bNum; 0315 0316 aLast = aNext; 0317 bLast = bNext; 0318 } 0319 } 0320 0321 static bool lessBookmark(const KBookmark &first, const KBookmark &second) // FIXME Using internal represantation 0322 { 0323 return lessAddress(first.address(), second.address()); 0324 } 0325 0326 KBookmark::List KEBApp::allBookmarks() const 0327 { 0328 KBookmark::List bookmarks; 0329 selectedBookmarksExpandedHelper(GlobalBookmarkManager::self()->root(), bookmarks); 0330 return bookmarks; 0331 } 0332 0333 KBookmark::List KEBApp::selectedBookmarks() const 0334 { 0335 KBookmark::List bookmarks; 0336 const QModelIndexList &list = mBookmarkListView->selectionModel()->selectedIndexes(); 0337 if (!list.isEmpty()) { 0338 QModelIndexList::const_iterator it, end; 0339 end = list.constEnd(); 0340 for (it = list.constBegin(); it != end; ++it) { 0341 if ((*it).column() != 0) 0342 continue; 0343 KBookmark bk = mBookmarkListView->bookmarkModel()->bookmarkForIndex(*it); 0344 ; 0345 if (bk.address() != GlobalBookmarkManager::self()->root().address()) 0346 bookmarks.push_back(bk); 0347 } 0348 std::sort(bookmarks.begin(), bookmarks.end(), lessBookmark); 0349 } else { 0350 bookmarks.push_back(firstSelected()); 0351 } 0352 0353 return bookmarks; 0354 } 0355 0356 KBookmark::List KEBApp::selectedBookmarksExpanded() const 0357 { 0358 KBookmark::List bookmarks = selectedBookmarks(); 0359 KBookmark::List result; 0360 KBookmark::List::const_iterator it, end; 0361 end = bookmarks.constEnd(); 0362 for (it = bookmarks.constBegin(); it != end; ++it) { 0363 selectedBookmarksExpandedHelper(*it, result); 0364 } 0365 return result; 0366 } 0367 0368 void KEBApp::selectedBookmarksExpandedHelper(const KBookmark &bk, KBookmark::List &bookmarks) const 0369 { 0370 // FIXME in which order parents should ideally be: parent then child 0371 // or child and then parents 0372 if (bk.isGroup()) { 0373 KBookmarkGroup parent = bk.toGroup(); 0374 KBookmark child = parent.first(); 0375 while (!child.isNull()) { 0376 selectedBookmarksExpandedHelper(child, bookmarks); 0377 child = parent.next(child); 0378 } 0379 } else { 0380 bookmarks.push_back(bk); 0381 } 0382 } 0383 0384 KEBApp::~KEBApp() 0385 { 0386 // Save again, just in case the user expanded/collapsed folders (#131127) 0387 GlobalBookmarkManager::self()->notifyManagers(); 0388 0389 s_topLevel = nullptr; 0390 delete m_cmdHistory; 0391 delete m_actionsImpl; 0392 delete mBookmarkListView; 0393 delete GlobalBookmarkManager::self(); 0394 } 0395 0396 void KEBApp::resetActions() 0397 { 0398 stateChanged(QStringLiteral("disablestuff")); 0399 stateChanged(QStringLiteral("normal")); 0400 0401 if (!m_readOnly) 0402 stateChanged(QStringLiteral("notreadonly")); 0403 } 0404 0405 void KEBApp::selectionChanged() 0406 { 0407 updateActions(); 0408 } 0409 0410 void KEBApp::updateActions() 0411 { 0412 resetActions(); 0413 setActionsEnabled(getSelectionAbilities()); 0414 } 0415 0416 void KEBApp::slotClipboardDataChanged() 0417 { 0418 // //qCDebug(KEDITBOOKMARKS_LOG) << "KEBApp::slotClipboardDataChanged"; 0419 if (!m_readOnly) { 0420 m_canPaste = KBookmark::List::canDecode(QApplication::clipboard()->mimeData()); 0421 updateActions(); 0422 } 0423 } 0424 0425 /* -------------------------- */ 0426 0427 void KEBApp::notifyCommandExecuted() 0428 { 0429 // //qCDebug(KEDITBOOKMARKS_LOG) << "KEBApp::notifyCommandExecuted()"; 0430 updateActions(); 0431 } 0432 0433 /* -------------------------- */ 0434 0435 void KEBApp::slotConfigureToolbars() 0436 { 0437 // PORT TO QT5 saveMainWindowSettings(KConfigGroup( KSharedConfig::openConfig(), "MainWindow") ); 0438 KEditToolBar dlg(actionCollection(), this); 0439 connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KEBApp::slotNewToolbarConfig); 0440 dlg.exec(); 0441 } 0442 0443 void KEBApp::slotNewToolbarConfig() 0444 { 0445 // called when OK or Apply is clicked 0446 createGUI(); 0447 applyMainWindowSettings(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("MainWindow"))); 0448 } 0449 0450 void KEBApp::slotManagerError(const QString &errorMessage) 0451 { 0452 KMessageBox::error(this, errorMessage); 0453 } 0454 0455 /* -------------------------- */ 0456 0457 #include "moc_toplevel.cpp"