summaryrefslogtreecommitdiffstats
path: root/ui/qt/profile_dialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ui/qt/profile_dialog.cpp')
-rw-r--r--ui/qt/profile_dialog.cpp736
1 files changed, 736 insertions, 0 deletions
diff --git a/ui/qt/profile_dialog.cpp b/ui/qt/profile_dialog.cpp
new file mode 100644
index 0000000..5b53a2c
--- /dev/null
+++ b/ui/qt/profile_dialog.cpp
@@ -0,0 +1,736 @@
+/* profile_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include "wsutil/filesystem.h"
+#include "wsutil/utf8_entities.h"
+#include "epan/prefs.h"
+
+#include <ui/qt/utils/qt_ui_utils.h>
+
+#include "ui/profile.h"
+#include "ui/recent.h"
+
+#include <ui/qt/utils/variant_pointer.h>
+#include <ui/qt/models/profile_model.h>
+
+#include "profile_dialog.h"
+#include <ui_profile_dialog.h>
+#include "main_application.h"
+#include <ui/qt/utils/color_utils.h>
+#include <ui/qt/simple_dialog.h>
+
+#include <QBrush>
+#include <QDir>
+#include <QFont>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QTreeWidgetItem>
+#include <QUrl>
+#include <QComboBox>
+#include <QLineEdit>
+#include <QFileDialog>
+#include <QStandardPaths>
+#include <QKeyEvent>
+#include <QMenu>
+#include <QMessageBox>
+
+#define PROFILE_EXPORT_PROPERTY "export"
+#define PROFILE_EXPORT_ALL "all"
+#define PROFILE_EXPORT_SELECTED "selected"
+
+ProfileDialog::ProfileDialog(QWidget *parent) :
+ GeometryStateDialog(parent),
+ pd_ui_(new Ui::ProfileDialog),
+ ok_button_(Q_NULLPTR),
+ import_button_(Q_NULLPTR),
+ model_(Q_NULLPTR),
+ sort_model_(Q_NULLPTR)
+{
+ pd_ui_->setupUi(this);
+ loadGeometry();
+ setWindowTitle(mainApp->windowTitleString(tr("Configuration Profiles")));
+
+ ok_button_ = pd_ui_->buttonBox->button(QDialogButtonBox::Ok);
+
+ // XXX - Use NSImageNameAddTemplate and NSImageNameRemoveTemplate to set stock
+ // icons on macOS.
+ // Are there equivalent stock icons on Windows?
+ pd_ui_->newToolButton->setStockIcon("list-add");
+ pd_ui_->deleteToolButton->setStockIcon("list-remove");
+ pd_ui_->copyToolButton->setStockIcon("list-copy");
+#ifdef Q_OS_MAC
+ pd_ui_->newToolButton->setAttribute(Qt::WA_MacSmallSize, true);
+ pd_ui_->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true);
+ pd_ui_->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true);
+ pd_ui_->hintLabel->setAttribute(Qt::WA_MacSmallSize, true);
+#endif
+
+ import_button_ = pd_ui_->buttonBox->addButton(tr("Import", "noun"), QDialogButtonBox::ActionRole);
+
+#ifdef HAVE_MINIZIP
+ export_button_ = pd_ui_->buttonBox->addButton(tr("Export", "noun"), QDialogButtonBox::ActionRole);
+
+ QMenu * importMenu = new QMenu(import_button_);
+ QAction * entry = importMenu->addAction(tr("From Zip File..."));
+ connect(entry, &QAction::triggered, this, &ProfileDialog::importFromZip, Qt::QueuedConnection);
+ entry = importMenu->addAction(tr("From Directory..."));
+ connect(entry, &QAction::triggered, this, &ProfileDialog::importFromDirectory, Qt::QueuedConnection);
+ import_button_->setMenu(importMenu);
+
+ QMenu * exportMenu = new QMenu(export_button_);
+ export_selected_entry_ = exportMenu->addAction(tr("%Ln Selected Personal Profile(s)...", "", 0));
+ export_selected_entry_->setProperty(PROFILE_EXPORT_PROPERTY, PROFILE_EXPORT_SELECTED);
+ connect(export_selected_entry_, &QAction::triggered, this, &ProfileDialog::exportProfiles, Qt::QueuedConnection);
+ entry = exportMenu->addAction(tr("All Personal Profiles..."));
+ entry->setProperty(PROFILE_EXPORT_PROPERTY, PROFILE_EXPORT_ALL);
+ connect(entry, &QAction::triggered, this, &ProfileDialog::exportProfiles, Qt::QueuedConnection);
+ export_button_->setMenu(exportMenu);
+#else
+ connect(import_button_, &QPushButton::clicked, this, &ProfileDialog::importFromDirectory);
+#endif
+
+ resetTreeView();
+
+ /* Select the row for the currently selected profile or the first row if non is selected*/
+ selectProfile();
+
+ pd_ui_->cmbProfileTypes->addItems(ProfileSortModel::filterTypes());
+
+ connect (pd_ui_->cmbProfileTypes, &QComboBox::currentTextChanged,
+ this, &ProfileDialog::filterChanged);
+ connect (pd_ui_->lineProfileFilter, &QLineEdit::textChanged,
+ this, &ProfileDialog::filterChanged);
+
+ currentItemChanged();
+
+ pd_ui_->profileTreeView->setFocus();
+}
+
+ProfileDialog::~ProfileDialog()
+{
+ delete pd_ui_;
+ empty_profile_list (TRUE);
+}
+
+void ProfileDialog::keyPressEvent(QKeyEvent *evt)
+{
+ if (pd_ui_->lineProfileFilter->hasFocus() && (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return))
+ return;
+ QDialog::keyPressEvent(evt);
+}
+
+void ProfileDialog::selectProfile(QString profile)
+{
+ if (profile.isEmpty())
+ profile = QString(get_profile_name());
+
+ int row = model_->findByName(profile);
+ QModelIndex idx = sort_model_->mapFromSource(model_->index(row, ProfileModel::COL_NAME));
+ if (idx.isValid())
+ pd_ui_->profileTreeView->selectRow(idx.row());
+}
+
+int ProfileDialog::execAction(ProfileDialog::ProfileAction profile_action)
+{
+ int ret = QDialog::Accepted;
+ QModelIndex item;
+
+ switch (profile_action) {
+ case ShowProfiles:
+ ret = exec();
+ break;
+ case NewProfile:
+ on_newToolButton_clicked();
+ ret = exec();
+ break;
+ case ImportZipProfile:
+#ifdef HAVE_MINIZIP
+ importFromZip();
+#endif
+ break;
+ case ImportDirProfile:
+ importFromDirectory();
+ break;
+ case ExportSingleProfile:
+#ifdef HAVE_MINIZIP
+ exportProfiles();
+#endif
+ break;
+ case ExportAllProfiles:
+#ifdef HAVE_MINIZIP
+ exportProfiles(true);
+#endif
+ break;
+ case EditCurrentProfile:
+ item = pd_ui_->profileTreeView->currentIndex();
+ if (item.isValid()) {
+ pd_ui_->profileTreeView->edit(item);
+ }
+ ret = exec();
+ break;
+ case DeleteCurrentProfile:
+ if (delete_current_profile()) {
+ mainApp->setConfigurationProfile (Q_NULLPTR);
+ }
+ break;
+ }
+ return ret;
+}
+
+QModelIndexList ProfileDialog::selectedProfiles()
+{
+ QModelIndexList profiles;
+
+ foreach (QModelIndex idx, pd_ui_->profileTreeView->selectionModel()->selectedIndexes())
+ {
+ QModelIndex temp = sort_model_->mapToSource(idx);
+ if (! temp.isValid() || profiles.contains(temp) || temp.column() != ProfileModel::COL_NAME)
+ continue;
+
+ profiles << temp;
+ }
+
+ return profiles;
+}
+
+void ProfileDialog::selectionChanged()
+{
+ if (selectedProfiles().count() == 0)
+ pd_ui_->profileTreeView->selectRow(0);
+
+ updateWidgets();
+}
+
+void ProfileDialog::updateWidgets()
+{
+ bool enable_del = true;
+ bool enable_ok = true;
+ bool multiple = false;
+ bool enable_import = true;
+ int user_profiles = 0;
+
+ QString msg;
+ QModelIndex index = sort_model_->mapToSource(pd_ui_->profileTreeView->currentIndex());
+ QModelIndexList profiles = selectedProfiles();
+
+ /* Ensure that the index is always the name column */
+ if (index.column() != ProfileModel::COL_NAME)
+ index = index.sibling(index.row(), ProfileModel::COL_NAME);
+
+ /* check if more than one viable profile is selected, and inform the sorting model */
+ if (profiles.count() > 1)
+ multiple = true;
+
+ /* Check if user profiles have been selected and allow export if it is so */
+ for (int cnt = 0; cnt < profiles.count(); cnt++)
+ {
+ if (! profiles[cnt].data(ProfileModel::DATA_IS_GLOBAL).toBool() && ! profiles[cnt].data(ProfileModel::DATA_IS_DEFAULT).toBool())
+ user_profiles++;
+ }
+ if (model_->changesPending())
+ {
+ enable_import = false;
+ msg = tr("An import of profiles is not allowed, while changes are pending");
+ }
+ else if (model_->importPending())
+ {
+ enable_import = false;
+ msg = tr("An import is pending to be saved. Additional imports are not allowed");
+ }
+ import_button_->setToolTip(msg);
+ import_button_->setEnabled(enable_import);
+
+#ifdef HAVE_MINIZIP
+ bool contains_user = false;
+ bool enable_export = false;
+
+ if (user_profiles > 0)
+ contains_user = true;
+
+ /* enable export if no changes are pending */
+ if (! model_->changesPending())
+ enable_export = true;
+
+ export_button_->setEnabled(enable_export);
+ if (! enable_export)
+ {
+ if (! contains_user)
+ export_button_->setToolTip(tr("An export of profiles is only allowed for personal profiles"));
+ else
+ export_button_->setToolTip(tr("An export of profiles is not allowed, while changes are pending"));
+ }
+ export_selected_entry_->setVisible(contains_user);
+#endif
+
+ /* if the current profile is default with reset pending or a global one, deactivate delete */
+ if (! multiple)
+ {
+ if (index.isValid())
+ {
+ if (index.data(ProfileModel::DATA_IS_GLOBAL).toBool())
+ enable_del = false;
+ else if (index.data(ProfileModel::DATA_IS_DEFAULT).toBool() && model_->resetDefault())
+ enable_del = false;
+ }
+ else if (! index.isValid())
+ enable_del = false;
+ }
+
+ QString hintUrl;
+ msg.clear();
+ if (multiple)
+ {
+ /* multiple profiles are being selected, copy is no longer allowed */
+ pd_ui_->copyToolButton->setEnabled(false);
+
+ msg = tr("%Ln Selected Personal Profile(s)...", "", user_profiles);
+ pd_ui_->hintLabel->setText(msg);
+#ifdef HAVE_MINIZIP
+ export_selected_entry_->setText(msg);
+#endif
+ }
+ else
+ {
+ /* if only one profile is selected, display it's path in the hint label and activate link (if allowed) */
+ if (index.isValid())
+ {
+ QString temp = index.data(ProfileModel::DATA_PATH).toString();
+ if (index.data(ProfileModel::DATA_PATH_IS_NOT_DESCRIPTION).toBool() && QFileInfo(temp).isDir())
+ hintUrl = QUrl::fromLocalFile(temp).toString();
+ pd_ui_->hintLabel->setText(temp);
+ pd_ui_->hintLabel->setToolTip(index.data(Qt::ToolTipRole).toString());
+
+ if (! index.data(ProfileModel::DATA_IS_GLOBAL).toBool() && ! index.data(ProfileModel::DATA_IS_DEFAULT).toBool())
+ msg = tr("%Ln Selected Personal Profile(s)...", "", 1);
+ }
+
+ pd_ui_->copyToolButton->setEnabled(true);
+#ifdef HAVE_MINIZIP
+ export_selected_entry_->setText(msg);
+#endif
+ }
+
+ /* Ensure, that the ok button is disabled, if an invalid name is used or if duplicate global profiles exist */
+ if (model_ && model_->rowCount() > 0)
+ {
+ msg.clear();
+ for (int row = 0; row < model_->rowCount() && enable_ok; row++)
+ {
+ QModelIndex idx = model_->index(row, ProfileModel::COL_NAME);
+ QString name = idx.data().toString();
+
+ if (! ProfileModel::checkNameValidity(name, &msg))
+ {
+ if (idx == index || selectedProfiles().contains(idx))
+ {
+ hintUrl.clear();
+ pd_ui_->hintLabel->setText(msg);
+ }
+
+ enable_ok = false;
+ continue;
+ }
+
+ if (model_->checkInvalid(idx) || (! idx.data(ProfileModel::DATA_IS_GLOBAL).toBool() && model_->checkIfDeleted(idx)) )
+ {
+ if (idx == index)
+ hintUrl.clear();
+ enable_ok = false;
+ continue;
+ }
+
+ if (idx != index && idx.data().toString().compare(index.data().toString()) == 0)
+ {
+ if (idx.data(ProfileModel::DATA_IS_GLOBAL).toBool() == index.data(ProfileModel::DATA_IS_GLOBAL).toBool())
+ enable_ok = false;
+ }
+
+ QList<int> rows = model_->findAllByNameAndVisibility(name, idx.data(ProfileModel::DATA_IS_GLOBAL).toBool());
+ if (rows.count() > 1)
+ enable_ok = false;
+ }
+
+ if (enable_ok && ! model_->checkIfDeleted(index) && index.data(ProfileModel::DATA_STATUS).toInt() == PROF_STAT_CHANGED)
+ hintUrl.clear();
+ }
+
+ pd_ui_->hintLabel->setUrl(hintUrl);
+
+ /* ensure the name column is resized to it's content */
+ pd_ui_->profileTreeView->resizeColumnToContents(ProfileModel::COL_NAME);
+
+ pd_ui_->deleteToolButton->setEnabled(enable_del);
+ ok_button_->setEnabled(enable_ok);
+}
+
+void ProfileDialog::currentItemChanged(const QModelIndex &, const QModelIndex &)
+{
+ updateWidgets();
+}
+
+void ProfileDialog::on_newToolButton_clicked()
+{
+ pd_ui_->lineProfileFilter->setText("");
+ pd_ui_->cmbProfileTypes->setCurrentIndex(ProfileSortModel::AllProfiles);
+ sort_model_->setFilterString();
+
+ QModelIndex ridx = sort_model_->mapFromSource(model_->addNewProfile(tr("New profile")));
+ if (ridx.isValid())
+ {
+ pd_ui_->profileTreeView->setCurrentIndex(ridx);
+ pd_ui_->profileTreeView->scrollTo(ridx);
+ pd_ui_->profileTreeView->edit(ridx);
+ currentItemChanged();
+ }
+ else
+ updateWidgets();
+}
+
+void ProfileDialog::on_deleteToolButton_clicked()
+{
+ QModelIndexList profiles = selectedProfiles();
+ if (profiles.count() <= 0)
+ return;
+
+ model_->deleteEntries(profiles);
+
+ bool isGlobal = model_->activeProfile().data(ProfileModel::DATA_IS_GLOBAL).toBool();
+ int row = model_->findByName(model_->activeProfile().data().toString());
+ /* If the active profile is deleted, the default is selected next */
+ if (row < 0)
+ row = 0;
+ QModelIndex newIdx = sort_model_->mapFromSource(model_->index(row, 0));
+ if (newIdx.data(ProfileModel::DATA_IS_GLOBAL).toBool() != isGlobal)
+ newIdx = sort_model_->mapFromSource(model_->index(0, 0));
+
+ pd_ui_->profileTreeView->setCurrentIndex(newIdx);
+
+ updateWidgets();
+}
+
+void ProfileDialog::on_copyToolButton_clicked()
+{
+ QModelIndexList profiles = selectedProfiles();
+ if (profiles.count() > 1)
+ return;
+
+ pd_ui_->lineProfileFilter->setText("");
+ pd_ui_->cmbProfileTypes->setCurrentIndex(ProfileSortModel::AllProfiles);
+ sort_model_->setFilterString();
+
+ QModelIndex current = pd_ui_->profileTreeView->currentIndex();
+ if (current.column() != ProfileModel::COL_NAME)
+ current = current.sibling(current.row(), ProfileModel::COL_NAME);
+
+ QModelIndex source = sort_model_->mapToSource(current);
+ QModelIndex ridx = model_->duplicateEntry(source);
+ if (ridx.isValid())
+ {
+ pd_ui_->profileTreeView->setCurrentIndex(sort_model_->mapFromSource(ridx));
+ pd_ui_->profileTreeView->scrollTo(sort_model_->mapFromSource(ridx));
+ pd_ui_->profileTreeView->edit(sort_model_->mapFromSource(ridx));
+ currentItemChanged();
+ }
+ else
+ updateWidgets();
+}
+
+void ProfileDialog::on_buttonBox_accepted()
+{
+ bool write_recent = true;
+ bool item_data_removed = false;
+
+ QModelIndex index = sort_model_->mapToSource(pd_ui_->profileTreeView->currentIndex());
+
+ pd_ui_->buttonBox->setFocus();
+
+ QModelIndexList profiles = selectedProfiles();
+ if (profiles.count() <= 0)
+ index = QModelIndex();
+
+ QModelIndex default_item = sort_model_->mapFromSource(model_->index(0, ProfileModel::COL_NAME));
+ if (index.isValid() && index.column() != ProfileModel::COL_NAME)
+ index = index.sibling(index.row(), ProfileModel::COL_NAME);
+
+ if (default_item.data(ProfileModel::DATA_STATUS).toInt() == PROF_STAT_DEFAULT && model_->resetDefault())
+ {
+ // Reset Default profile.
+ GList *fl_entry = model_->at(0);
+ remove_from_profile_list(fl_entry);
+
+ // Don't write recent file if leaving the Default profile after this has been reset.
+ write_recent = !is_default_profile();
+
+ // Don't fetch profile data if removed.
+ item_data_removed = (index.row() == 0);
+ }
+
+ if (write_recent) {
+ /* Get the current geometry, before writing it to disk */
+ mainApp->emitAppSignal(MainApplication::ProfileChanging);
+
+ /* Write recent file for current profile now because
+ * the profile may be renamed in apply_profile_changes() */
+ write_profile_recent();
+ }
+
+ gchar * err_msg = Q_NULLPTR;
+ if ((err_msg = apply_profile_changes()) != Q_NULLPTR) {
+ QMessageBox::critical(this, tr("Profile Error"),
+ err_msg,
+ QMessageBox::Ok);
+ g_free(err_msg);
+
+ model_->doResetModel();
+ return;
+ }
+
+ model_->doResetModel();
+
+ QString profileName;
+
+ if (! index.isValid() && model_->lastSetRow() >= 0)
+ {
+ QModelIndex original = model_->index(model_->lastSetRow(), ProfileModel::COL_NAME);
+ index = sort_model_->mapFromSource(original);
+ }
+
+ /* If multiple profiles are selected, do not change the selected profile */
+ if (index.isValid() && ! item_data_removed && profiles.count() <= 1)
+ {
+ profileName = model_->data(index).toString();
+ }
+
+ if (profileName.length() > 0 && model_->findByName(profileName) >= 0) {
+ // The new profile exists, change.
+ mainApp->setConfigurationProfile (profileName.toUtf8().constData(), FALSE);
+ } else if (!model_->activeProfile().isValid()) {
+ // The new profile does not exist, and the previous profile has
+ // been deleted. Change to the default profile.
+ mainApp->setConfigurationProfile (Q_NULLPTR, FALSE);
+ }
+}
+
+void ProfileDialog::on_buttonBox_rejected()
+{
+ QString msg;
+ if (! model_->clearImported(&msg))
+ QMessageBox::critical(this, tr("Error"), msg);
+}
+
+void ProfileDialog::on_buttonBox_helpRequested()
+{
+ mainApp->helpTopicAction(HELP_CONFIG_PROFILES_DIALOG);
+}
+
+void ProfileDialog::dataChanged(const QModelIndex &)
+{
+ pd_ui_->lineProfileFilter->setText("");
+ pd_ui_->cmbProfileTypes->setCurrentIndex(ProfileSortModel::AllProfiles);
+
+ pd_ui_->profileTreeView->setFocus();
+ if (model_->lastSetRow() >= 0)
+ {
+ QModelIndex original = model_->index(model_->lastSetRow(), ProfileModel::COL_NAME);
+ pd_ui_->profileTreeView->setCurrentIndex(sort_model_->mapFromSource(original));
+ pd_ui_->profileTreeView->selectRow(sort_model_->mapFromSource(original).row());
+ }
+
+ updateWidgets();
+}
+
+void ProfileDialog::filterChanged(const QString &text)
+{
+ if (qobject_cast<QComboBox *>(sender()))
+ {
+ QComboBox * cmb = qobject_cast<QComboBox *>(sender());
+ sort_model_->setFilterType(static_cast<ProfileSortModel::FilterType>(cmb->currentIndex()));
+ }
+ else if (qobject_cast<QLineEdit *>(sender()))
+ sort_model_->setFilterString(text);
+
+ pd_ui_->profileTreeView->resizeColumnToContents(ProfileModel::COL_NAME);
+
+ QModelIndex active = sort_model_->mapFromSource(model_->activeProfile());
+ if (active.isValid())
+ pd_ui_->profileTreeView->setCurrentIndex(active);
+}
+
+#ifdef HAVE_MINIZIP
+void ProfileDialog::exportProfiles(bool exportAllPersonalProfiles)
+{
+ QAction * action = qobject_cast<QAction *>(sender());
+ if (action && action->property(PROFILE_EXPORT_PROPERTY).isValid())
+ exportAllPersonalProfiles = action->property(PROFILE_EXPORT_PROPERTY).toString().compare(PROFILE_EXPORT_ALL) == 0;
+
+ QModelIndexList items;
+ int skipped = 0;
+
+ if (! exportAllPersonalProfiles)
+ {
+ foreach (QModelIndex idx, selectedProfiles())
+ {
+ QModelIndex baseIdx = sort_model_->index(idx.row(), ProfileModel::COL_NAME);
+ if (! baseIdx.data(ProfileModel::DATA_IS_GLOBAL).toBool() && ! baseIdx.data(ProfileModel::DATA_IS_DEFAULT).toBool())
+ items << sort_model_->mapToSource(baseIdx);
+ else
+ skipped++;
+ }
+ }
+ else if (exportAllPersonalProfiles)
+ {
+ for (int cnt = 0; cnt < sort_model_->rowCount(); cnt++)
+ {
+ QModelIndex idx = sort_model_->index(cnt, ProfileModel::COL_NAME);
+ if (! idx.data(ProfileModel::DATA_IS_GLOBAL).toBool() && ! idx.data(ProfileModel::DATA_IS_DEFAULT).toBool())
+ items << sort_model_->mapToSource(idx);
+ }
+ }
+ if (items.count() == 0)
+ {
+ QString msg = tr("No profiles found for export");
+ if (skipped > 0)
+ msg.append(tr(", %Ln profile(s) skipped", "", skipped));
+ QMessageBox::critical(this, tr("Exporting profiles"), msg);
+ return;
+ }
+
+ QString zipFile = QFileDialog::getSaveFileName(this, tr("Select zip file for export"), openDialogInitialDir(), tr("Zip File (*.zip)"));
+
+ if (zipFile.length() > 0)
+ {
+ QFileInfo fi(zipFile);
+ if (fi.suffix().length() == 0 || fi.suffix().toLower().compare("zip") != 0)
+ zipFile += ".zip";
+
+ QString err;
+ if (model_->exportProfiles(zipFile, items, &err))
+ {
+ QString msg = tr("%Ln profile(s) exported", "", static_cast<int>(items.count()));
+ if (skipped > 0)
+ msg.append(tr(", %Ln profile(s) skipped", "", skipped));
+ QMessageBox::information(this, tr("Exporting profiles"), msg);
+
+ QFileInfo zip(zipFile);
+ storeLastDir(zip.absolutePath());
+ }
+ else
+ {
+ QString msg = tr("An error has occurred while exporting profiles");
+ if (err.length() > 0)
+ msg.append(QString("\n\n%1: %3").arg(tr("Error")).arg(err));
+ QMessageBox::critical(this, tr("Exporting profiles"), msg);
+ }
+ }
+}
+
+void ProfileDialog::importFromZip()
+{
+ QString zipFile = QFileDialog::getOpenFileName(this, tr("Select zip file for import"), openDialogInitialDir(), tr("Zip File (*.zip)"));
+
+ QFileInfo fi(zipFile);
+ if (! fi.exists())
+ return;
+
+ int skipped = 0;
+ QStringList import;
+ int count = model_->importProfilesFromZip(zipFile, &skipped, &import);
+
+ finishImport(fi, count, skipped, import);
+}
+#endif
+
+void ProfileDialog::importFromDirectory()
+{
+ QString importDir = QFileDialog::getExistingDirectory(this, tr("Select directory for import"), openDialogInitialDir());
+
+ QFileInfo fi(importDir);
+ if (! fi.isDir())
+ return;
+
+ int skipped = 0;
+ QStringList import;
+ int count = model_->importProfilesFromDir(importDir, &skipped, false, &import);
+
+ finishImport(fi, count, skipped, import);
+}
+
+void ProfileDialog::finishImport(QFileInfo fi, int count, int skipped, QStringList import)
+{
+ QString msg;
+ QMessageBox::Icon icon;
+
+ if (count == 0 && skipped == 0)
+ {
+ icon = QMessageBox::Warning;
+ msg = tr("No profiles found for import in %1").arg(fi.fileName());
+ }
+ else
+ {
+ icon = QMessageBox::Information;
+ msg = tr("%Ln profile(s) imported", "", count);
+ if (skipped > 0)
+ msg.append(tr(", %Ln profile(s) skipped", "", skipped));
+ }
+ QMessageBox msgBox(icon, tr("Importing profiles"), msg, QMessageBox::Ok, this);
+ msgBox.exec();
+
+ storeLastDir(fi.absolutePath());
+
+ if (count > 0)
+ {
+ import.sort();
+ resetTreeView();
+ model_->markAsImported(import);
+ int rowFirstImported = model_->findByName(import.at(0));
+ QModelIndex idx = sort_model_->mapFromSource(model_->index(rowFirstImported, ProfileModel::COL_NAME));
+ pd_ui_->profileTreeView->selectRow(idx.isValid() ? idx.row() : 0);
+ }
+
+ updateWidgets();
+}
+
+void ProfileDialog::resetTreeView()
+{
+ if (model_)
+ {
+ pd_ui_->profileTreeView->setModel(Q_NULLPTR);
+ sort_model_->setSourceModel(Q_NULLPTR);
+ model_->disconnect();
+ if (pd_ui_->profileTreeView->selectionModel())
+ pd_ui_->profileTreeView->selectionModel()->disconnect();
+ delete sort_model_;
+ delete model_;
+ }
+
+ model_ = new ProfileModel(pd_ui_->profileTreeView);
+ sort_model_ = new ProfileSortModel(pd_ui_->profileTreeView);
+ sort_model_->setSourceModel(model_);
+ pd_ui_->profileTreeView->setModel(sort_model_);
+
+ connect(model_, &ProfileModel::itemChanged, this, &ProfileDialog::dataChanged, Qt::QueuedConnection);
+ QItemSelectionModel *selModel = pd_ui_->profileTreeView->selectionModel();
+ connect(selModel, &QItemSelectionModel::currentChanged,
+ this, &ProfileDialog::currentItemChanged, Qt::QueuedConnection);
+ connect(selModel, &QItemSelectionModel::selectionChanged,
+ this, &ProfileDialog::selectionChanged);
+
+ selectionChanged();
+
+ if (sort_model_->columnCount() <= 1)
+ pd_ui_->profileTreeView->header()->hide();
+ else
+ {
+ pd_ui_->profileTreeView->header()->setStretchLastSection(false);
+ pd_ui_->profileTreeView->header()->setSectionResizeMode(ProfileModel::COL_NAME, QHeaderView::Stretch);
+ }
+}