File indexing completed on 2025-01-19 03:59:16
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2004-11-22 0007 * Description : digiKam image editor - Internal setup 0008 * 0009 * SPDX-FileCopyrightText: 2004-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "imagewindow_p.h" 0016 0017 namespace Digikam 0018 { 0019 0020 void ImageWindow::setupActions() 0021 { 0022 setupStandardActions(); 0023 0024 KActionCollection* const ac = actionCollection(); 0025 0026 d->toMainWindowAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-icons")), 0027 i18nc("@action Finish editing, close editor, back to main window", "Close Editor"), this); 0028 connect(d->toMainWindowAction, SIGNAL(triggered()), this, SLOT(slotToMainWindow())); 0029 ac->addAction(QLatin1String("imageview_tomainwindow"), d->toMainWindowAction); 0030 0031 0032 // -- Special Delete actions --------------------------------------------------------------- 0033 0034 // Pop up dialog to ask user whether to permanently delete 0035 0036 d->fileDeletePermanentlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete File Permanently"), this); 0037 connect(d->fileDeletePermanentlyAction, SIGNAL(triggered()), 0038 this, SLOT(slotDeleteCurrentItemPermanently())); 0039 ac->addAction(QLatin1String("image_delete_permanently"), d->fileDeletePermanentlyAction); 0040 ac->setDefaultShortcut(d->fileDeletePermanentlyAction, Qt::SHIFT | Qt::Key_Delete); 0041 0042 // These two actions are hidden, no menu entry, no toolbar entry, no shortcut. 0043 // Power users may add them. 0044 0045 d->fileDeletePermanentlyDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), 0046 i18n("Delete Permanently without Confirmation"), this); 0047 connect(d->fileDeletePermanentlyDirectlyAction, SIGNAL(triggered()), 0048 this, SLOT(slotDeleteCurrentItemPermanentlyDirectly())); 0049 ac->addAction(QLatin1String("image_delete_permanently_directly"), 0050 d->fileDeletePermanentlyDirectlyAction); 0051 0052 d->fileTrashDirectlyAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash")), 0053 i18n("Move to Trash without Confirmation"), this); 0054 connect(d->fileTrashDirectlyAction, SIGNAL(triggered()), 0055 this, SLOT(slotTrashCurrentItemDirectly())); 0056 ac->addAction(QLatin1String("image_trash_directly"), d->fileTrashDirectlyAction); 0057 0058 // --------------------------------------------------------------------------------- 0059 0060 createHelpActions(QLatin1String("image_editor")); 0061 0062 // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. 0063 0064 TagsActionMngr::defaultManager()->registerLabelsActions(ac); 0065 0066 QAction* const editTitles = new QAction(i18n("Edit Titles"), this); 0067 ac->addAction(QLatin1String("edit_titles"), editTitles); 0068 ac->setDefaultShortcut(editTitles, Qt::ALT | Qt::SHIFT | Qt::Key_T); 0069 connect(editTitles, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateTitles())); 0070 0071 QAction* const editComments = new QAction(i18n("Edit Comments"), this); 0072 ac->addAction(QLatin1String("edit_comments"), editComments); 0073 ac->setDefaultShortcut(editComments, Qt::ALT | Qt::SHIFT | Qt::Key_C); 0074 connect(editComments, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateComments())); 0075 0076 QAction* const assignedTags = new QAction(i18n("Show Assigned Tags"), this); 0077 ac->addAction(QLatin1String("assigned_tags"), assignedTags); 0078 ac->setDefaultShortcut(assignedTags, Qt::ALT | Qt::SHIFT | Qt::Key_A); 0079 connect(assignedTags, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateAssignedTags())); 0080 } 0081 0082 void ImageWindow::setupConnections() 0083 { 0084 setupStandardConnections(); 0085 0086 connect(this, SIGNAL(loadCurrentLater()), 0087 this, SLOT(slotLoadCurrent()), Qt::QueuedConnection); 0088 0089 // To toggle properly keyboards shortcuts from comments & tags side bar tab. 0090 0091 connect(d->rightSideBar, SIGNAL(signalNextItem()), 0092 this, SLOT(slotForward())); 0093 0094 connect(d->rightSideBar, SIGNAL(signalPrevItem()), 0095 this, SLOT(slotBackward())); 0096 0097 connect(d->rightSideBar->getFiltersHistoryTab(), SIGNAL(actionTriggered(ItemInfo)), 0098 this, SLOT(openImage(ItemInfo))); 0099 0100 connect(this, SIGNAL(signalSelectionChanged(QRect)), 0101 d->rightSideBar, SLOT(slotImageSelectionChanged(QRect))); 0102 0103 connect(this, SIGNAL(signalNoCurrentItem()), 0104 d->rightSideBar, SLOT(slotNoCurrentItem())); 0105 0106 ItemAttributesWatch* watch = ItemAttributesWatch::instance(); 0107 0108 connect(watch, SIGNAL(signalFileMetadataChanged(QUrl)), 0109 this, SLOT(slotFileMetadataChanged(QUrl))); 0110 0111 /* 0112 connect(CoreDbAccess::databaseWatch(), SIGNAL(collectionImageChange(CollectionImageChangeset)), 0113 this, SLOT(slotCollectionImageChange(CollectionImageChangeset)), 0114 Qt::QueuedConnection); 0115 0116 connect(d->imageFilterModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), 0117 this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int))); 0118 */ 0119 0120 connect(d->thumbBar, SIGNAL(currentChanged(ItemInfo)), 0121 this, SLOT(slotThumbBarImageSelected(ItemInfo))); 0122 0123 connect(d->dragDropHandler, SIGNAL(itemInfosDropped(QList<ItemInfo>)), 0124 this, SLOT(slotDroppedOnThumbbar(QList<ItemInfo>))); 0125 0126 connect(d->thumbBarDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), 0127 d->thumbBar, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); 0128 0129 connect(d->imageInfoModel, SIGNAL(allRefreshingFinished()), 0130 this, SLOT(slotThumbBarModelReady())); 0131 0132 connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), 0133 this, SLOT(slotSetupChanged())); 0134 } 0135 0136 void ImageWindow::setupUserArea() 0137 { 0138 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0139 KConfigGroup group = config->group(configGroupName()); 0140 0141 QWidget* const widget = new QWidget(this); 0142 QHBoxLayout* const hlay = new QHBoxLayout(widget); 0143 m_splitter = new SidebarSplitter(widget); 0144 0145 d->viewContainer = new KMainWindow(widget, Qt::Widget); 0146 m_splitter->addWidget(d->viewContainer); 0147 m_stackView = new EditorStackView(d->viewContainer); 0148 m_canvas = new Canvas(m_stackView); 0149 d->viewContainer->setCentralWidget(m_stackView); 0150 0151 m_splitter->setFrameStyle(QFrame::NoFrame); 0152 m_splitter->setFrameShape(QFrame::NoFrame); 0153 m_splitter->setFrameShadow(QFrame::Plain); 0154 m_splitter->setStretchFactor(m_splitter->indexOf(d->viewContainer), 10); // set Canvas default size to max. 0155 m_splitter->setOpaqueResize(false); 0156 0157 m_canvas->makeDefaultEditingCanvas(); 0158 m_stackView->setCanvas(m_canvas); 0159 m_stackView->setViewMode(EditorStackView::CanvasMode); 0160 0161 d->rightSideBar = new ItemPropertiesSideBarDB(widget, m_splitter, Qt::RightEdge, true); 0162 d->rightSideBar->setObjectName(QLatin1String("ImageEditor Right Sidebar")); 0163 d->rightSideBar->getFiltersHistoryTab()->addOpenImageAction(); 0164 0165 hlay->addWidget(m_splitter); 0166 hlay->addWidget(d->rightSideBar); 0167 hlay->setContentsMargins(QMargins()); 0168 hlay->setSpacing(0); 0169 0170 // Code to check for the now depreciated HorizontalThumbar directive. It 0171 // is found, it is honored and deleted. The state will from than on be saved 0172 // by d->viewContainers built-in mechanism. 0173 0174 Qt::DockWidgetArea dockArea = Qt::LeftDockWidgetArea; 0175 0176 if (group.hasKey(d->configHorizontalThumbbarEntry)) 0177 { 0178 if (group.readEntry(d->configHorizontalThumbbarEntry, true)) 0179 { 0180 // Horizontal thumbbar layout 0181 0182 dockArea = Qt::TopDockWidgetArea; 0183 } 0184 0185 group.deleteEntry(d->configHorizontalThumbbarEntry); 0186 } 0187 0188 d->imageInfoModel = new ItemListModel(this); 0189 0190 d->imageFilterModel = new ItemFilterModel(this); 0191 d->imageFilterModel->setSourceItemModel(d->imageInfoModel); 0192 0193 d->imageInfoModel->setWatchFlags(d->imageFilterModel->suggestedWatchFlags()); 0194 d->imageInfoModel->setThumbnailLoadThread(ThumbnailLoadThread::defaultIconViewThread()); 0195 0196 d->imageFilterModel->setCategorizationMode(ItemSortSettings::NoCategories); 0197 d->imageFilterModel->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); 0198 d->imageFilterModel->setSortRole((ItemSortSettings::SortRole)ApplicationSettings::instance()->getImageSortOrder()); 0199 d->imageFilterModel->setSortOrder((ItemSortSettings::SortOrder)ApplicationSettings::instance()->getImageSorting()); 0200 d->imageFilterModel->setAllGroupsOpen(true); // disable filtering out by group, see bug #283847 0201 d->imageFilterModel->sort(0); // an initial sorting is necessary 0202 0203 d->dragDropHandler = new ItemDragDropHandler(d->imageInfoModel); 0204 d->dragDropHandler->setReadOnlyDrop(true); 0205 d->imageInfoModel->setDragDropHandler(d->dragDropHandler); 0206 0207 // The thumb bar is placed in a detachable/dockable widget. 0208 0209 d->thumbBarDock = new ThumbBarDock(d->viewContainer, Qt::Tool); 0210 d->thumbBarDock->setObjectName(QLatin1String("editor_thumbbar")); 0211 0212 d->thumbBar = new ItemThumbnailBar(d->thumbBarDock); 0213 d->thumbBar->setModels(d->imageInfoModel, d->imageFilterModel); 0214 0215 d->thumbBarDock->setWidget(d->thumbBar); 0216 d->viewContainer->addDockWidget(dockArea, d->thumbBarDock); 0217 d->thumbBarDock->setFloating(false); 0218 /* 0219 d->thumbBar->slotDockLocationChanged(dockArea); 0220 */ 0221 setCentralWidget(widget); 0222 } 0223 0224 void ImageWindow::addServicesMenu() 0225 { 0226 addServicesMenuForUrl(d->currentUrl()); 0227 } 0228 0229 void ImageWindow::slotContextMenu() 0230 { 0231 if (m_contextMenu) 0232 { 0233 m_contextMenu->addSeparator(); 0234 addServicesMenu(); 0235 m_contextMenu->addSeparator(); 0236 0237 // Bulk assignment/removal of tags -------------------------- 0238 0239 QList<qlonglong> idList; 0240 idList << d->currentItemInfo.id(); 0241 0242 TagsPopupMenu* const assignTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::RECENTLYASSIGNED, this); 0243 TagsPopupMenu* const removeTagsMenu = new TagsPopupMenu(idList, TagsPopupMenu::REMOVE, this); 0244 assignTagsMenu->menuAction()->setText(i18n("Assign Tag")); 0245 removeTagsMenu->menuAction()->setText(i18n("Remove Tag")); 0246 0247 m_contextMenu->addSeparator(); 0248 0249 m_contextMenu->addMenu(assignTagsMenu); 0250 m_contextMenu->addMenu(removeTagsMenu); 0251 0252 connect(assignTagsMenu, SIGNAL(signalTagActivated(int)), 0253 this, SLOT(slotAssignTag(int))); 0254 0255 connect(removeTagsMenu, SIGNAL(signalTagActivated(int)), 0256 this, SLOT(slotRemoveTag(int))); 0257 0258 connect(assignTagsMenu, SIGNAL(signalPopupTagsView()), 0259 d->rightSideBar, SLOT(slotPopupTagsView())); 0260 0261 if (!CoreDbAccess().db()->hasTags(idList)) 0262 { 0263 m_contextMenu->menuAction()->setEnabled(false); 0264 } 0265 0266 m_contextMenu->addSeparator(); 0267 0268 // Assign Labels ------------------------------------------- 0269 0270 QMenu* const menuLabels = new QMenu(i18n("Assign Labels"), m_contextMenu); 0271 PickLabelMenuAction* const pmenu = new PickLabelMenuAction(m_contextMenu); 0272 ColorLabelMenuAction* const cmenu = new ColorLabelMenuAction(m_contextMenu); 0273 RatingMenuAction* const rmenu = new RatingMenuAction(m_contextMenu); 0274 menuLabels->addAction(pmenu->menuAction()); 0275 menuLabels->addAction(cmenu->menuAction()); 0276 menuLabels->addAction(rmenu->menuAction()); 0277 m_contextMenu->addMenu(menuLabels); 0278 0279 connect(pmenu, SIGNAL(signalPickLabelChanged(int)), 0280 this, SLOT(slotAssignPickLabel(int))); 0281 0282 connect(cmenu, SIGNAL(signalColorLabelChanged(int)), 0283 this, SLOT(slotAssignColorLabel(int))); 0284 0285 connect(rmenu, SIGNAL(signalRatingChanged(int)), 0286 this, SLOT(slotAssignRating(int))); 0287 0288 // -------------------------------------------------------------- 0289 0290 m_contextMenu->exec(QCursor::pos()); 0291 0292 delete assignTagsMenu; 0293 delete removeTagsMenu; 0294 delete cmenu; 0295 delete pmenu; 0296 delete rmenu; 0297 delete menuLabels; 0298 } 0299 } 0300 0301 } // namespace Digikam