1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2012-09-07
7  * Description : Qt Model for ImportUI - drag and drop handling
8  *
9  * Copyright (C) 2012      by Islam Wazery <wazery at ubuntu dot com>
10  * Copyright (C) 2013-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "importdragdrop.h"
26 
27 // Qt includes
28 
29 #include <QDropEvent>
30 #include <QIcon>
31 
32 // KDE includes
33 
34 #include <klocalizedstring.h>
35 
36 // Local includes
37 
38 #include "digikam_debug.h"
39 #include "importiconview.h"
40 #include "importui.h"
41 #include "ddragobjects.h"
42 #include "importcategorizedview.h"
43 #include "camiteminfo.h"
44 #include "albummanager.h"
45 #include "digikamapp.h"
46 #include "itemiconview.h"
47 
48 namespace Digikam
49 {
50 
ImportDragDropHandler(ImportItemModel * const model)51 ImportDragDropHandler::ImportDragDropHandler(ImportItemModel* const model)
52     : AbstractItemDragDropHandler(model)
53 {
54 }
55 
addGroupAction(QMenu * const menu)56 QAction* ImportDragDropHandler::addGroupAction(QMenu* const menu)
57 {
58     return menu->addAction(QIcon::fromTheme(QLatin1String("go-bottom")),
59                            i18nc("@action:inmenu Group images with this image", "Group here"));
60 }
61 
addCancelAction(QMenu * const menu)62 QAction* ImportDragDropHandler::addCancelAction(QMenu* const menu)
63 {
64     return menu->addAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("C&ancel"));
65 }
66 
copyOrMove(const QDropEvent * e,QWidget * const view,bool allowMove,bool askForGrouping)67 ImportDragDropHandler::DropAction ImportDragDropHandler::copyOrMove(const QDropEvent* e,
68                                                                     QWidget* const view,
69                                                                     bool allowMove,
70                                                                     bool askForGrouping)
71 {
72     if      (e->keyboardModifiers() & Qt::ControlModifier)
73     {
74         return CopyAction;
75     }
76     else if (e->keyboardModifiers() & Qt::ShiftModifier)
77     {
78         return MoveAction;
79     }
80 
81     if (!allowMove && !askForGrouping)
82     {
83         switch (e->proposedAction())
84         {
85             case Qt::CopyAction:
86             {
87                 return CopyAction;
88             }
89 
90             case Qt::MoveAction:
91             {
92                 return MoveAction;
93             }
94 
95             default:
96             {
97                 return NoAction;
98             }
99         }
100     }
101 
102     QMenu popMenu(view);
103 
104     QAction* moveAction       = nullptr;
105 
106     if (allowMove)
107     {
108         moveAction = popMenu.addAction(QIcon::fromTheme(QLatin1String("go-jump")), i18n("&Move Here"));
109     }
110 
111     QAction* const copyAction = popMenu.addAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18n("&Copy Here"));
112     popMenu.addSeparator();
113 
114     QAction* groupAction      = nullptr;
115 
116     if (askForGrouping)
117     {
118         groupAction = addGroupAction(&popMenu);
119         popMenu.addSeparator();
120     }
121 
122     addCancelAction(&popMenu);
123 
124     popMenu.setMouseTracking(true);
125     QAction* const choice = popMenu.exec(QCursor::pos());
126 
127     if      (moveAction && (choice == moveAction))
128     {
129         return MoveAction;
130     }
131     else if (choice == copyAction)
132     {
133         return CopyAction;
134     }
135     else if (groupAction && (choice == groupAction))
136     {
137         return GroupAction;
138     }
139 
140     return NoAction;
141 }
142 
143 /*
144 static DropAction tagAction(const QDropEvent*, QWidget* view, bool askForGrouping)
145 {
146 }
147 
148 static DropAction groupAction(const QDropEvent*, QWidget* view)
149 {
150 }
151 */
152 
dropEvent(QAbstractItemView * abstractview,const QDropEvent * e,const QModelIndex & droppedOn)153 bool ImportDragDropHandler::dropEvent(QAbstractItemView* abstractview,
154                                       const QDropEvent* e,
155                                       const QModelIndex& droppedOn)
156 {
157     ImportCategorizedView* const view = static_cast<ImportCategorizedView*>(abstractview);
158 
159     if (accepts(e, droppedOn) == Qt::IgnoreAction)
160     {
161         return false;
162     }
163 
164     if (DItemDrag::canDecode(e->mimeData()))
165     {
166         QList<QUrl> lst         = DigikamApp::instance()->view()->selectedUrls();
167 
168         QMenu popMenu(view);
169         popMenu.addSection(QIcon::fromTheme(QLatin1String("digikam")), i18n("Exporting"));
170         QAction* const upAction = popMenu.addAction(QIcon::fromTheme(QLatin1String("media-flash-sd-mmc")),
171                                                     i18n("Upload to Camera"));
172         popMenu.addSeparator();
173         popMenu.addAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("C&ancel"));
174         popMenu.setMouseTracking(true);
175         QAction* const choice   = popMenu.exec(view->mapToGlobal(e->pos()));
176 
177         if (choice)
178         {
179             if (choice == upAction)
180             {
181                 ImportUI::instance()->slotUploadItems(lst);
182             }
183         }
184 
185         return true;
186     }
187 /*
188     TODO: Implement tag dropping in import tool.
189     else if (DTagListDrag::canDecode(e->mimeData()))
190     {
191     }
192 */
193     return false;
194 }
195 
accepts(const QDropEvent * e,const QModelIndex &)196 Qt::DropAction ImportDragDropHandler::accepts(const QDropEvent* e, const QModelIndex& /*dropIndex*/)
197 {
198     if (DItemDrag::canDecode(e->mimeData()) || e->mimeData()->hasUrls())
199     {
200         if      (e->keyboardModifiers() & Qt::ControlModifier)
201         {
202             return Qt::CopyAction;
203         }
204         else if (e->keyboardModifiers() & Qt::ShiftModifier)
205         {
206             return Qt::MoveAction;
207         }
208 
209         return Qt::MoveAction;
210     }
211 
212     if (DTagListDrag::canDecode(e->mimeData())        ||
213         DCameraItemListDrag::canDecode(e->mimeData()) ||
214         DCameraDragObject::canDecode(e->mimeData()))
215     {
216         return Qt::MoveAction;
217     }
218 
219     return Qt::IgnoreAction;
220 }
221 
mimeTypes() const222 QStringList ImportDragDropHandler::mimeTypes() const
223 {
224     QStringList mimeTypes;
225     mimeTypes << DItemDrag::mimeTypes()
226               << DTagListDrag::mimeTypes()
227               << DCameraItemListDrag::mimeTypes()
228               << DCameraDragObject::mimeTypes()
229               << QLatin1String("text/uri-list");
230 
231     return mimeTypes;
232 }
233 
createMimeData(const QList<QModelIndex> & indexes)234 QMimeData* ImportDragDropHandler::createMimeData(const QList<QModelIndex>& indexes)
235 {
236     QList<CamItemInfo> infos = model()->camItemInfos(indexes);
237 
238     QStringList lst;
239 
240     foreach (const CamItemInfo& info, infos)
241     {
242         lst.append(info.folder + info.name);
243     }
244 
245     if (lst.isEmpty())
246     {
247         return nullptr;
248     }
249 
250     return (new DCameraItemListDrag(lst));
251 }
252 
model() const253 ImportItemModel* ImportDragDropHandler::model() const
254 {
255     return static_cast<ImportItemModel*>(m_model);
256 }
257 
258 } // namespace Digikam
259