File indexing completed on 2024-05-05 04:19:20
0001 // vim: set tabstop=4 shiftwidth=4 expandtab: 0002 /* 0003 Gwenview: an image viewer 0004 Copyright 2008 Aurélien Gâteau <agateau@kde.org> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License 0008 as published by the Free Software Foundation; either version 2 0009 of the License, or (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. 0019 0020 */ 0021 // Self 0022 #include "startmainpage.h" 0023 #include <config-gwenview.h> 0024 0025 // Qt 0026 #include <QListView> 0027 #include <QMenu> 0028 0029 #ifdef GTK_WORKAROUND_BROKE_IN_KF5_PORT 0030 #include <QPlastiqueStyle> 0031 #endif 0032 0033 #include <QIcon> 0034 #include <QStyledItemDelegate> 0035 0036 // KF 0037 #include <KFilePlacesModel> 0038 #include <KLocalizedString> 0039 0040 // Local 0041 #include "gwenview_app_debug.h" 0042 #include <gvcore.h> 0043 #include <lib/dialogguard.h> 0044 #include <lib/flowlayout.h> 0045 #include <lib/gvdebug.h> 0046 #include <lib/gwenviewconfig.h> 0047 #include <lib/scrollerutils.h> 0048 #include <lib/thumbnailprovider/thumbnailprovider.h> 0049 #include <lib/thumbnailview/abstractthumbnailviewhelper.h> 0050 #include <lib/thumbnailview/previewitemdelegate.h> 0051 #include <ui_startmainpage.h> 0052 0053 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE 0054 #include <lib/semanticinfo/tagmodel.h> 0055 #endif 0056 0057 namespace Gwenview 0058 { 0059 class HistoryThumbnailViewHelper : public AbstractThumbnailViewHelper 0060 { 0061 public: 0062 HistoryThumbnailViewHelper(QObject *parent) 0063 : AbstractThumbnailViewHelper(parent) 0064 { 0065 } 0066 0067 void showContextMenu(QWidget *) override 0068 { 0069 } 0070 0071 void showMenuForUrlDroppedOnViewport(QWidget *, const QList<QUrl> &) override 0072 { 0073 } 0074 0075 void showMenuForUrlDroppedOnDir(QWidget *, const QList<QUrl> &, const QUrl &) override 0076 { 0077 } 0078 }; 0079 0080 struct StartMainPagePrivate : public Ui_StartMainPage { 0081 StartMainPage *q = nullptr; 0082 GvCore *mGvCore = nullptr; 0083 KFilePlacesModel *mBookmarksModel = nullptr; 0084 ThumbnailProvider *mRecentFilesThumbnailProvider = nullptr; 0085 bool mSearchUiInitialized; 0086 0087 void setupSearchUi() 0088 { 0089 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_BALOO 0090 mTagView->setModel(TagModel::createAllTagsModel(mTagView, mGvCore->semanticInfoBackEnd())); 0091 mTagView->show(); 0092 mTagLabel->hide(); 0093 #else 0094 mTagView->hide(); 0095 mTagLabel->hide(); 0096 #endif 0097 } 0098 0099 void updateHistoryTab() 0100 { 0101 mHistoryWidget->setVisible(GwenviewConfig::historyEnabled()); 0102 mHistoryDisabledLabel->setVisible(!GwenviewConfig::historyEnabled()); 0103 } 0104 0105 void setupHistoryView(ThumbnailView *view) 0106 { 0107 view->setThumbnailViewHelper(new HistoryThumbnailViewHelper(view)); 0108 auto delegate = new PreviewItemDelegate(view); 0109 delegate->setContextBarActions(PreviewItemDelegate::NoAction); 0110 delegate->setTextElideMode(Qt::ElideLeft); 0111 view->setItemDelegate(delegate); 0112 view->setThumbnailWidth(128); 0113 view->setCreateThumbnailsForRemoteUrls(false); 0114 QModelIndex index = view->model()->index(0, 0); 0115 if (index.isValid()) { 0116 view->setCurrentIndex(index); 0117 } 0118 } 0119 }; 0120 0121 static void initViewPalette(QAbstractItemView *view, const QColor &fgColor) 0122 { 0123 QWidget *viewport = view->viewport(); 0124 QPalette palette = viewport->palette(); 0125 palette.setColor(viewport->backgroundRole(), Qt::transparent); 0126 palette.setColor(QPalette::WindowText, fgColor); 0127 palette.setColor(QPalette::Text, fgColor); 0128 0129 // QListView uses QStyledItemDelegate, which uses the view palette for 0130 // foreground color, while KFilePlacesView uses the viewport palette. 0131 viewport->setPalette(palette); 0132 view->setPalette(palette); 0133 } 0134 0135 static bool styleIsGtkBased() 0136 { 0137 const char *name = QApplication::style()->metaObject()->className(); 0138 return qstrcmp(name, "QGtkStyle") == 0; 0139 } 0140 0141 StartMainPage::StartMainPage(QWidget *parent, GvCore *gvCore) 0142 : QFrame(parent) 0143 , d(new StartMainPagePrivate) 0144 { 0145 d->mRecentFilesThumbnailProvider = nullptr; 0146 d->q = this; 0147 d->mGvCore = gvCore; 0148 d->mSearchUiInitialized = false; 0149 0150 d->setupUi(this); 0151 if (styleIsGtkBased()) { 0152 #ifdef GTK_WORKAROUND_BROKE_IN_KF5_PORT 0153 0154 // Gtk-based styles do not apply the correct background color on tabs. 0155 // As a workaround, use the Plastique style instead. 0156 QStyle *fix = new QPlastiqueStyle(); 0157 fix->setParent(this); 0158 d->mHistoryWidget->tabBar()->setStyle(fix); 0159 d->mPlacesTagsWidget->tabBar()->setStyle(fix); 0160 #endif 0161 } 0162 setFrameStyle(QFrame::NoFrame); 0163 0164 // Bookmark view 0165 d->mBookmarksModel = new KFilePlacesModel(this); 0166 0167 d->mBookmarksView->setModel(d->mBookmarksModel); 0168 d->mBookmarksView->setAutoResizeItemsEnabled(false); 0169 0170 connect(d->mBookmarksView, &KFilePlacesView::urlChanged, this, &StartMainPage::urlSelected); 0171 0172 // Tag view 0173 connect(d->mTagView, &QListView::clicked, this, &StartMainPage::slotTagViewClicked); 0174 0175 // Recent folders view 0176 connect(d->mRecentFoldersView, &Gwenview::ThumbnailView::indexActivated, this, &StartMainPage::slotListViewActivated); 0177 connect(d->mRecentFoldersView, &Gwenview::ThumbnailView::customContextMenuRequested, this, &StartMainPage::showContextMenu); 0178 0179 // Recent files view 0180 connect(d->mRecentFilesView, &Gwenview::ThumbnailView::indexActivated, this, &StartMainPage::slotListViewActivated); 0181 connect(d->mRecentFilesView, &Gwenview::ThumbnailView::customContextMenuRequested, this, &StartMainPage::showContextMenu); 0182 0183 d->updateHistoryTab(); 0184 connect(GwenviewConfig::self(), &GwenviewConfig::configChanged, this, &StartMainPage::loadConfig); 0185 0186 connect(qApp, &QApplication::paletteChanged, this, [this]() { 0187 applyPalette(d->mGvCore->palette(GvCore::NormalViewPalette)); 0188 }); 0189 0190 d->mRecentFoldersView->setFocus(); 0191 0192 ScrollerUtils::setQScroller(d->mBookmarksView->viewport()); 0193 d->mBookmarksView->viewport()->installEventFilter(this); 0194 } 0195 0196 StartMainPage::~StartMainPage() 0197 { 0198 delete d->mRecentFilesThumbnailProvider; 0199 delete d; 0200 } 0201 0202 bool StartMainPage::eventFilter(QObject *, QEvent *event) 0203 { 0204 if (event->type() == QEvent::MouseMove) { 0205 auto mouseEvent = static_cast<QMouseEvent *>(event); 0206 if (mouseEvent->source() == Qt::MouseEventSynthesizedByQt) { 0207 return true; 0208 } 0209 } 0210 return false; 0211 } 0212 0213 void StartMainPage::slotTagViewClicked(const QModelIndex &index) 0214 { 0215 #ifdef GWENVIEW_SEMANTICINFO_BACKEND_BALOO 0216 if (!index.isValid()) { 0217 return; 0218 } 0219 // FIXME: Check label encoding 0220 const QString tag = index.data().toString(); 0221 Q_EMIT urlSelected(QUrl("tags:/" + tag)); 0222 #endif 0223 } 0224 0225 void StartMainPage::applyPalette(const QPalette &newPalette) 0226 { 0227 QColor fgColor = newPalette.text().color(); 0228 0229 QPalette pal = palette(); 0230 pal.setBrush(backgroundRole(), newPalette.base()); 0231 pal.setBrush(QPalette::Button, newPalette.base()); 0232 pal.setBrush(QPalette::WindowText, fgColor); 0233 pal.setBrush(QPalette::ButtonText, fgColor); 0234 pal.setBrush(QPalette::Text, fgColor); 0235 setPalette(pal); 0236 0237 initViewPalette(d->mBookmarksView, fgColor); 0238 initViewPalette(d->mTagView, fgColor); 0239 initViewPalette(d->mRecentFoldersView, fgColor); 0240 initViewPalette(d->mRecentFilesView, fgColor); 0241 } 0242 0243 void StartMainPage::slotListViewActivated(const QModelIndex &index) 0244 { 0245 if (!index.isValid()) { 0246 return; 0247 } 0248 QVariant data = index.data(KFilePlacesModel::UrlRole); 0249 QUrl url = data.toUrl(); 0250 0251 // Prevent dir lister error 0252 if (!url.isValid()) { 0253 qCCritical(GWENVIEW_APP_LOG) << "Tried to open an invalid url"; 0254 return; 0255 } 0256 Q_EMIT urlSelected(url); 0257 } 0258 0259 void StartMainPage::showEvent(QShowEvent *event) 0260 { 0261 if (GwenviewConfig::historyEnabled()) { 0262 if (!d->mRecentFoldersView->model()) { 0263 d->mRecentFoldersView->setModel(d->mGvCore->recentFoldersModel()); 0264 d->setupHistoryView(d->mRecentFoldersView); 0265 } 0266 if (!d->mRecentFilesView->model()) { 0267 d->mRecentFilesView->setModel(d->mGvCore->recentFilesModel()); 0268 d->mRecentFilesThumbnailProvider = new ThumbnailProvider(); 0269 d->mRecentFilesView->setThumbnailProvider(d->mRecentFilesThumbnailProvider); 0270 d->setupHistoryView(d->mRecentFilesView); 0271 } 0272 } 0273 if (!d->mSearchUiInitialized) { 0274 d->mSearchUiInitialized = true; 0275 d->setupSearchUi(); 0276 } 0277 QFrame::showEvent(event); 0278 } 0279 0280 void StartMainPage::showContextMenu(const QPoint &pos) 0281 { 0282 // Create menu 0283 DialogGuard<QMenu> menu(this); 0284 0285 QAction *addAction = menu->addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), QString()); 0286 QAction *forgetAction = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), QString()); 0287 menu->addSeparator(); 0288 QAction *forgetAllAction = menu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete-all")), QString()); 0289 0290 if (d->mHistoryWidget->currentWidget() == d->mRecentFoldersTab) { 0291 addAction->setText(i18nc("@action Recent Folders view", "Add Folder to Places")); 0292 forgetAction->setText(i18nc("@action Recent Folders view", "Forget This Folder")); 0293 forgetAllAction->setText(i18nc("@action Recent Folders view", "Forget All Folders")); 0294 } else if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) { 0295 addAction->setText(i18nc("@action Recent Files view", "Add Containing Folder to Places")); 0296 forgetAction->setText(i18nc("@action Recent Files view", "Forget This File")); 0297 forgetAllAction->setText(i18nc("@action Recent Files view", "Forget All Files")); 0298 } else { 0299 GV_WARN_AND_RETURN("Context menu not implemented on this tab page"); 0300 } 0301 0302 const QAbstractItemView *view = qobject_cast<QAbstractItemView *>(sender()); 0303 const QModelIndex index = view->indexAt(pos); 0304 addAction->setEnabled(index.isValid()); 0305 forgetAction->setEnabled(index.isValid()); 0306 0307 // Handle menu 0308 const QAction *action = menu->exec(view->mapToGlobal(pos)); 0309 if (!action) { 0310 return; 0311 } 0312 0313 const QVariant data = index.data(KFilePlacesModel::UrlRole); 0314 QUrl url = data.toUrl(); 0315 if (action == addAction) { 0316 if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) { 0317 url = url.adjusted(QUrl::RemoveFilename); 0318 } 0319 QString text = url.adjusted(QUrl::StripTrailingSlash).fileName(); 0320 if (text.isEmpty()) { 0321 text = url.toDisplayString(); 0322 } 0323 d->mBookmarksModel->addPlace(text, url); 0324 } else if (action == forgetAction) { 0325 view->model()->removeRow(index.row()); 0326 if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) { 0327 Q_EMIT recentFileRemoved(url); 0328 } 0329 } else if (action == forgetAllAction) { 0330 view->model()->removeRows(0, view->model()->rowCount()); 0331 if (d->mHistoryWidget->currentWidget() == d->mRecentFilesTab) { 0332 Q_EMIT recentFilesCleared(); 0333 } 0334 } 0335 } 0336 0337 void StartMainPage::loadConfig() 0338 { 0339 d->updateHistoryTab(); 0340 applyPalette(d->mGvCore->palette(GvCore::NormalViewPalette)); 0341 } 0342 0343 ThumbnailView *StartMainPage::recentFoldersView() const 0344 { 0345 return d->mRecentFoldersView; 0346 } 0347 0348 } // namespace 0349 0350 #include "moc_startmainpage.cpp"