diff --git a/src/plugins/qmldesigner/components/componentcore/addimagesdialog.cpp b/src/plugins/qmldesigner/components/componentcore/addimagesdialog.cpp new file mode 100644 index 00000000000..4c81e4e455f --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/addimagesdialog.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "addimagesdialog.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static QTableWidget* createFilesTable(const QStringList &fileNames) +{ + QTableWidget *table = new QTableWidget(0, 2); + table->setSelectionMode(QAbstractItemView::NoSelection); + + QStringList labels({ + QCoreApplication::translate("AddImageToResources","Filename"), + QCoreApplication::translate("AddImageToResources","Size") + }); + table->setHorizontalHeaderLabels(labels); + table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + table->verticalHeader()->hide(); + table->setShowGrid(false); + + for (const QString &filePath : fileNames) { + const QString toolTip = QDir::toNativeSeparators(filePath); + const QString fileName = QFileInfo(filePath).fileName(); + const qint64 size = QFileInfo(filePath).size(); + QTableWidgetItem *fileNameItem = new QTableWidgetItem(fileName); + fileNameItem->setToolTip(toolTip); + fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable); + QTableWidgetItem *sizeItem = new QTableWidgetItem(QLocale().formattedDataSize(size)); + sizeItem->setToolTip(toolTip); + sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); + sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable); + + int row = table->rowCount(); + table->insertRow(row); + table->setItem(row, 0, fileNameItem); + table->setItem(row, 1, sizeItem); + } + + return table; +} + +QComboBox *createDirectoryComboBox(const QString &defaultDirectory) +{ + QComboBox *comboBox = new QComboBox; + comboBox->addItem(defaultDirectory); + comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + for (const QString &dir : QDir(defaultDirectory).entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) + comboBox->addItem(defaultDirectory + "/" +dir); + + return comboBox; +} + +namespace QmlDesigner { + +QString AddImagesDialog::getDirectory(const QStringList &fileNames, const QString &defaultDirectory) +{ + QDialog *dialog = new QDialog(Core::ICore::dialogParent()); + dialog->setMinimumWidth(480); + + QString result; + QString directory = defaultDirectory; + + dialog->setModal(true); + dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint); + dialog->setWindowTitle(QCoreApplication::translate("AddImageToResources","Add Resources")); + QTableWidget *table = createFilesTable(fileNames); + table->setParent(dialog); + QGridLayout *mainLayout = new QGridLayout(dialog); + mainLayout->addWidget(table, 0, 0, 1, 4); + + QComboBox *directoryComboBox = createDirectoryComboBox(defaultDirectory); + + auto setDirectoryForComboBox = [directoryComboBox, &directory](const QString &newDir) { + if (directoryComboBox->findText(newDir) < 0) + directoryComboBox->addItem(newDir); + + directoryComboBox->setCurrentText(newDir); + directory = newDir; + }; + + QObject::connect(directoryComboBox, &QComboBox::currentTextChanged, dialog, [&directory](const QString &text){ + directory = text; + }); + + QPushButton *browseButton = new QPushButton(QCoreApplication::translate("AddImageToResources", "&Browse..."), dialog); + + QObject::connect(browseButton, &QPushButton::clicked, dialog, [setDirectoryForComboBox, &directory]() { + const QString newDir = QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + QCoreApplication::translate("AddImageToResources", "Target Directory"), + directory); + if (!newDir.isEmpty()) + setDirectoryForComboBox(newDir); + }); + + mainLayout->addWidget(new QLabel(QCoreApplication::translate("AddImageToResources", "In directory:")), 1, 0); + mainLayout->addWidget(directoryComboBox, 1, 0, 1, 3); + mainLayout->addWidget(browseButton, 1, 3, 1 , 1); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + + mainLayout->addWidget(buttonBox, 3, 2, 1, 2); + + QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, [dialog](){ + dialog->accept(); + dialog->deleteLater(); + }); + + QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, [dialog, &directory](){ + dialog->reject(); + dialog->deleteLater(); + directory = QString(); + }); + + QObject::connect(dialog, &QDialog::accepted, [&directory, &result](){ + result = directory; + }); + + dialog->exec(); + + return result; +} + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/addimagesdialog.h b/src/plugins/qmldesigner/components/componentcore/addimagesdialog.h new file mode 100644 index 00000000000..a01886a3c38 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/addimagesdialog.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace QmlDesigner { + +class AddImagesDialog +{ +public: + static QString getDirectory(const QStringList &fileNames, const QString &defaultDirectory); +}; + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore.pri b/src/plugins/qmldesigner/components/componentcore/componentcore.pri index f2482dc289d..45f781e7926 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore.pri +++ b/src/plugins/qmldesigner/components/componentcore/componentcore.pri @@ -1,6 +1,7 @@ VPATH += $$PWD SOURCES += modelnodecontextmenu.cpp +SOURCES += addimagesdialog.cpp SOURCES += changestyleaction.cpp SOURCES += theme.cpp SOURCES += findimplementation.cpp @@ -17,6 +18,7 @@ SOURCES += crumblebar.cpp SOURCES += qmldesignericonprovider.cpp HEADERS += modelnodecontextmenu.h +HEADERS += addimagesdialog.h HEADERS += changestyleaction.h HEADERS += theme.h HEADERS += findimplementation.h diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 45c3abc08cd..03660ca6b8e 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -42,7 +42,7 @@ namespace QmlDesigner { class DesignerActionManagerView; -typedef std::function AddResourceOperation; +typedef std::function AddResourceOperation; struct AddResourceHandler { diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 41429bbb160..bc43ca65155 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -25,9 +25,11 @@ #include "modelnodeoperations.h" #include "modelnodecontextmenu_helper.h" +#include "addimagesdialog.h" #include "layoutingridlayout.h" #include "findimplementation.h" + #include "addsignalhandlerdialog.h" #include @@ -1008,25 +1010,35 @@ void addTabBarToStackedContainer(const SelectionContext &selectionContext) } } -bool addImageToProject(const QString &fileName, const QString &directory) +bool addImageToProject(const QStringList &fileNames, const QString &defaultDirectory) { - const QString targetFile = directory + "/" + QFileInfo(fileName).fileName(); - const bool success = QFile::copy(fileName, targetFile); + QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); - auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); + if (directory.isEmpty()) + return true; - QTC_ASSERT(document, return false); + bool allSuccessful = true; + for (const QString &fileName : fileNames) { + const QString targetFile = directory + "/" + QFileInfo(fileName).fileName(); + const bool success = QFile::copy(fileName, targetFile); - if (success) { - ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName()); - if (node) { - ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode(); - if (containingFolder) - containingFolder->addFiles(QStringList(targetFile)); + auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); + + QTC_ASSERT(document, return false); + + if (success) { + ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(document->fileName()); + if (node) { + ProjectExplorer::FolderNode *containingFolder = node->parentFolderNode(); + if (containingFolder) + containingFolder->addFiles(QStringList(targetFile)); + } + } else { + allSuccessful = false; } } - return success; + return allSuccessful; } } // namespace Mode diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 0aec320316e..e3396a303e9 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -72,7 +72,7 @@ void addItemToStackedContainer(const SelectionContext &selectionContext); void increaseIndexOfStackedContainer(const SelectionContext &selectionContext); void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext); void addTabBarToStackedContainer(const SelectionContext &selectionContext); -bool addImageToProject(const QString &fileName, const QString &directory); +bool addImageToProject(const QStringList &fileNames, const QString &directory); } // namespace ModelNodeOperationso } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 59ae7fd2f31..54145541869 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -402,6 +402,11 @@ void ItemLibraryWidget::addResources() map.insert(handler.category, handler.filter); } + QMap reverseMap; + for (const AddResourceHandler &handler : handlers) { + reverseMap.insert(handler.filter, handler.category); + } + QMap priorities; for (const AddResourceHandler &handler : handlers) { priorities.insert(handler.category, handler.piority); @@ -422,25 +427,30 @@ void ItemLibraryWidget::addResources() filters.append(str); } + filters.prepend(tr("All Files (%1)").arg(map.values().join(" "))); + const auto fileNames = QFileDialog::getOpenFileNames(this, tr("Add Resources"), document->fileName().parentDir().toString(), filters.join(";;")); - if (!fileNames.isEmpty()) { - const auto directory = QFileDialog::getExistingDirectory(this, - tr("Target Directory"), - document->fileName().parentDir().toString()); + QMultiMap partitionedFileNames; - for (const QString &fileName : fileNames) { - for (const AddResourceHandler &handler : handlers) { - QString postfix = handler.filter; - postfix.remove(0, 1); - if (fileName.endsWith(postfix)) - if (!handler.operation(fileName, directory)) - Core::AsynchronousMessageBox::warning(tr("Failed to Add File"), tr("Could not add %1 to project.").arg(fileName)); - } - } + for (const QString &fileName : fileNames) { + const QString suffix = "*." + QFileInfo(fileName).completeSuffix(); + const QString category = reverseMap.value(suffix); + partitionedFileNames.insert(category, fileName); + } + + for (const QString &category : partitionedFileNames.uniqueKeys()) { + for (const AddResourceHandler &handler : handlers) { + QStringList fileNames = partitionedFileNames.values(category); + if (handler.category == category) { + if (!handler.operation(fileNames, document->fileName().parentDir().toString())) + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(" "))); + break; + } + } } } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 3a3b75fe2c2..5111271bfc9 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -371,6 +371,8 @@ Project { Group { prefix: "components/" files: [ + "componentcore/addimagesdialog.cpp", + "componentcore/addimagesdialog.h", "componentcore/abstractaction.cpp", "componentcore/abstractaction.h", "componentcore/abstractactiongroup.cpp",