|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Designer of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "abstractsettings_p.h" |
|
43 #include "qtresourceview_p.h" |
|
44 #include "qtresourcemodel_p.h" |
|
45 #include "qtresourceeditordialog_p.h" |
|
46 #include "iconloader_p.h" |
|
47 #include "filterwidget_p.h" // For FilterWidget |
|
48 |
|
49 #include <QtDesigner/QDesignerFormEditorInterface> |
|
50 |
|
51 #include <QtGui/QToolBar> |
|
52 #include <QtGui/QAction> |
|
53 #include <QtGui/QSplitter> |
|
54 #include <QtGui/QTreeWidget> |
|
55 #include <QtGui/QListWidget> |
|
56 #include <QtGui/QHeaderView> |
|
57 #include <QtGui/QVBoxLayout> |
|
58 #include <QtGui/QPainter> |
|
59 #include <QtCore/QFileInfo> |
|
60 #include <QtCore/QDir> |
|
61 #include <QtCore/QQueue> |
|
62 #include <QtGui/QPainter> |
|
63 #include <QtGui/QDialogButtonBox> |
|
64 #include <QtGui/QPushButton> |
|
65 #include <QtGui/QMessageBox> |
|
66 #include <QtGui/QApplication> |
|
67 #include <QtGui/QClipboard> |
|
68 #include <QtGui/QMenu> |
|
69 #include <QtGui/QDrag> |
|
70 #include <QtCore/QMimeData> |
|
71 #include <QtXml/QDomDocument> |
|
72 |
|
73 QT_BEGIN_NAMESPACE |
|
74 |
|
75 static const char *elementResourceData = "resource"; |
|
76 static const char *typeAttribute = "type"; |
|
77 static const char *typeImage = "image"; |
|
78 static const char *typeStyleSheet = "stylesheet"; |
|
79 static const char *typeOther = "other"; |
|
80 static const char *fileAttribute = "file"; |
|
81 static const char *SplitterPosition = "SplitterPosition"; |
|
82 static const char *Geometry = "Geometry"; |
|
83 static const char *ResourceViewDialogC = "ResourceDialog"; |
|
84 |
|
85 // ---------------- ResourceListWidget: A list widget that has drag enabled |
|
86 class ResourceListWidget : public QListWidget { |
|
87 public: |
|
88 ResourceListWidget(QWidget *parent = 0); |
|
89 |
|
90 protected: |
|
91 virtual void startDrag(Qt::DropActions supportedActions); |
|
92 }; |
|
93 |
|
94 ResourceListWidget::ResourceListWidget(QWidget *parent) : |
|
95 QListWidget(parent) |
|
96 { |
|
97 setDragEnabled(true); |
|
98 } |
|
99 |
|
100 void ResourceListWidget::startDrag(Qt::DropActions supportedActions) |
|
101 { |
|
102 if (supportedActions == Qt::MoveAction) |
|
103 return; |
|
104 |
|
105 QListWidgetItem *item = currentItem(); |
|
106 if (!item) |
|
107 return; |
|
108 |
|
109 const QString filePath = item->data(Qt::UserRole).toString(); |
|
110 const QIcon icon = item->icon(); |
|
111 |
|
112 QMimeData *mimeData = new QMimeData; |
|
113 const QtResourceView::ResourceType type = icon.isNull() ? QtResourceView::ResourceOther : QtResourceView::ResourceImage; |
|
114 mimeData->setText(QtResourceView::encodeMimeData(type , filePath)); |
|
115 |
|
116 QDrag *drag = new QDrag(this); |
|
117 if (!icon.isNull()) { |
|
118 const QSize size = icon.actualSize(iconSize()); |
|
119 drag->setPixmap(icon.pixmap(size)); |
|
120 drag->setHotSpot(QPoint(size.width() / 2, size.height() / 2)); |
|
121 } |
|
122 |
|
123 drag->setMimeData(mimeData); |
|
124 drag->exec(Qt::CopyAction); |
|
125 } |
|
126 |
|
127 /* TODO |
|
128 |
|
129 1) load the icons in separate thread...Hmm..if Qt is configured with threads.... |
|
130 */ |
|
131 |
|
132 // ---------------------------- QtResourceViewPrivate |
|
133 class QtResourceViewPrivate |
|
134 { |
|
135 QtResourceView *q_ptr; |
|
136 Q_DECLARE_PUBLIC(QtResourceView) |
|
137 public: |
|
138 QtResourceViewPrivate(QDesignerFormEditorInterface *core); |
|
139 |
|
140 void slotResourceSetActivated(QtResourceSet *resourceSet); |
|
141 void slotCurrentPathChanged(QTreeWidgetItem *); |
|
142 void slotCurrentResourceChanged(QListWidgetItem *); |
|
143 void slotResourceActivated(QListWidgetItem *); |
|
144 void slotEditResources(); |
|
145 void slotReloadResources(); |
|
146 void slotCopyResourcePath(); |
|
147 void slotListWidgetContextMenuRequested(const QPoint &pos); |
|
148 void slotFilterChanged(const QString &pattern); |
|
149 void createPaths(); |
|
150 QTreeWidgetItem *createPath(const QString &path, QTreeWidgetItem *parent); |
|
151 void createResources(const QString &path); |
|
152 void storeExpansionState(); |
|
153 void applyExpansionState(); |
|
154 void restoreSettings(); |
|
155 void saveSettings(); |
|
156 void updateActions(); |
|
157 void filterOutResources(); |
|
158 |
|
159 QPixmap makeThumbnail(const QPixmap &pix) const; |
|
160 |
|
161 QDesignerFormEditorInterface *m_core; |
|
162 QtResourceModel *m_resourceModel; |
|
163 QToolBar *m_toolBar; |
|
164 qdesigner_internal::FilterWidget *m_filterWidget; |
|
165 QTreeWidget *m_treeWidget; |
|
166 QListWidget *m_listWidget; |
|
167 QSplitter *m_splitter; |
|
168 QMap<QString, QStringList> m_pathToContents; // full path to contents file names (full path to its resource filenames) |
|
169 QMap<QString, QString> m_pathToParentPath; // full path to full parent path |
|
170 QMap<QString, QStringList> m_pathToSubPaths; // full path to full sub paths |
|
171 QMap<QString, QTreeWidgetItem *> m_pathToItem; |
|
172 QMap<QTreeWidgetItem *, QString> m_itemToPath; |
|
173 QMap<QString, QListWidgetItem *> m_resourceToItem; |
|
174 QMap<QListWidgetItem *, QString> m_itemToResource; |
|
175 QAction *m_editResourcesAction; |
|
176 QAction *m_reloadResourcesAction; |
|
177 QAction *m_copyResourcePathAction; |
|
178 |
|
179 QMap<QString, bool> m_expansionState; |
|
180 |
|
181 bool m_ignoreGuiSignals; |
|
182 QString m_settingsKey; |
|
183 bool m_resourceEditingEnabled; |
|
184 QString m_filterPattern; |
|
185 }; |
|
186 |
|
187 QtResourceViewPrivate::QtResourceViewPrivate(QDesignerFormEditorInterface *core) : |
|
188 q_ptr(0), |
|
189 m_core(core), |
|
190 m_resourceModel(0), |
|
191 m_toolBar(new QToolBar), |
|
192 m_treeWidget(new QTreeWidget), |
|
193 m_listWidget(new ResourceListWidget), |
|
194 m_splitter(0), |
|
195 m_editResourcesAction(0), |
|
196 m_reloadResourcesAction(0), |
|
197 m_copyResourcePathAction(0), |
|
198 m_ignoreGuiSignals(false), |
|
199 m_resourceEditingEnabled(true) |
|
200 { |
|
201 } |
|
202 |
|
203 void QtResourceViewPrivate::restoreSettings() |
|
204 { |
|
205 if (m_settingsKey.isEmpty()) |
|
206 return; |
|
207 |
|
208 QDesignerSettingsInterface *settings = m_core->settingsManager(); |
|
209 settings->beginGroup(m_settingsKey); |
|
210 |
|
211 m_splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray()); |
|
212 settings->endGroup(); |
|
213 } |
|
214 |
|
215 void QtResourceViewPrivate::saveSettings() |
|
216 { |
|
217 if (m_settingsKey.isEmpty()) |
|
218 return; |
|
219 |
|
220 QDesignerSettingsInterface *settings = m_core->settingsManager(); |
|
221 settings->beginGroup(m_settingsKey); |
|
222 |
|
223 settings->setValue(QLatin1String(SplitterPosition), m_splitter->saveState()); |
|
224 settings->endGroup(); |
|
225 } |
|
226 |
|
227 void QtResourceViewPrivate::slotEditResources() |
|
228 { |
|
229 const QString selectedResource |
|
230 = QtResourceEditorDialog::editResources(m_core, m_resourceModel, |
|
231 m_core->dialogGui(), q_ptr); |
|
232 if (!selectedResource.isEmpty()) |
|
233 q_ptr->selectResource(selectedResource); |
|
234 } |
|
235 |
|
236 void QtResourceViewPrivate::slotReloadResources() |
|
237 { |
|
238 if (m_resourceModel) { |
|
239 int errorCount; |
|
240 QString errorMessages; |
|
241 m_resourceModel->reload(&errorCount, &errorMessages); |
|
242 if (errorCount) |
|
243 QtResourceEditorDialog::displayResourceFailures(errorMessages, m_core->dialogGui(), q_ptr); |
|
244 } |
|
245 } |
|
246 |
|
247 void QtResourceViewPrivate::slotCopyResourcePath() |
|
248 { |
|
249 const QString path = q_ptr->selectedResource(); |
|
250 QClipboard *clipboard = QApplication::clipboard(); |
|
251 clipboard->setText(path); |
|
252 } |
|
253 |
|
254 void QtResourceViewPrivate::slotListWidgetContextMenuRequested(const QPoint &pos) |
|
255 { |
|
256 QMenu menu(q_ptr); |
|
257 menu.addAction(m_copyResourcePathAction); |
|
258 menu.exec(m_listWidget->mapToGlobal(pos)); |
|
259 } |
|
260 |
|
261 void QtResourceViewPrivate::slotFilterChanged(const QString &pattern) |
|
262 { |
|
263 m_filterPattern = pattern; |
|
264 filterOutResources(); |
|
265 } |
|
266 |
|
267 void QtResourceViewPrivate::storeExpansionState() |
|
268 { |
|
269 QMapIterator<QString, QTreeWidgetItem *> it(m_pathToItem); |
|
270 while (it.hasNext()) { |
|
271 it.next(); |
|
272 m_expansionState[it.key()] = it.value()->isExpanded(); |
|
273 } |
|
274 } |
|
275 |
|
276 void QtResourceViewPrivate::applyExpansionState() |
|
277 { |
|
278 QMapIterator<QString, QTreeWidgetItem *> it(m_pathToItem); |
|
279 while (it.hasNext()) { |
|
280 it.next(); |
|
281 it.value()->setExpanded(m_expansionState.value(it.key(), true)); |
|
282 } |
|
283 } |
|
284 |
|
285 QPixmap QtResourceViewPrivate::makeThumbnail(const QPixmap &pix) const |
|
286 { |
|
287 int w = qMax(48, pix.width()); |
|
288 int h = qMax(48, pix.height()); |
|
289 QRect imgRect(0, 0, w, h); |
|
290 QImage img(w, h, QImage::Format_ARGB32_Premultiplied); |
|
291 img.fill(0); |
|
292 if (!pix.isNull()) { |
|
293 QRect r(0, 0, pix.width(), pix.height()); |
|
294 r.moveCenter(imgRect.center()); |
|
295 QPainter p(&img); |
|
296 p.drawPixmap(r.topLeft(), pix); |
|
297 } |
|
298 return QPixmap::fromImage(img); |
|
299 } |
|
300 |
|
301 void QtResourceViewPrivate::updateActions() |
|
302 { |
|
303 bool resourceActive = false; |
|
304 if (m_resourceModel) |
|
305 resourceActive = m_resourceModel->currentResourceSet(); |
|
306 |
|
307 m_editResourcesAction->setVisible(m_resourceEditingEnabled); |
|
308 m_editResourcesAction->setEnabled(resourceActive); |
|
309 m_reloadResourcesAction->setEnabled(resourceActive); |
|
310 m_filterWidget->setEnabled(resourceActive); |
|
311 } |
|
312 |
|
313 void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet) |
|
314 { |
|
315 Q_UNUSED(resourceSet) |
|
316 |
|
317 updateActions(); |
|
318 |
|
319 storeExpansionState(); |
|
320 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem()); |
|
321 const QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); |
|
322 m_treeWidget->clear(); |
|
323 m_pathToContents.clear(); |
|
324 m_pathToParentPath.clear(); |
|
325 m_pathToSubPaths.clear(); |
|
326 m_pathToItem.clear(); |
|
327 m_itemToPath.clear(); |
|
328 m_listWidget->clear(); |
|
329 m_resourceToItem.clear(); |
|
330 m_itemToResource.clear(); |
|
331 |
|
332 createPaths(); |
|
333 applyExpansionState(); |
|
334 |
|
335 if (!currentResource.isEmpty()) |
|
336 q_ptr->selectResource(currentResource); |
|
337 else if (!currentPath.isEmpty()) |
|
338 q_ptr->selectResource(currentPath); |
|
339 filterOutResources(); |
|
340 } |
|
341 |
|
342 void QtResourceViewPrivate::slotCurrentPathChanged(QTreeWidgetItem *item) |
|
343 { |
|
344 if (m_ignoreGuiSignals) |
|
345 return; |
|
346 |
|
347 m_listWidget->clear(); |
|
348 m_resourceToItem.clear(); |
|
349 m_itemToResource.clear(); |
|
350 |
|
351 if (!item) |
|
352 return; |
|
353 |
|
354 const QString currentPath = m_itemToPath.value(item); |
|
355 createResources(currentPath); |
|
356 } |
|
357 |
|
358 void QtResourceViewPrivate::slotCurrentResourceChanged(QListWidgetItem *item) |
|
359 { |
|
360 m_copyResourcePathAction->setEnabled(item); |
|
361 if (m_ignoreGuiSignals) |
|
362 return; |
|
363 |
|
364 emit q_ptr->resourceSelected(m_itemToResource.value(item)); |
|
365 } |
|
366 |
|
367 void QtResourceViewPrivate::slotResourceActivated(QListWidgetItem *item) |
|
368 { |
|
369 if (m_ignoreGuiSignals) |
|
370 return; |
|
371 |
|
372 emit q_ptr->resourceActivated(m_itemToResource.value(item)); |
|
373 } |
|
374 |
|
375 void QtResourceViewPrivate::createPaths() |
|
376 { |
|
377 if (!m_resourceModel) |
|
378 return; |
|
379 |
|
380 const QString root(QLatin1Char(':')); |
|
381 |
|
382 QMap<QString, QString> contents = m_resourceModel->contents(); |
|
383 QMapIterator<QString, QString> itContents(contents); |
|
384 while (itContents.hasNext()) { |
|
385 const QString filePath = itContents.next().key(); |
|
386 const QFileInfo fi(filePath); |
|
387 QString dirPath = fi.absolutePath(); |
|
388 m_pathToContents[dirPath].append(fi.fileName()); |
|
389 while (!m_pathToParentPath.contains(dirPath) && dirPath != root) { // create all parent paths |
|
390 const QFileInfo fd(dirPath); |
|
391 const QString parentDirPath = fd.absolutePath(); |
|
392 m_pathToParentPath[dirPath] = parentDirPath; |
|
393 m_pathToSubPaths[parentDirPath].append(dirPath); |
|
394 dirPath = parentDirPath; |
|
395 } |
|
396 } |
|
397 |
|
398 QQueue<QPair<QString, QTreeWidgetItem *> > pathToParentItemQueue; |
|
399 pathToParentItemQueue.enqueue(qMakePair(root, static_cast<QTreeWidgetItem *>(0))); |
|
400 while (!pathToParentItemQueue.isEmpty()) { |
|
401 QPair<QString, QTreeWidgetItem *> pathToParentItem = pathToParentItemQueue.dequeue(); |
|
402 const QString path = pathToParentItem.first; |
|
403 QTreeWidgetItem *item = createPath(path, pathToParentItem.second); |
|
404 QStringList subPaths = m_pathToSubPaths.value(path); |
|
405 QStringListIterator itSubPaths(subPaths); |
|
406 while (itSubPaths.hasNext()) |
|
407 pathToParentItemQueue.enqueue(qMakePair(itSubPaths.next(), item)); |
|
408 } |
|
409 } |
|
410 |
|
411 void QtResourceViewPrivate::filterOutResources() |
|
412 { |
|
413 QMap<QString, bool> pathToMatchingContents; // true means the path has any matching contents |
|
414 QMap<QString, bool> pathToVisible; // true means the path has to be shown |
|
415 |
|
416 // 1) we go from root path recursively. |
|
417 // 2) we check every path if it contains at least one matching resource - if empty we add it |
|
418 // to pathToMatchingContents and pathToVisible with false, if non empty |
|
419 // we add it with true and change every parent path in pathToVisible to true. |
|
420 // 3) we hide these items which has pathToVisible value false. |
|
421 |
|
422 const bool matchAll = m_filterPattern.isEmpty(); |
|
423 const QString root(QLatin1Char(':')); |
|
424 |
|
425 QQueue<QString> pathQueue; |
|
426 pathQueue.enqueue(root); |
|
427 while (!pathQueue.isEmpty()) { |
|
428 const QString path = pathQueue.dequeue(); |
|
429 |
|
430 QStringList fileNames = m_pathToContents.value(path); |
|
431 QStringListIterator it(fileNames); |
|
432 bool hasContents = matchAll; |
|
433 if (!matchAll) { // the case filter is not empty - we check if the path contains anything |
|
434 while (it.hasNext()) { |
|
435 QString fileName = it.next(); |
|
436 hasContents = fileName.contains(m_filterPattern, Qt::CaseInsensitive); |
|
437 if (hasContents) // the path contains at least one resource which matches the filter |
|
438 break; |
|
439 } |
|
440 } |
|
441 |
|
442 pathToMatchingContents[path] = hasContents; |
|
443 pathToVisible[path] = hasContents; |
|
444 |
|
445 if (hasContents) { // if the path is going to be shown we need to show all its parent paths |
|
446 QString parentPath = m_pathToParentPath.value(path); |
|
447 while (!parentPath.isEmpty()) { |
|
448 QString p = parentPath; |
|
449 if (pathToVisible.value(p)) // parent path is already shown, we break the loop |
|
450 break; |
|
451 pathToVisible[p] = true; |
|
452 parentPath = m_pathToParentPath.value(p); |
|
453 } |
|
454 } |
|
455 |
|
456 QStringList subPaths = m_pathToSubPaths.value(path); // we do the same for children paths |
|
457 QStringListIterator itSubPaths(subPaths); |
|
458 while (itSubPaths.hasNext()) |
|
459 pathQueue.enqueue(itSubPaths.next()); |
|
460 } |
|
461 |
|
462 // we setup here new path and resource to be activated |
|
463 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem()); |
|
464 QString newCurrentPath = currentPath; |
|
465 QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); |
|
466 if (!matchAll) { |
|
467 bool searchForNewPathWithContents = true; |
|
468 |
|
469 if (!currentPath.isEmpty()) { // if the currentPath is empty we will search for a new path too |
|
470 QMap<QString, bool>::ConstIterator it = pathToMatchingContents.constFind(currentPath); |
|
471 if (it != pathToMatchingContents.constEnd() && it.value()) // the current item has contents, we don't need to search for another path |
|
472 searchForNewPathWithContents = false; |
|
473 } |
|
474 |
|
475 if (searchForNewPathWithContents) { |
|
476 // we find the first path with the matching contents |
|
477 QMap<QString, bool>::ConstIterator itContents = pathToMatchingContents.constBegin(); |
|
478 while (itContents != pathToMatchingContents.constEnd()) { |
|
479 if (itContents.value()) { |
|
480 newCurrentPath = itContents.key(); // the new path will be activated |
|
481 break; |
|
482 } |
|
483 |
|
484 itContents++; |
|
485 } |
|
486 } |
|
487 |
|
488 QFileInfo fi(currentResource); |
|
489 if (!fi.fileName().contains(m_filterPattern, Qt::CaseInsensitive)) { // the case when the current resource is filtered out |
|
490 const QStringList fileNames = m_pathToContents.value(newCurrentPath); |
|
491 QStringListIterator it(fileNames); |
|
492 while (it.hasNext()) { // we try to select the first matching resource from the newCurrentPath |
|
493 QString fileName = it.next(); |
|
494 if (fileName.contains(m_filterPattern, Qt::CaseInsensitive)) { |
|
495 QDir dirPath(newCurrentPath); |
|
496 currentResource = dirPath.absoluteFilePath(fileName); // the new resource inside newCurrentPath will be activated |
|
497 break; |
|
498 } |
|
499 } |
|
500 } |
|
501 } |
|
502 |
|
503 QTreeWidgetItem *newCurrentItem = m_pathToItem.value(newCurrentPath); |
|
504 if (currentPath != newCurrentPath) |
|
505 m_treeWidget->setCurrentItem(newCurrentItem); |
|
506 else |
|
507 slotCurrentPathChanged(newCurrentItem); // trigger filtering on the current path |
|
508 |
|
509 QListWidgetItem *currentResourceItem = m_resourceToItem.value(currentResource); |
|
510 if (currentResourceItem) { |
|
511 m_listWidget->setCurrentItem(currentResourceItem); |
|
512 m_listWidget->scrollToItem(currentResourceItem); |
|
513 } |
|
514 |
|
515 QMapIterator<QString, bool> it(pathToVisible); // hide all paths filtered out |
|
516 while (it.hasNext()) { |
|
517 const QString path = it.next().key(); |
|
518 QTreeWidgetItem *item = m_pathToItem.value(path); |
|
519 if (item) |
|
520 item->setHidden(!it.value()); |
|
521 } |
|
522 } |
|
523 |
|
524 QTreeWidgetItem *QtResourceViewPrivate::createPath(const QString &path, QTreeWidgetItem *parent) |
|
525 { |
|
526 QTreeWidgetItem *item = 0; |
|
527 if (parent) |
|
528 item = new QTreeWidgetItem(parent); |
|
529 else |
|
530 item = new QTreeWidgetItem(m_treeWidget); |
|
531 m_pathToItem[path] = item; |
|
532 m_itemToPath[item] = path; |
|
533 QString substPath; |
|
534 if (parent) { |
|
535 QFileInfo di(path); |
|
536 substPath = di.fileName(); |
|
537 } else { |
|
538 substPath = QLatin1String("<resource root>"); |
|
539 } |
|
540 item->setText(0, substPath); |
|
541 item->setToolTip(0, path); |
|
542 return item; |
|
543 } |
|
544 |
|
545 void QtResourceViewPrivate::createResources(const QString &path) |
|
546 { |
|
547 const bool matchAll = m_filterPattern.isEmpty(); |
|
548 |
|
549 QDir dir(path); |
|
550 QStringList fileNames = m_pathToContents.value(path); |
|
551 QStringListIterator it(fileNames); |
|
552 while (it.hasNext()) { |
|
553 QString fileName = it.next(); |
|
554 const bool showProperty = matchAll || fileName.contains(m_filterPattern, Qt::CaseInsensitive); |
|
555 if (showProperty) { |
|
556 QString filePath = dir.absoluteFilePath(fileName); |
|
557 QFileInfo fi(filePath); |
|
558 if (fi.isFile()) { |
|
559 QListWidgetItem *item = new QListWidgetItem(fi.fileName(), m_listWidget); |
|
560 const QPixmap pix = QPixmap(filePath); |
|
561 if (pix.isNull()) { |
|
562 item->setToolTip(filePath); |
|
563 } else { |
|
564 item->setIcon(QIcon(makeThumbnail(pix))); |
|
565 const QSize size = pix.size(); |
|
566 item->setToolTip(QtResourceView::tr("Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath)); |
|
567 } |
|
568 item->setFlags(item->flags() | Qt::ItemIsDragEnabled); |
|
569 item->setData(Qt::UserRole, filePath); |
|
570 m_itemToResource[item] = filePath; |
|
571 m_resourceToItem[filePath] = item; |
|
572 } |
|
573 } |
|
574 } |
|
575 } |
|
576 |
|
577 // -------------- QtResourceView |
|
578 |
|
579 QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent) : |
|
580 QWidget(parent), |
|
581 d_ptr(new QtResourceViewPrivate(core)) |
|
582 { |
|
583 d_ptr->q_ptr = this; |
|
584 |
|
585 QIcon editIcon = QIcon::fromTheme("document-properties", qdesigner_internal::createIconSet(QLatin1String("edit.png"))); |
|
586 d_ptr->m_editResourcesAction = new QAction(editIcon, tr("Edit Resources..."), this); |
|
587 d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction); |
|
588 connect(d_ptr->m_editResourcesAction, SIGNAL(triggered()), this, SLOT(slotEditResources())); |
|
589 d_ptr->m_editResourcesAction->setEnabled(false); |
|
590 |
|
591 QIcon refreshIcon = QIcon::fromTheme("view-refresh", qdesigner_internal::createIconSet(QLatin1String("reload.png"))); |
|
592 d_ptr->m_reloadResourcesAction = new QAction(refreshIcon, tr("Reload"), this); |
|
593 |
|
594 d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction); |
|
595 connect(d_ptr->m_reloadResourcesAction, SIGNAL(triggered()), this, SLOT(slotReloadResources())); |
|
596 d_ptr->m_reloadResourcesAction->setEnabled(false); |
|
597 |
|
598 QIcon copyIcon = QIcon::fromTheme("edit-copy", qdesigner_internal::createIconSet(QLatin1String("editcopy.png"))); |
|
599 d_ptr->m_copyResourcePathAction = new QAction(copyIcon, tr("Copy Path"), this); |
|
600 connect(d_ptr->m_copyResourcePathAction, SIGNAL(triggered()), this, SLOT(slotCopyResourcePath())); |
|
601 d_ptr->m_copyResourcePathAction->setEnabled(false); |
|
602 |
|
603 //d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(0, qdesigner_internal::FilterWidget::LayoutAlignNone); |
|
604 d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(d_ptr->m_toolBar); |
|
605 d_ptr->m_toolBar->addWidget(d_ptr->m_filterWidget); |
|
606 connect(d_ptr->m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(slotFilterChanged(QString))); |
|
607 |
|
608 d_ptr->m_splitter = new QSplitter; |
|
609 d_ptr->m_splitter->setChildrenCollapsible(false); |
|
610 d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget); |
|
611 d_ptr->m_splitter->addWidget(d_ptr->m_listWidget); |
|
612 |
|
613 QLayout *layout = new QVBoxLayout(this); |
|
614 layout->setMargin(0); |
|
615 layout->setSpacing(0); |
|
616 layout->addWidget(d_ptr->m_toolBar); |
|
617 layout->addWidget(d_ptr->m_splitter); |
|
618 |
|
619 d_ptr->m_treeWidget->setColumnCount(1); |
|
620 d_ptr->m_treeWidget->header()->hide(); |
|
621 d_ptr->m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); |
|
622 |
|
623 d_ptr->m_listWidget->setViewMode(QListView::IconMode); |
|
624 d_ptr->m_listWidget->setResizeMode(QListView::Adjust); |
|
625 d_ptr->m_listWidget->setIconSize(QSize(48, 48)); |
|
626 d_ptr->m_listWidget->setGridSize(QSize(64, 64)); |
|
627 |
|
628 connect(d_ptr->m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), |
|
629 this, SLOT(slotCurrentPathChanged(QTreeWidgetItem *))); |
|
630 connect(d_ptr->m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), |
|
631 this, SLOT(slotCurrentResourceChanged(QListWidgetItem *))); |
|
632 connect(d_ptr->m_listWidget, SIGNAL(itemActivated(QListWidgetItem *)), |
|
633 this, SLOT(slotResourceActivated(QListWidgetItem *))); |
|
634 d_ptr->m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu); |
|
635 connect(d_ptr->m_listWidget, SIGNAL(customContextMenuRequested(QPoint)), |
|
636 this, SLOT(slotListWidgetContextMenuRequested(QPoint))); |
|
637 } |
|
638 |
|
639 QtResourceView::~QtResourceView() |
|
640 { |
|
641 if (!d_ptr->m_settingsKey.isEmpty()) |
|
642 d_ptr->saveSettings(); |
|
643 } |
|
644 |
|
645 bool QtResourceView::event(QEvent *event) |
|
646 { |
|
647 if (event->type() == QEvent::Show) { |
|
648 d_ptr->m_listWidget->scrollToItem(d_ptr->m_listWidget->currentItem()); |
|
649 d_ptr->m_treeWidget->scrollToItem(d_ptr->m_treeWidget->currentItem()); |
|
650 } |
|
651 return QWidget::event(event); |
|
652 } |
|
653 |
|
654 QtResourceModel *QtResourceView::model() const |
|
655 { |
|
656 return d_ptr->m_resourceModel; |
|
657 } |
|
658 |
|
659 QString QtResourceView::selectedResource() const |
|
660 { |
|
661 QListWidgetItem *item = d_ptr->m_listWidget->currentItem(); |
|
662 return d_ptr->m_itemToResource.value(item); |
|
663 } |
|
664 |
|
665 void QtResourceView::selectResource(const QString &resource) |
|
666 { |
|
667 QFileInfo fi(resource); |
|
668 QDir dir = fi.absoluteDir(); |
|
669 if (fi.isDir()) |
|
670 dir = QDir(resource); |
|
671 QString dirPath = dir.absolutePath(); |
|
672 QMap<QString, QTreeWidgetItem *>::const_iterator it; |
|
673 while ((it = d_ptr->m_pathToItem.find(dirPath)) == d_ptr->m_pathToItem.constEnd()) { |
|
674 if (!dir.cdUp()) |
|
675 break; |
|
676 dirPath = dir.absolutePath(); |
|
677 } |
|
678 if (it != d_ptr->m_pathToItem.constEnd()) { |
|
679 QTreeWidgetItem *treeItem = it.value(); |
|
680 d_ptr->m_treeWidget->setCurrentItem(treeItem); |
|
681 d_ptr->m_treeWidget->scrollToItem(treeItem); |
|
682 // expand all up to current one is done by qt |
|
683 // list widget is already propagated (currrent changed was sent by qt) |
|
684 QListWidgetItem *item = d_ptr->m_resourceToItem.value(resource); |
|
685 if (item) { |
|
686 d_ptr->m_listWidget->setCurrentItem(item); |
|
687 d_ptr->m_listWidget->scrollToItem(item); |
|
688 } |
|
689 } |
|
690 } |
|
691 |
|
692 QString QtResourceView::settingsKey() const |
|
693 { |
|
694 return d_ptr->m_settingsKey; |
|
695 } |
|
696 |
|
697 void QtResourceView::setSettingsKey(const QString &key) |
|
698 { |
|
699 if (d_ptr->m_settingsKey == key) |
|
700 return; |
|
701 |
|
702 d_ptr->m_settingsKey = key; |
|
703 |
|
704 if (key.isEmpty()) |
|
705 return; |
|
706 |
|
707 d_ptr->restoreSettings(); |
|
708 } |
|
709 |
|
710 void QtResourceView::setResourceModel(QtResourceModel *model) |
|
711 { |
|
712 if (d_ptr->m_resourceModel) { |
|
713 disconnect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet *, bool)), |
|
714 this, SLOT(slotResourceSetActivated(QtResourceSet *))); |
|
715 } |
|
716 |
|
717 // clear here |
|
718 d_ptr->m_treeWidget->clear(); |
|
719 d_ptr->m_listWidget->clear(); |
|
720 |
|
721 d_ptr->m_resourceModel = model; |
|
722 |
|
723 if (!d_ptr->m_resourceModel) |
|
724 return; |
|
725 |
|
726 connect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet *, bool)), |
|
727 this, SLOT(slotResourceSetActivated(QtResourceSet *))); |
|
728 |
|
729 // fill new here |
|
730 d_ptr->slotResourceSetActivated(d_ptr->m_resourceModel->currentResourceSet()); |
|
731 } |
|
732 |
|
733 bool QtResourceView::isResourceEditingEnabled() const |
|
734 { |
|
735 return d_ptr->m_resourceEditingEnabled; |
|
736 } |
|
737 |
|
738 void QtResourceView::setResourceEditingEnabled(bool enable) |
|
739 { |
|
740 d_ptr->m_resourceEditingEnabled = enable; |
|
741 d_ptr->updateActions(); |
|
742 } |
|
743 |
|
744 void QtResourceView::setDragEnabled(bool dragEnabled) |
|
745 { |
|
746 d_ptr->m_listWidget->setDragEnabled(dragEnabled); |
|
747 } |
|
748 |
|
749 bool QtResourceView::dragEnabled() const |
|
750 { |
|
751 return d_ptr->m_listWidget->dragEnabled(); |
|
752 } |
|
753 |
|
754 QString QtResourceView::encodeMimeData(ResourceType resourceType, const QString &path) |
|
755 { |
|
756 QDomDocument doc; |
|
757 QDomElement elem = doc.createElement(QLatin1String(elementResourceData)); |
|
758 switch (resourceType) { |
|
759 case ResourceImage: |
|
760 elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeImage)); |
|
761 break; |
|
762 case ResourceStyleSheet: |
|
763 elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeStyleSheet)); |
|
764 break; |
|
765 case ResourceOther: |
|
766 elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeOther)); |
|
767 break; |
|
768 } |
|
769 elem.setAttribute(QLatin1String(fileAttribute), path); |
|
770 doc.appendChild(elem); |
|
771 return doc.toString(); |
|
772 } |
|
773 |
|
774 bool QtResourceView::decodeMimeData(const QMimeData *md, ResourceType *t, QString *file) |
|
775 { |
|
776 return md->hasText() ? decodeMimeData(md->text(), t, file) : false; |
|
777 } |
|
778 |
|
779 bool QtResourceView::decodeMimeData(const QString &text, ResourceType *t, QString *file) |
|
780 { |
|
781 |
|
782 const QString docElementName = QLatin1String(elementResourceData); |
|
783 static const QString docElementString = QLatin1Char('<') + docElementName; |
|
784 |
|
785 if (text.isEmpty() || text.indexOf(docElementString) == -1) |
|
786 return false; |
|
787 |
|
788 QDomDocument doc; |
|
789 if (!doc.setContent(text)) |
|
790 return false; |
|
791 |
|
792 const QDomElement domElement = doc.documentElement(); |
|
793 if (domElement.tagName() != docElementName) |
|
794 return false; |
|
795 |
|
796 if (t) { |
|
797 const QString typeAttr = QLatin1String(typeAttribute); |
|
798 if (domElement.hasAttribute (typeAttr)) { |
|
799 const QString typeValue = domElement.attribute(typeAttr, QLatin1String(typeOther)); |
|
800 if (typeValue == QLatin1String(typeImage)) { |
|
801 *t = ResourceImage; |
|
802 } else { |
|
803 *t = typeValue == QLatin1String(typeStyleSheet) ? ResourceStyleSheet : ResourceOther; |
|
804 } |
|
805 } |
|
806 } |
|
807 if (file) { |
|
808 const QString fileAttr = QLatin1String(fileAttribute); |
|
809 if (domElement.hasAttribute(fileAttr)) { |
|
810 *file = domElement.attribute(fileAttr, QString()); |
|
811 } else { |
|
812 file->clear(); |
|
813 } |
|
814 } |
|
815 return true; |
|
816 } |
|
817 |
|
818 // ---------------------------- QtResourceViewDialogPrivate |
|
819 |
|
820 class QtResourceViewDialogPrivate |
|
821 { |
|
822 QtResourceViewDialog *q_ptr; |
|
823 Q_DECLARE_PUBLIC(QtResourceViewDialog) |
|
824 public: |
|
825 QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core); |
|
826 |
|
827 void slotResourceSelected(const QString &resource) { setOkButtonEnabled(!resource.isEmpty()); } |
|
828 void setOkButtonEnabled(bool v) { m_box->button(QDialogButtonBox::Ok)->setEnabled(v); } |
|
829 |
|
830 QDesignerFormEditorInterface *m_core; |
|
831 QtResourceView *m_view; |
|
832 QDialogButtonBox *m_box; |
|
833 }; |
|
834 |
|
835 QtResourceViewDialogPrivate::QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core) : |
|
836 q_ptr(0), |
|
837 m_core(core), |
|
838 m_view(new QtResourceView(core)), |
|
839 m_box(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)) |
|
840 { |
|
841 m_view->setSettingsKey(QLatin1String(ResourceViewDialogC)); |
|
842 } |
|
843 |
|
844 // ------------ QtResourceViewDialog |
|
845 QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent) : |
|
846 QDialog(parent), |
|
847 d_ptr(new QtResourceViewDialogPrivate(core)) |
|
848 { |
|
849 setWindowTitle(tr("Select Resource")); |
|
850 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); |
|
851 d_ptr->q_ptr = this; |
|
852 QVBoxLayout *layout = new QVBoxLayout(this); |
|
853 layout->addWidget(d_ptr->m_view); |
|
854 layout->addWidget(d_ptr->m_box); |
|
855 connect(d_ptr->m_box, SIGNAL(accepted()), this, SLOT(accept())); |
|
856 connect(d_ptr->m_box, SIGNAL(rejected()), this, SLOT(reject())); |
|
857 connect(d_ptr->m_view, SIGNAL(resourceActivated(QString)), this, SLOT(accept())); |
|
858 connect(d_ptr->m_view, SIGNAL(resourceSelected(QString)), this, SLOT(slotResourceSelected(QString))); |
|
859 d_ptr->setOkButtonEnabled(false); |
|
860 d_ptr->m_view->setResourceModel(core->resourceModel()); |
|
861 |
|
862 QDesignerSettingsInterface *settings = core->settingsManager(); |
|
863 settings->beginGroup(QLatin1String(ResourceViewDialogC)); |
|
864 |
|
865 if (settings->contains(QLatin1String(Geometry))) |
|
866 setGeometry(settings->value(QLatin1String(Geometry)).toRect()); |
|
867 |
|
868 settings->endGroup(); |
|
869 } |
|
870 |
|
871 QtResourceViewDialog::~QtResourceViewDialog() |
|
872 { |
|
873 QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager(); |
|
874 settings->beginGroup(QLatin1String(ResourceViewDialogC)); |
|
875 |
|
876 settings->setValue(QLatin1String(Geometry), geometry()); |
|
877 |
|
878 settings->endGroup(); |
|
879 } |
|
880 |
|
881 QString QtResourceViewDialog::selectedResource() const |
|
882 { |
|
883 return d_ptr->m_view->selectedResource(); |
|
884 } |
|
885 |
|
886 void QtResourceViewDialog::selectResource(const QString &path) |
|
887 { |
|
888 d_ptr->m_view->selectResource(path); |
|
889 } |
|
890 |
|
891 bool QtResourceViewDialog::isResourceEditingEnabled() const |
|
892 { |
|
893 return d_ptr->m_view->isResourceEditingEnabled(); |
|
894 } |
|
895 |
|
896 void QtResourceViewDialog::setResourceEditingEnabled(bool enable) |
|
897 { |
|
898 d_ptr->m_view->setResourceEditingEnabled(enable); |
|
899 } |
|
900 |
|
901 QT_END_NAMESPACE |
|
902 |
|
903 #include "moc_qtresourceview_p.cpp" |