73 if (supportedActions == Qt::MoveAction)
76 QListWidgetItem *item = currentItem();
80 const QString filePath = item->data(Qt::UserRole).toString();
81 const QIcon icon = item->icon();
83 QMimeData *mimeData =
new QMimeData;
84 const QtResourceView::ResourceType type = icon.isNull() ? QtResourceView::ResourceOther : QtResourceView::ResourceImage;
85 mimeData->setText(QtResourceView::encodeMimeData(type , filePath));
87 QDrag *drag =
new QDrag(
this);
89 const QSize size = icon.actualSize(iconSize());
90 drag->setPixmap(icon.pixmap(size));
91 drag->setHotSpot(QPoint(size.width() / 2, size.height() / 2));
94 drag->setMimeData(mimeData);
95 drag->exec(Qt::CopyAction);
247QPixmap QtResourceViewPrivate::makeThumbnail(
const QPixmap &pix)
const
249 int w = qMax(48, pix.width());
250 int h = qMax(48, pix.height());
251 QRect imgRect(0, 0, w, h);
252 QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
255 QRect r(0, 0, pix.width(), pix.height());
256 r.moveCenter(imgRect.center());
258 p.drawPixmap(r.topLeft(), pix);
260 return QPixmap::fromImage(img);
275void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet)
277 Q_UNUSED(resourceSet);
281 storeExpansionState();
282 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem());
283 const QString currentResource = m_itemToResource.value(m_listWidget->currentItem());
284 m_treeWidget->clear();
285 m_pathToContents.clear();
286 m_pathToParentPath.clear();
287 m_pathToSubPaths.clear();
288 m_pathToItem.clear();
289 m_itemToPath.clear();
290 m_listWidget->clear();
291 m_resourceToItem.clear();
292 m_itemToResource.clear();
295 applyExpansionState();
297 if (!currentResource.isEmpty())
298 q_ptr->selectResource(currentResource);
299 else if (!currentPath.isEmpty())
300 q_ptr->selectResource(currentPath);
301 filterOutResources();
337void QtResourceViewPrivate::createPaths()
339 if (!m_resourceModel)
343 const QString root(u":/"_s);
345 QMap<QString, QString> contents = m_resourceModel->contents();
346 for (
auto it = contents.cbegin(), end = contents.cend(); it != end; ++it) {
347 const QFileInfo fi(it.key());
348 QString dirPath = fi.absolutePath();
349 m_pathToContents[dirPath].append(fi.fileName());
350 while (!m_pathToParentPath.contains(dirPath) && dirPath != root) {
351 const QFileInfo fd(dirPath);
352 const QString parentDirPath = fd.absolutePath();
353 m_pathToParentPath[dirPath] = parentDirPath;
354 m_pathToSubPaths[parentDirPath].append(dirPath);
355 dirPath = parentDirPath;
359 QQueue<std::pair<QString, QTreeWidgetItem *>> pathToParentItemQueue;
360 pathToParentItemQueue.enqueue(std::make_pair(root,
static_cast<QTreeWidgetItem *>(
nullptr)));
361 while (!pathToParentItemQueue.isEmpty()) {
362 std::pair<QString, QTreeWidgetItem *> pathToParentItem = pathToParentItemQueue.dequeue();
363 const QString path = pathToParentItem.first;
364 QTreeWidgetItem *item = createPath(path, pathToParentItem.second);
365 const QStringList subPaths = m_pathToSubPaths.value(path);
366 for (
const QString &subPath : subPaths)
367 pathToParentItemQueue.enqueue(std::make_pair(subPath, item));
371void QtResourceViewPrivate::filterOutResources()
373 QMap<QString,
bool> pathToMatchingContents;
374 QMap<QString,
bool> pathToVisible;
382 const bool matchAll = m_filterPattern.isEmpty();
383 const QString root(u":/"_s);
385 QQueue<QString> pathQueue;
386 pathQueue.enqueue(root);
387 while (!pathQueue.isEmpty()) {
388 const QString path = pathQueue.dequeue();
390 bool hasContents = matchAll;
393 const QStringList fileNames = m_pathToContents.value(path);
395 std::any_of(fileNames.cbegin(), fileNames.cend(),
396 [
this] (
const QString &f) {
return f.contains(
this->m_filterPattern, Qt::CaseInsensitive); });
399 pathToMatchingContents[path] = hasContents;
400 pathToVisible[path] = hasContents;
403 QString parentPath = m_pathToParentPath.value(path);
404 while (!parentPath.isEmpty()) {
405 QString p = parentPath;
406 if (pathToVisible.value(p))
408 pathToVisible[p] =
true;
409 parentPath = m_pathToParentPath.value(p);
413 const QStringList subPaths = m_pathToSubPaths.value(path);
414 for (
const QString &subPath : subPaths)
415 pathQueue.enqueue(subPath);
419 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem());
420 QString newCurrentPath = currentPath;
421 QString currentResource = m_itemToResource.value(m_listWidget->currentItem());
423 bool searchForNewPathWithContents =
true;
425 if (!currentPath.isEmpty()) {
426 const auto it = pathToMatchingContents.constFind(currentPath);
427 if (it != pathToMatchingContents.constEnd() && it.value())
428 searchForNewPathWithContents =
false;
431 if (searchForNewPathWithContents) {
433 for (
auto itContents = pathToMatchingContents.cbegin(), cend = pathToMatchingContents.cend(); itContents != cend; ++itContents) {
434 if (itContents.value()) {
435 newCurrentPath = itContents.key();
441 QFileInfo fi(currentResource);
442 if (!fi.fileName().contains(m_filterPattern, Qt::CaseInsensitive)) {
443 const QStringList fileNames = m_pathToContents.value(newCurrentPath);
445 for (
const QString &fileName : fileNames) {
446 if (fileName.contains(m_filterPattern, Qt::CaseInsensitive)) {
447 QDir dirPath(newCurrentPath);
448 currentResource = dirPath.absoluteFilePath(fileName);
455 QTreeWidgetItem *newCurrentItem = m_pathToItem.value(newCurrentPath);
456 if (currentPath != newCurrentPath)
457 m_treeWidget->setCurrentItem(newCurrentItem);
459 slotCurrentPathChanged(newCurrentItem);
461 QListWidgetItem *currentResourceItem = m_resourceToItem.value(currentResource);
462 if (currentResourceItem) {
463 m_listWidget->setCurrentItem(currentResourceItem);
464 m_listWidget->scrollToItem(currentResourceItem);
468 for (
auto it = pathToVisible.cbegin(), end = pathToVisible.cend(); it != end; ++it) {
469 if (QTreeWidgetItem *item = m_pathToItem.value(it.key()))
470 item->setHidden(!it.value());
495void QtResourceViewPrivate::createResources(
const QString &path)
497 const bool matchAll = m_filterPattern.isEmpty();
500 const QStringList fileNames = m_pathToContents.value(path);
501 for (
const QString &fileName : fileNames) {
502 const bool showProperty = matchAll || fileName.contains(m_filterPattern, Qt::CaseInsensitive);
504 QString filePath = dir.absoluteFilePath(fileName);
505 QFileInfo fi(filePath);
507 QListWidgetItem *item =
new QListWidgetItem(fi.fileName(), m_listWidget);
508 const QPixmap pix = QPixmap(filePath);
510 item->setToolTip(filePath);
512 item->setIcon(QIcon(makeThumbnail(pix)));
513 const QSize size = pix.size();
514 item->setToolTip(QtResourceView::tr(
"Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath));
516 item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
517 item->setData(Qt::UserRole, filePath);
518 m_itemToResource[item] = filePath;
519 m_resourceToItem[filePath] = item;
527QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent) :
529 d_ptr(
new QtResourceViewPrivate(core))
533 QIcon editIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::DocumentProperties,
535 d_ptr->m_editResourcesAction =
new QAction(editIcon, tr(
"Edit Resources..."),
this);
536 d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction);
537 connect(d_ptr->m_editResourcesAction, &QAction::triggered,
538 this, [
this] { d_ptr->slotEditResources(); });
539 d_ptr->m_editResourcesAction->setEnabled(
false);
541 QIcon refreshIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::ViewRefresh,
543 d_ptr->m_reloadResourcesAction =
new QAction(refreshIcon, tr(
"Reload"),
this);
545 d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction);
546 connect(d_ptr->m_reloadResourcesAction, &QAction::triggered,
547 this, [
this] { d_ptr->slotReloadResources(); });
548 d_ptr->m_reloadResourcesAction->setEnabled(
false);
550#if QT_CONFIG(clipboard)
551 QIcon copyIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::EditCopy,
553 d_ptr->m_copyResourcePathAction =
new QAction(copyIcon, tr(
"Copy Path"),
this);
554 connect(d_ptr->m_copyResourcePathAction, &QAction::triggered,
555 this, [
this] { d_ptr->slotCopyResourcePath(); });
556 d_ptr->m_copyResourcePathAction->setEnabled(
false);
559 d_ptr->m_filterWidget =
new QWidget(d_ptr->m_toolBar);
560 QHBoxLayout *filterLayout =
new QHBoxLayout(d_ptr->m_filterWidget);
561 filterLayout->setContentsMargins(0, 0, 0, 0);
562 QLineEdit *filterLineEdit =
new QLineEdit(d_ptr->m_filterWidget);
563 connect(filterLineEdit, &QLineEdit::textChanged,
564 this, [
this](
const QString &text) { d_ptr->slotFilterChanged(text); });
565 filterLineEdit->setPlaceholderText(tr(
"Filter"));
566 filterLineEdit->setClearButtonEnabled(
true);
567 filterLayout->addItem(
new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
568 filterLayout->addWidget(filterLineEdit);
569 d_ptr->m_toolBar->addWidget(d_ptr->m_filterWidget);
571 d_ptr->m_splitter =
new QSplitter;
572 d_ptr->m_splitter->setChildrenCollapsible(
false);
573 d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget);
574 d_ptr->m_splitter->addWidget(d_ptr->m_listWidget);
576 QLayout *layout =
new QVBoxLayout(
this);
577 layout->setContentsMargins(QMargins());
578 layout->setSpacing(0);
579 layout->addWidget(d_ptr->m_toolBar);
580 layout->addWidget(d_ptr->m_splitter);
582 d_ptr->m_treeWidget->setColumnCount(1);
583 d_ptr->m_treeWidget->header()->hide();
584 d_ptr->m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
586 d_ptr->m_listWidget->setViewMode(QListView::IconMode);
587 d_ptr->m_listWidget->setResizeMode(QListView::Adjust);
588 d_ptr->m_listWidget->setIconSize(QSize(48, 48));
589 d_ptr->m_listWidget->setGridSize(QSize(64, 64));
591 connect(d_ptr->m_treeWidget, &QTreeWidget::currentItemChanged,
592 this, [
this](QTreeWidgetItem *item) { d_ptr->slotCurrentPathChanged(item); });
593 connect(d_ptr->m_listWidget, &QListWidget::currentItemChanged,
594 this, [
this](QListWidgetItem *item) { d_ptr->slotCurrentResourceChanged(item); });
595 connect(d_ptr->m_listWidget, &QListWidget::itemActivated,
596 this, [
this](QListWidgetItem *item) { d_ptr->slotResourceActivated(item); });
597 d_ptr->m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
598 connect(d_ptr->m_listWidget, &QListWidget::customContextMenuRequested,
599 this, [
this](
const QPoint &point) { d_ptr->slotListWidgetContextMenuRequested(point); });
628void QtResourceView::selectResource(
const QString &resource)
630 if (resource.isEmpty())
632 QFileInfo fi(resource);
633 QDir dir = fi.absoluteDir();
635 dir = QDir(resource);
636 QString dirPath = dir.absolutePath();
637 const auto cend = d_ptr->m_pathToItem.constEnd();
639 while ((it = d_ptr->m_pathToItem.constFind(dirPath)) == cend) {
642 dirPath = dir.absolutePath();
645 QTreeWidgetItem *treeItem = it.value();
646 d_ptr->m_treeWidget->setCurrentItem(treeItem);
647 d_ptr->m_treeWidget->scrollToItem(treeItem);
650 QListWidgetItem *item = d_ptr->m_resourceToItem.value(resource);
652 d_ptr->m_listWidget->setCurrentItem(item);
653 d_ptr->m_listWidget->scrollToItem(item);
676void QtResourceView::setResourceModel(QtResourceModel *model)
678 if (d_ptr->m_resourceModel)
679 disconnect(d_ptr->m_resourceModel, &QtResourceModel::resourceSetActivated,
this,
nullptr);
682 d_ptr->m_treeWidget->clear();
683 d_ptr->m_listWidget->clear();
685 d_ptr->m_resourceModel = model;
687 if (!d_ptr->m_resourceModel)
690 connect(d_ptr->m_resourceModel, &QtResourceModel::resourceSetActivated,
691 this, [
this](QtResourceSet *resource) { d_ptr->slotResourceSetActivated(resource); });
694 d_ptr->slotResourceSetActivated(d_ptr->m_resourceModel->currentResourceSet());
743bool QtResourceView::decodeMimeData(
const QString &text, ResourceType *t, QString *file)
746 static auto docElementName = elementResourceData;
747 static const QString docElementString = u'<' + docElementName;
749 if (text.isEmpty() || text.indexOf(docElementString) == -1)
753 if (!doc.setContent(text))
756 const QDomElement domElement = doc.documentElement();
757 if (domElement.tagName() != docElementName)
761 const QString typeAttr = typeAttribute;
762 if (domElement.hasAttribute (typeAttr)) {
763 const QString typeValue = domElement.attribute(typeAttr, typeOther);
764 if (typeValue == typeImage) {
767 *t = typeValue == typeStyleSheet ? ResourceStyleSheet : ResourceOther;
772 const QString fileAttr = fileAttribute;
773 if (domElement.hasAttribute(fileAttr)) {
774 *file = domElement.attribute(fileAttr, QString());
809QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
811 d_ptr(
new QtResourceViewDialogPrivate(core))
813 setWindowTitle(tr(
"Select Resource"));
815 QVBoxLayout *layout =
new QVBoxLayout(
this);
816 layout->addWidget(d_ptr->m_view);
817 layout->addWidget(d_ptr->m_box);
818 connect(d_ptr->m_box, &QDialogButtonBox::accepted,
this, &QDialog::accept);
819 connect(d_ptr->m_box, &QDialogButtonBox::rejected,
this, &QDialog::reject);
820 connect(d_ptr->m_view, &QtResourceView::resourceActivated,
this, &QDialog::accept);
821 connect(d_ptr->m_view, &QtResourceView::resourceSelected,
822 this, [
this](
const QString &resource) { d_ptr->slotResourceSelected(resource); });
823 d_ptr->setOkButtonEnabled(
false);
824 d_ptr->m_view->setResourceModel(core->resourceModel());
826 QDesignerSettingsInterface *settings = core->settingsManager();
827 settings->beginGroup(ResourceViewDialogC);
829 const QVariant geometry = settings->value(qrvGeometry);
830 if (geometry.metaType().id() == QMetaType::QByteArray)
831 restoreGeometry(geometry.toByteArray());
833 settings->endGroup();