1 /***************************************************************************
2     File                 : Folder.cpp
3     Project              : SciDAVis
4     --------------------------------------------------------------------
5     Copyright            : (C) 2006 by Ion Vasilief,
6                            Tilman Benkert,
7                                           Knut Franke
8     Email (use @ for *)  : ion_vasilief*yahoo.fr, thzs*gmx.net,
9                            knut.franke*gmx.de
10     Description          : Folder for the project explorer
11 
12  ***************************************************************************/
13 
14 /***************************************************************************
15  *                                                                         *
16  *  This program is free software; you can redistribute it and/or modify   *
17  *  it under the terms of the GNU General Public License as published by   *
18  *  the Free Software Foundation; either version 2 of the License, or      *
19  *  (at your option) any later version.                                    *
20  *                                                                         *
21  *  This program is distributed in the hope that it will be useful,        *
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
24  *  GNU General Public License for more details.                           *
25  *                                                                         *
26  *   You should have received a copy of the GNU General Public License     *
27  *   along with this program; if not, write to the Free Software           *
28  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
29  *   Boston, MA  02110-1301  USA                                           *
30  *                                                                         *
31  ***************************************************************************/
32 #include "Folder.h"
33 
34 #include <qobject.h>
35 #include <qdatetime.h>
36 #include <qpixmap.h>
37 
38 #include <qevent.h>
39 #include <qpoint.h>
40 #include <qmessagebox.h>
41 #include <qstringlist.h>
42 #include <qapplication.h>
43 #include <qcursor.h>
44 // Added by qt3to4:
45 #include <QKeyEvent>
46 #include <QDropEvent>
47 #include <QMouseEvent>
48 #include <QDrag>
49 
Folder(const QString & name)50 Folder::Folder(const QString &name) : d_active_window(0)
51 {
52     QObject::setObjectName(name);
53     birthdate = QLocale().toString(QDateTime::currentDateTime());
54 
55     // FIXME: This doesn't work anymore in Qt4, need alternative method
56     // lstWindows.setAutoDelete( true );
57 }
58 
folders() const59 QList<Folder *> Folder::folders() const
60 {
61     QList<Folder *> lst;
62     foreach (QObject *f, children())
63         lst.append((Folder *)f);
64     return lst;
65 }
66 
subfolders()67 QStringList Folder::subfolders()
68 {
69     QStringList list = QStringList();
70     QObjectList folderList = children();
71     if (!folderList.isEmpty()) {
72         QObject *f;
73         foreach (f, folderList)
74             list << static_cast<Folder *>(f)->name();
75     }
76     return list;
77 }
78 
path()79 QString Folder::path()
80 {
81     QString s = "/" + QString(name()) + "/";
82     Folder *parentFolder = (Folder *)parent();
83     while (parentFolder) {
84         s.prepend("/" + QString(parentFolder->name()));
85         parentFolder = (Folder *)parentFolder->parent();
86     }
87     return s;
88 }
89 
findSubfolder(const QString & s,bool caseSensitive,bool partialMatch)90 Folder *Folder::findSubfolder(const QString &s, bool caseSensitive, bool partialMatch)
91 {
92     QObjectList folderList = children();
93     if (!folderList.isEmpty()) {
94         QObject *f;
95 
96         foreach (f, folderList) {
97             QString name = static_cast<Folder *>(f)->name();
98             if (partialMatch) {
99                 if (caseSensitive && name.startsWith(s, Qt::CaseSensitive))
100                     return static_cast<Folder *>(f);
101                 else if (!caseSensitive && name.startsWith(s, Qt::CaseInsensitive))
102                     return static_cast<Folder *>(f);
103             } else // partialMatch == false
104             {
105                 if (caseSensitive && name == s)
106                     return static_cast<Folder *>(f);
107                 else if (!caseSensitive && (name.toLower() == s.toLower()))
108                     return static_cast<Folder *>(f);
109             }
110         }
111     }
112     return 0;
113 }
114 
findWindow(const QString & s,bool windowNames,bool labels,bool caseSensitive,bool partialMatch)115 MyWidget *Folder::findWindow(const QString &s, bool windowNames, bool labels, bool caseSensitive,
116                              bool partialMatch)
117 {
118     Qt::CaseSensitivity cs = Qt::CaseSensitive;
119     if (!caseSensitive)
120         cs = Qt::CaseInsensitive;
121     MyWidget *w;
122     foreach (w, lstWindows) {
123         if (windowNames) {
124             QString name = w->name();
125             if (partialMatch && name.startsWith(s, cs))
126                 return w;
127             else if (caseSensitive && name == s)
128                 return w;
129             else {
130                 QString text = s;
131                 if (name == text.toLower())
132                     return w;
133             }
134         }
135 
136         if (labels) {
137             QString label = w->windowLabel();
138             if (partialMatch && label.startsWith(s, cs))
139                 return w;
140             else if (caseSensitive && label == s)
141                 return w;
142             else {
143                 QString text = s;
144                 if (label == text.toLower())
145                     return w;
146             }
147         }
148     }
149     return 0;
150 }
151 
window(const QString & name,const char * cls,bool recursive)152 MyWidget *Folder::window(const QString &name, const char *cls, bool recursive)
153 {
154     foreach (MyWidget *w, lstWindows)
155         if (w->inherits(cls) && name == w->name().mid(0, w->name().indexOf("@")))
156             return w;
157     if (!recursive)
158         return NULL;
159     foreach (QObject *f, children()) {
160         MyWidget *w = ((Folder *)f)->window(name, cls, true);
161         if (w)
162             return w;
163     }
164     return NULL;
165 }
166 
rootFolder()167 Folder *Folder::rootFolder()
168 {
169     Folder *i = this;
170     while (i->parent())
171         i = (Folder *)i->parent();
172     return i;
173 }
174 
175 /*****************************************************************************
176  *
177  * Class FolderListItem
178  *
179  *****************************************************************************/
180 
FolderListItem(QTreeWidget * parent,Folder * f)181 FolderListItem::FolderListItem(QTreeWidget *parent, Folder *f)
182     : QTreeWidgetItem(parent, FolderListItem::FolderType)
183 {
184     myFolder = f;
185 
186     setText(0, f->name());
187     setExpanded(true);
188     setActive(true);
189     setFlags(flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
190 }
191 
FolderListItem(FolderListItem * parent,Folder * f)192 FolderListItem::FolderListItem(FolderListItem *parent, Folder *f)
193     : QTreeWidgetItem(parent, FolderListItem::FolderType)
194 {
195     myFolder = f;
196 
197     setText(0, f->name());
198     setExpanded(true);
199     setActive(true);
200 }
201 
setActive(bool o)202 void FolderListItem::setActive(bool o)
203 {
204     if (o)
205         setIcon(0, QIcon(QPixmap(":/folder_open.xpm")));
206     else
207         setIcon(0, QIcon(QPixmap(":/folder_closed.xpm")));
208 
209     setSelected(o);
210 }
211 
isChildOf(FolderListItem * src)212 bool FolderListItem::isChildOf(FolderListItem *src)
213 {
214     FolderListItem *parent = (FolderListItem *)this->parent();
215     while (parent) {
216         if (parent == src)
217             return true;
218 
219         parent = (FolderListItem *)parent->parent();
220     }
221     return false;
222 }
223 
depth()224 int FolderListItem::depth()
225 {
226     int c = 0;
227     FolderListItem *parent = (FolderListItem *)this->parent();
228     while (parent) {
229         c++;
230         parent = (FolderListItem *)parent->parent();
231     }
232     return c;
233 }
234 
setData(int column,int role,const QVariant & value)235 void FolderListItem::setData(int column, int role, const QVariant &value)
236 {
237     if ((role == Qt::EditRole) && (column == 0)
238         && (value
239             != this->text(
240                     0))) { // data should be accepted or rejected on slot connected to this signal
241         emit this->folderListView()->itemRenamed(this, column, value.toString());
242     } else {
243         QTreeWidgetItem::setData(column, role, value);
244     }
245 }
246 /*****************************************************************************
247  *
248  * Class FolderListView
249  *
250  *****************************************************************************/
251 
FolderListView(const QString & name)252 FolderListView::FolderListView(const QString &name) : mousePressed(false)
253 {
254     setObjectName(name.toLocal8Bit());
255     setAcceptDrops(true);
256     viewport()->setAcceptDrops(true);
257     setDropIndicatorShown(true);
258 }
259 
startDrag(Qt::DropActions supportedActions)260 void FolderListView::startDrag(Qt::DropActions supportedActions)
261 {
262     QTreeWidgetItem *item = currentItem();
263     if (!item)
264         return;
265 
266     if (item == topLevelItem(0) && item->treeWidget()->rootIsDecorated())
267         return; // it's the project folder so we don't want the user to move it
268 
269     QPixmap pix;
270     if (item->type() == FolderListItem::FolderType)
271         pix = QPixmap(":/folder_closed.xpm");
272     else
273         pix = item->icon(0).pixmap(QSize());
274 
275     QDrag *drag = new QDrag(viewport());
276     drag->setPixmap(pix);
277     drag->setHotSpot(QPoint(pix.width() / 2, pix.height() / 2));
278 
279     QList<QTreeWidgetItem *> lst;
280     QTreeWidgetItemIterator it(this);
281     while (*it) {
282         if ((*it)->isSelected())
283             lst.append(*it);
284         it++;
285     }
286 
287     emit dragItems(lst);
288     drag->setMimeData(mimeData(lst));
289     drag->exec(supportedActions);
290 }
291 
dropEvent(QDropEvent * e)292 void FolderListView::dropEvent(QDropEvent *e)
293 {
294     QTreeWidgetItem *dest = itemAt(e->pos());
295     if (dest && dest->type() == FolderListItem::FolderType) {
296         if (dropIndicatorPosition() != QAbstractItemView::OnItem) {
297             e->ignore();
298         } else {
299             emit dropItems(dest);
300             e->accept();
301             this->setState(QAbstractItemView::NoState); // hack to clear DraggingState
302         }
303         mousePressed = false;
304     } else
305         e->ignore();
306 }
307 
keyPressEvent(QKeyEvent * e)308 void FolderListView::keyPressEvent(QKeyEvent *e)
309 {
310     if (isRenaming()) {
311         e->ignore();
312         return;
313     }
314     QTreeWidgetItem *item = currentItem();
315     if (!item) {
316         QTreeWidget::keyPressEvent(e);
317         return;
318     }
319 
320     if (item->type() == FolderListItem::FolderType
321         && (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)) {
322         emit itemDoubleClicked(item, 0);
323         e->accept();
324     } else if (e->key() == Qt::Key_F2) {
325         if (item)
326             emit renameItem(item, 0);
327         e->accept();
328     } else if (e->key() == Qt::Key_A && e->modifiers() == Qt::ControlModifier) {
329         selectAll();
330         e->accept();
331     } else if (e->key() == Qt::Key_F7) {
332         emit addFolderItem();
333         e->accept();
334     } else if (e->key() == Qt::Key_F8) {
335         emit deleteSelection();
336         e->accept();
337     } else
338         QTreeWidget::keyPressEvent(e);
339 }
340 
mouseDoubleClickEvent(QMouseEvent * e)341 void FolderListView::mouseDoubleClickEvent(QMouseEvent *e)
342 {
343     if (isRenaming()) {
344         e->ignore();
345         return;
346     }
347 
348     QTreeWidget::mouseDoubleClickEvent(e);
349 }
350 
mousePressEvent(QMouseEvent * e)351 void FolderListView::mousePressEvent(QMouseEvent *e)
352 {
353     QTreeWidget::mousePressEvent(e);
354     if (e->button() == Qt::LeftButton) {
355         presspos = e->pos();
356         mousePressed = true;
357     }
358 }
359 
mouseMoveEvent(QMouseEvent * e)360 void FolderListView::mouseMoveEvent(QMouseEvent *e)
361 {
362     if (mousePressed
363         && (presspos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
364         mousePressed = false;
365         QTreeWidgetItem *item = itemAt(presspos);
366         if (item)
367             startDrag();
368     }
369 }
370 
adjustColumns()371 void FolderListView::adjustColumns()
372 {
373     for (int i = 0; i < columnCount(); i++)
374         resizeColumnToContents(i);
375 }
376 
377 /*****************************************************************************
378  *
379  * Class WindowListItem
380  *
381  *****************************************************************************/
382 
WindowListItem(QTreeWidget * parent,MyWidget * w)383 WindowListItem::WindowListItem(QTreeWidget *parent, MyWidget *w)
384     : QTreeWidgetItem(parent, WindowListItem::WindowType)
385 {
386     myWindow = w;
387     this->treeWidget()->setCurrentItem(
388             this, 0, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
389 
390     setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled);
391 }
392 
setData(int column,int role,const QVariant & value)393 void WindowListItem::setData(int column, int role, const QVariant &value)
394 {
395     if (role
396         == Qt::EditRole) { // data should be accepted or rejected on slot connected to this signal
397         if (column == 0)
398             emit this->folderListView()->itemRenamed(this, column, value.toString());
399     } else {
400         QTreeWidgetItem::setData(column, role, value);
401     }
402 }
403