74 if (supportedActions == Qt::MoveAction)
77 QListWidgetItem *item = currentItem();
81 const QString filePath = item->data(Qt::UserRole).toString();
82 const QIcon icon = item->icon();
84 QMimeData *mimeData =
new QMimeData;
85 const QtResourceView::ResourceType type = icon.isNull() ? QtResourceView::ResourceOther : QtResourceView::ResourceImage;
86 mimeData->setText(QtResourceView::encodeMimeData(type , filePath));
88 QDrag *drag =
new QDrag(
this);
90 const QSize size = icon.actualSize(iconSize());
91 drag->setPixmap(icon.pixmap(size));
92 drag->setHotSpot(QPoint(size.width() / 2, size.height() / 2));
95 drag->setMimeData(mimeData);
96 drag->exec(Qt::CopyAction);
248QPixmap QtResourceViewPrivate::makeThumbnail(
const QPixmap &pix)
const
250 int w = qMax(48, pix.width());
251 int h = qMax(48, pix.height());
252 QRect imgRect(0, 0, w, h);
253 QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
256 QRect r(0, 0, pix.width(), pix.height());
257 r.moveCenter(imgRect.center());
259 p.drawPixmap(r.topLeft(), pix);
261 return QPixmap::fromImage(img);
276void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet)
278 Q_UNUSED(resourceSet);
282 storeExpansionState();
283 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem());
284 const QString currentResource = m_itemToResource.value(m_listWidget->currentItem());
285 m_treeWidget->clear();
286 m_pathToContents.clear();
287 m_pathToParentPath.clear();
288 m_pathToSubPaths.clear();
289 m_pathToItem.clear();
290 m_itemToPath.clear();
291 m_listWidget->clear();
292 m_resourceToItem.clear();
293 m_itemToResource.clear();
296 applyExpansionState();
298 if (!currentResource.isEmpty())
299 q_ptr->selectResource(currentResource);
300 else if (!currentPath.isEmpty())
301 q_ptr->selectResource(currentPath);
302 filterOutResources();
338void QtResourceViewPrivate::createPaths()
340 if (!m_resourceModel)
344 const QString root(u":/"_s);
346 QMap<QString, QString> contents = m_resourceModel->contents();
347 for (
auto it = contents.cbegin(), end = contents.cend(); it != end; ++it) {
348 const QFileInfo fi(it.key());
349 QString dirPath = fi.absolutePath();
350 m_pathToContents[dirPath].append(fi.fileName());
351 while (!m_pathToParentPath.contains(dirPath) && dirPath != root) {
352 const QFileInfo fd(dirPath);
353 const QString parentDirPath = fd.absolutePath();
354 m_pathToParentPath[dirPath] = parentDirPath;
355 m_pathToSubPaths[parentDirPath].append(dirPath);
356 dirPath = parentDirPath;
360 QQueue<std::pair<QString, QTreeWidgetItem *>> pathToParentItemQueue;
361 pathToParentItemQueue.enqueue(std::make_pair(root,
static_cast<QTreeWidgetItem *>(
nullptr)));
362 while (!pathToParentItemQueue.isEmpty()) {
363 std::pair<QString, QTreeWidgetItem *> pathToParentItem = pathToParentItemQueue.dequeue();
364 const QString path = pathToParentItem.first;
365 QTreeWidgetItem *item = createPath(path, pathToParentItem.second);
366 const QStringList subPaths = m_pathToSubPaths.value(path);
367 for (
const QString &subPath : subPaths)
368 pathToParentItemQueue.enqueue(std::make_pair(subPath, item));
372void QtResourceViewPrivate::filterOutResources()
374 QMap<QString,
bool> pathToMatchingContents;
375 QMap<QString,
bool> pathToVisible;
383 const bool matchAll = m_filterPattern.isEmpty();
384 const QString root(u":/"_s);
386 QQueue<QString> pathQueue;
387 pathQueue.enqueue(root);
388 while (!pathQueue.isEmpty()) {
389 const QString path = pathQueue.dequeue();
391 bool hasContents = matchAll;
394 const QStringList fileNames = m_pathToContents.value(path);
396 std::any_of(fileNames.cbegin(), fileNames.cend(),
397 [
this] (
const QString &f) {
return f.contains(
this->m_filterPattern, Qt::CaseInsensitive); });
400 pathToMatchingContents[path] = hasContents;
401 pathToVisible[path] = hasContents;
404 QString parentPath = m_pathToParentPath.value(path);
405 while (!parentPath.isEmpty()) {
406 QString p = parentPath;
407 if (pathToVisible.value(p))
409 pathToVisible[p] =
true;
410 parentPath = m_pathToParentPath.value(p);
414 const QStringList subPaths = m_pathToSubPaths.value(path);
415 for (
const QString &subPath : subPaths)
416 pathQueue.enqueue(subPath);
420 const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem());
421 QString newCurrentPath = currentPath;
422 QString currentResource = m_itemToResource.value(m_listWidget->currentItem());
424 bool searchForNewPathWithContents =
true;
426 if (!currentPath.isEmpty()) {
427 const auto it = pathToMatchingContents.constFind(currentPath);
428 if (it != pathToMatchingContents.constEnd() && it.value())
429 searchForNewPathWithContents =
false;
432 if (searchForNewPathWithContents) {
434 for (
auto itContents = pathToMatchingContents.cbegin(), cend = pathToMatchingContents.cend(); itContents != cend; ++itContents) {
435 if (itContents.value()) {
436 newCurrentPath = itContents.key();
442 QFileInfo fi(currentResource);
443 if (!fi.fileName().contains(m_filterPattern, Qt::CaseInsensitive)) {
444 const QStringList fileNames = m_pathToContents.value(newCurrentPath);
446 for (
const QString &fileName : fileNames) {
447 if (fileName.contains(m_filterPattern, Qt::CaseInsensitive)) {
448 QDir dirPath(newCurrentPath);
449 currentResource = dirPath.absoluteFilePath(fileName);
456 QTreeWidgetItem *newCurrentItem = m_pathToItem.value(newCurrentPath);
457 if (currentPath != newCurrentPath)
458 m_treeWidget->setCurrentItem(newCurrentItem);
460 slotCurrentPathChanged(newCurrentItem);
462 QListWidgetItem *currentResourceItem = m_resourceToItem.value(currentResource);
463 if (currentResourceItem) {
464 m_listWidget->setCurrentItem(currentResourceItem);
465 m_listWidget->scrollToItem(currentResourceItem);
469 for (
auto it = pathToVisible.cbegin(), end = pathToVisible.cend(); it != end; ++it) {
470 if (QTreeWidgetItem *item = m_pathToItem.value(it.key()))
471 item->setHidden(!it.value());
496void QtResourceViewPrivate::createResources(
const QString &path)
498 const bool matchAll = m_filterPattern.isEmpty();
501 const QStringList fileNames = m_pathToContents.value(path);
502 for (
const QString &fileName : fileNames) {
503 const bool showProperty = matchAll || fileName.contains(m_filterPattern, Qt::CaseInsensitive);
505 QString filePath = dir.absoluteFilePath(fileName);
506 QFileInfo fi(filePath);
508 QListWidgetItem *item =
new QListWidgetItem(fi.fileName(), m_listWidget);
509 const QPixmap pix = QPixmap(filePath);
511 item->setToolTip(filePath);
513 item->setIcon(QIcon(makeThumbnail(pix)));
514 const QSize size = pix.size();
515 item->setToolTip(QtResourceView::tr(
"Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath));
517 item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
518 item->setData(Qt::UserRole, filePath);
519 m_itemToResource[item] = filePath;
520 m_resourceToItem[filePath] = item;
528QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent) :
530 d_ptr(
new QtResourceViewPrivate(core))
534 QIcon editIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::DocumentProperties,
536 d_ptr->m_editResourcesAction =
new QAction(editIcon, tr(
"Edit Resources..."),
this);
537 d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction);
538 connect(d_ptr->m_editResourcesAction, &QAction::triggered,
539 this, [
this] { d_ptr->slotEditResources(); });
540 d_ptr->m_editResourcesAction->setEnabled(
false);
542 QIcon refreshIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::ViewRefresh,
544 d_ptr->m_reloadResourcesAction =
new QAction(refreshIcon, tr(
"Reload"),
this);
546 d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction);
547 connect(d_ptr->m_reloadResourcesAction, &QAction::triggered,
548 this, [
this] { d_ptr->slotReloadResources(); });
549 d_ptr->m_reloadResourcesAction->setEnabled(
false);
551#if QT_CONFIG(clipboard)
552 QIcon copyIcon = qdesigner_internal::createIconSet(QIcon::ThemeIcon::EditCopy,
554 d_ptr->m_copyResourcePathAction =
new QAction(copyIcon, tr(
"Copy Path"),
this);
555 connect(d_ptr->m_copyResourcePathAction, &QAction::triggered,
556 this, [
this] { d_ptr->slotCopyResourcePath(); });
557 d_ptr->m_copyResourcePathAction->setEnabled(
false);
560 d_ptr->m_filterWidget =
new QWidget(d_ptr->m_toolBar);
561 QHBoxLayout *filterLayout =
new QHBoxLayout(d_ptr->m_filterWidget);
562 filterLayout->setContentsMargins(0, 0, 0, 0);
563 QLineEdit *filterLineEdit =
new QLineEdit(d_ptr->m_filterWidget);
564 connect(filterLineEdit, &QLineEdit::textChanged,
565 this, [
this](
const QString &text) { d_ptr->slotFilterChanged(text); });
566 filterLineEdit->setPlaceholderText(tr(
"Filter"));
567 filterLineEdit->setClearButtonEnabled(
true);
568 filterLayout->addItem(
new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored));
569 filterLayout->addWidget(filterLineEdit);
570 d_ptr->m_toolBar->addWidget(d_ptr->m_filterWidget);
572 d_ptr->m_splitter =
new QSplitter;
573 d_ptr->m_splitter->setChildrenCollapsible(
false);
574 d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget);
575 d_ptr->m_splitter->addWidget(d_ptr->m_listWidget);
577 QLayout *layout =
new QVBoxLayout(
this);
578 layout->setContentsMargins(QMargins());
579 layout->setSpacing(0);
580 layout->addWidget(d_ptr->m_toolBar);
581 layout->addWidget(d_ptr->m_splitter);
583 d_ptr->m_treeWidget->setColumnCount(1);
584 d_ptr->m_treeWidget->header()->hide();
585 d_ptr->m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
587 d_ptr->m_listWidget->setViewMode(QListView::IconMode);
588 d_ptr->m_listWidget->setResizeMode(QListView::Adjust);
589 d_ptr->m_listWidget->setIconSize(QSize(48, 48));
590 d_ptr->m_listWidget->setGridSize(QSize(64, 64));
592 connect(d_ptr->m_treeWidget, &QTreeWidget::currentItemChanged,
593 this, [
this](QTreeWidgetItem *item) { d_ptr->slotCurrentPathChanged(item); });
594 connect(d_ptr->m_listWidget, &QListWidget::currentItemChanged,
595 this, [
this](QListWidgetItem *item) { d_ptr->slotCurrentResourceChanged(item); });
596 connect(d_ptr->m_listWidget, &QListWidget::itemActivated,
597 this, [
this](QListWidgetItem *item) { d_ptr->slotResourceActivated(item); });
598 d_ptr->m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
599 connect(d_ptr->m_listWidget, &QListWidget::customContextMenuRequested,
600 this, [
this](
const QPoint &point) { d_ptr->slotListWidgetContextMenuRequested(point); });
629void QtResourceView::selectResource(
const QString &resource)
631 if (resource.isEmpty())
633 QFileInfo fi(resource);
634 QDir dir = fi.absoluteDir();
636 dir = QDir(resource);
637 QString dirPath = dir.absolutePath();
638 const auto cend = d_ptr->m_pathToItem.constEnd();
640 while ((it = d_ptr->m_pathToItem.constFind(dirPath)) == cend) {
643 dirPath = dir.absolutePath();
646 QTreeWidgetItem *treeItem = it.value();
647 d_ptr->m_treeWidget->setCurrentItem(treeItem);
648 d_ptr->m_treeWidget->scrollToItem(treeItem);
651 QListWidgetItem *item = d_ptr->m_resourceToItem.value(resource);
653 d_ptr->m_listWidget->setCurrentItem(item);
654 d_ptr->m_listWidget->scrollToItem(item);
677void QtResourceView::setResourceModel(QtResourceModel *model)
679 if (d_ptr->m_resourceModel)
680 disconnect(d_ptr->m_resourceModel, &QtResourceModel::resourceSetActivated,
this,
nullptr);
683 d_ptr->m_treeWidget->clear();
684 d_ptr->m_listWidget->clear();
686 d_ptr->m_resourceModel = model;
688 if (!d_ptr->m_resourceModel)
691 connect(d_ptr->m_resourceModel, &QtResourceModel::resourceSetActivated,
692 this, [
this](QtResourceSet *resource) { d_ptr->slotResourceSetActivated(resource); });
695 d_ptr->slotResourceSetActivated(d_ptr->m_resourceModel->currentResourceSet());
744bool QtResourceView::decodeMimeData(
const QString &text, ResourceType *t, QString *file)
747 static auto docElementName = elementResourceData;
748 static const QString docElementString = u'<' + docElementName;
750 if (text.isEmpty() || text.indexOf(docElementString) == -1)
754 if (!doc.setContent(text))
757 const QDomElement domElement = doc.documentElement();
758 if (domElement.tagName() != docElementName)
762 const QString typeAttr = typeAttribute;
763 if (domElement.hasAttribute (typeAttr)) {
764 const QString typeValue = domElement.attribute(typeAttr, typeOther);
765 if (typeValue == typeImage) {
768 *t = typeValue == typeStyleSheet ? ResourceStyleSheet : ResourceOther;
773 const QString fileAttr = fileAttribute;
774 if (domElement.hasAttribute(fileAttr)) {
775 *file = domElement.attribute(fileAttr, QString());
810QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent) :
812 d_ptr(
new QtResourceViewDialogPrivate(core))
814 setWindowTitle(tr(
"Select Resource"));
816 QVBoxLayout *layout =
new QVBoxLayout(
this);
817 layout->addWidget(d_ptr->m_view);
818 layout->addWidget(d_ptr->m_box);
819 connect(d_ptr->m_box, &QDialogButtonBox::accepted,
this, &QDialog::accept);
820 connect(d_ptr->m_box, &QDialogButtonBox::rejected,
this, &QDialog::reject);
821 connect(d_ptr->m_view, &QtResourceView::resourceActivated,
this, &QDialog::accept);
822 connect(d_ptr->m_view, &QtResourceView::resourceSelected,
823 this, [
this](
const QString &resource) { d_ptr->slotResourceSelected(resource); });
824 d_ptr->setOkButtonEnabled(
false);
825 d_ptr->m_view->setResourceModel(core->resourceModel());
827 QDesignerSettingsInterface *settings = core->settingsManager();
828 settings->beginGroup(ResourceViewDialogC);
830 const QVariant geometry = settings->value(qrvGeometry);
831 if (geometry.metaType().id() == QMetaType::QByteArray)
832 restoreGeometry(geometry.toByteArray());
834 settings->endGroup();