3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "wsutil/filesystem.h"
14 #include <ui/qt/utils/qt_ui_utils.h>
16 #include "ui/profile.h"
17 #include "ui/recent.h"
19 #include <ui/qt/utils/variant_pointer.h>
20 #include <ui/qt/models/profile_model.h>
22 #include "profile_dialog.h"
23 #include <ui_profile_dialog.h>
24 #include "main_application.h"
25 #include <ui/qt/utils/color_utils.h>
26 #include <ui/qt/simple_dialog.h>
27 #include <ui/qt/widgets/wireshark_file_dialog.h>
32 #include <QMessageBox>
33 #include <QPushButton>
34 #include <QTreeWidgetItem>
38 #include <QStandardPaths>
41 #include <QMessageBox>
43 #define PROFILE_EXPORT_PROPERTY "export"
44 #define PROFILE_EXPORT_ALL "all"
45 #define PROFILE_EXPORT_SELECTED "selected"
47 ProfileDialog::ProfileDialog(QWidget
*parent
) :
48 GeometryStateDialog(parent
),
49 pd_ui_(new Ui::ProfileDialog
),
50 ok_button_(Q_NULLPTR
),
51 import_button_(Q_NULLPTR
),
53 sort_model_(Q_NULLPTR
)
55 pd_ui_
->setupUi(this);
57 setWindowTitle(mainApp
->windowTitleString(tr("Configuration Profiles")));
59 ok_button_
= pd_ui_
->buttonBox
->button(QDialogButtonBox::Ok
);
61 // XXX - Use NSImageNameAddTemplate and NSImageNameRemoveTemplate to set stock
63 // Are there equivalent stock icons on Windows?
64 pd_ui_
->newToolButton
->setStockIcon("list-add");
65 pd_ui_
->deleteToolButton
->setStockIcon("list-remove");
66 pd_ui_
->copyToolButton
->setStockIcon("list-copy");
68 pd_ui_
->newToolButton
->setAttribute(Qt::WA_MacSmallSize
, true);
69 pd_ui_
->deleteToolButton
->setAttribute(Qt::WA_MacSmallSize
, true);
70 pd_ui_
->copyToolButton
->setAttribute(Qt::WA_MacSmallSize
, true);
71 pd_ui_
->hintLabel
->setAttribute(Qt::WA_MacSmallSize
, true);
74 QString as_tooltip
= pd_ui_
->autoSwitchLimitLabel
->toolTip();
75 pd_ui_
->autoSwitchSpinBox
->setToolTip(as_tooltip
);
76 if (!is_packet_configuration_namespace()) {
77 pd_ui_
->autoSwitchLimitLabel
->setText(tr("Auto switch event limit"));
79 pd_ui_
->autoSwitchSpinBox
->setValue(recent
.gui_profile_switch_check_count
);
81 import_button_
= pd_ui_
->buttonBox
->addButton(tr("Import", "noun"), QDialogButtonBox::ActionRole
);
83 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
84 export_button_
= pd_ui_
->buttonBox
->addButton(tr("Export", "noun"), QDialogButtonBox::ActionRole
);
86 QMenu
* importMenu
= new QMenu(import_button_
);
87 QAction
* entry
= importMenu
->addAction(tr("From Zip File..."));
88 connect(entry
, &QAction::triggered
, this, &ProfileDialog::importFromZip
, Qt::QueuedConnection
);
89 entry
= importMenu
->addAction(tr("From Directory..."));
90 connect(entry
, &QAction::triggered
, this, &ProfileDialog::importFromDirectory
, Qt::QueuedConnection
);
91 import_button_
->setMenu(importMenu
);
93 QMenu
* exportMenu
= new QMenu(export_button_
);
94 export_selected_entry_
= exportMenu
->addAction(tr("%Ln Selected Personal Profile(s)...", "", 0));
95 export_selected_entry_
->setProperty(PROFILE_EXPORT_PROPERTY
, PROFILE_EXPORT_SELECTED
);
96 connect(export_selected_entry_
, &QAction::triggered
, this, &ProfileDialog::exportProfiles
, Qt::QueuedConnection
);
97 entry
= exportMenu
->addAction(tr("All Personal Profiles..."));
98 entry
->setProperty(PROFILE_EXPORT_PROPERTY
, PROFILE_EXPORT_ALL
);
99 connect(entry
, &QAction::triggered
, this, &ProfileDialog::exportProfiles
, Qt::QueuedConnection
);
100 export_button_
->setMenu(exportMenu
);
102 connect(import_button_
, &QPushButton::clicked
, this, &ProfileDialog::importFromDirectory
);
107 /* Select the row for the currently selected profile or the first row if non is selected*/
110 pd_ui_
->cmbProfileTypes
->addItems(ProfileSortModel::filterTypes());
112 connect (pd_ui_
->cmbProfileTypes
, &QComboBox::currentTextChanged
,
113 this, &ProfileDialog::filterChanged
);
114 connect (pd_ui_
->lineProfileFilter
, &QLineEdit::textChanged
,
115 this, &ProfileDialog::filterChanged
);
117 currentItemChanged();
119 connect(pd_ui_
->newToolButton
, &StockIconToolButton::clicked
, this, &ProfileDialog::newToolButtonClicked
);
120 connect(pd_ui_
->deleteToolButton
, &StockIconToolButton::clicked
, this, &ProfileDialog::deleteToolButtonClicked
);
121 connect(pd_ui_
->copyToolButton
, &StockIconToolButton::clicked
, this, &ProfileDialog::copyToolButtonClicked
);
122 connect(pd_ui_
->buttonBox
, &QDialogButtonBox::accepted
, this, &ProfileDialog::buttonBoxAccepted
);
123 connect(pd_ui_
->buttonBox
, &QDialogButtonBox::rejected
, this, &ProfileDialog::buttonBoxRejected
);
124 connect(pd_ui_
->buttonBox
, &QDialogButtonBox::helpRequested
, this, &ProfileDialog::buttonBoxHelpRequested
);
126 pd_ui_
->profileTreeView
->resizeColumnToContents(ProfileModel::COL_NAME
);
127 pd_ui_
->profileTreeView
->resizeColumnToContents(ProfileModel::COL_TYPE
);
129 pd_ui_
->profileTreeView
->setFocus();
132 ProfileDialog::~ProfileDialog()
135 empty_profile_list (true);
138 void ProfileDialog::keyPressEvent(QKeyEvent
*evt
)
140 if (pd_ui_
->lineProfileFilter
->hasFocus() && (evt
->key() == Qt::Key_Enter
|| evt
->key() == Qt::Key_Return
))
142 QDialog::keyPressEvent(evt
);
145 void ProfileDialog::selectProfile(QString profile
)
147 if (profile
.isEmpty())
148 profile
= QString(get_profile_name());
150 int row
= model_
->findByName(profile
);
151 QModelIndex idx
= sort_model_
->mapFromSource(model_
->index(row
, ProfileModel::COL_NAME
));
153 pd_ui_
->profileTreeView
->selectRow(idx
.row());
156 int ProfileDialog::execAction(ProfileDialog::ProfileAction profile_action
)
158 int ret
= QDialog::Accepted
;
161 switch (profile_action
) {
166 newToolButtonClicked();
169 case ImportZipProfile
:
170 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
174 case ImportDirProfile
:
175 importFromDirectory();
177 case ExportSingleProfile
:
178 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
182 case ExportAllProfiles
:
183 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
184 exportProfiles(true);
187 case EditCurrentProfile
:
188 item
= pd_ui_
->profileTreeView
->currentIndex();
189 if (item
.isValid()) {
190 pd_ui_
->profileTreeView
->edit(item
);
194 case DeleteCurrentProfile
:
195 if (delete_current_profile()) {
196 mainApp
->setConfigurationProfile (Q_NULLPTR
);
203 QModelIndexList
ProfileDialog::selectedProfiles()
205 QModelIndexList profiles
;
207 foreach (QModelIndex idx
, pd_ui_
->profileTreeView
->selectionModel()->selectedIndexes())
209 QModelIndex temp
= sort_model_
->mapToSource(idx
);
210 if (! temp
.isValid() || profiles
.contains(temp
) || temp
.column() != ProfileModel::COL_NAME
)
219 void ProfileDialog::selectionChanged()
221 if (selectedProfiles().count() == 0)
222 pd_ui_
->profileTreeView
->selectRow(0);
227 void ProfileDialog::updateWidgets()
229 bool enable_del
= true;
230 bool enable_ok
= true;
231 bool multiple
= false;
232 bool enable_import
= true;
233 int user_profiles
= 0;
236 QModelIndex index
= sort_model_
->mapToSource(pd_ui_
->profileTreeView
->currentIndex());
237 QModelIndexList profiles
= selectedProfiles();
239 /* Ensure that the index is always the name column */
240 if (index
.column() != ProfileModel::COL_NAME
)
241 index
= index
.sibling(index
.row(), ProfileModel::COL_NAME
);
243 /* check if more than one viable profile is selected, and inform the sorting model */
244 if (profiles
.count() > 1)
247 /* Check if user profiles have been selected and allow export if it is so */
248 for (int cnt
= 0; cnt
< profiles
.count(); cnt
++)
250 if (! profiles
[cnt
].data(ProfileModel::DATA_IS_GLOBAL
).toBool() && ! profiles
[cnt
].data(ProfileModel::DATA_IS_DEFAULT
).toBool())
253 if (model_
->changesPending())
255 enable_import
= false;
256 msg
= tr("An import of profiles is not allowed, while changes are pending");
258 else if (model_
->importPending())
260 enable_import
= false;
261 msg
= tr("An import is pending to be saved. Additional imports are not allowed");
263 import_button_
->setToolTip(msg
);
264 import_button_
->setEnabled(enable_import
);
266 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
267 bool contains_user
= false;
268 bool enable_export
= false;
270 if (user_profiles
> 0)
271 contains_user
= true;
273 /* enable export if no changes are pending */
274 if (! model_
->changesPending())
275 enable_export
= true;
277 export_button_
->setEnabled(enable_export
);
281 export_button_
->setToolTip(tr("An export of profiles is only allowed for personal profiles"));
283 export_button_
->setToolTip(tr("An export of profiles is not allowed, while changes are pending"));
285 export_selected_entry_
->setVisible(contains_user
);
288 /* if the current profile is default with reset pending or a global one, deactivate delete */
293 if (index
.data(ProfileModel::DATA_IS_GLOBAL
).toBool())
295 else if (index
.data(ProfileModel::DATA_IS_DEFAULT
).toBool() && model_
->resetDefault())
298 else if (! index
.isValid())
306 /* multiple profiles are being selected, copy is no longer allowed */
307 pd_ui_
->copyToolButton
->setEnabled(false);
309 msg
= tr("%Ln Selected Personal Profile(s)...", "", user_profiles
);
310 pd_ui_
->hintLabel
->setText(msg
);
311 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
312 export_selected_entry_
->setText(msg
);
317 /* if only one profile is selected, display it's path in the hint label and activate link (if allowed) */
320 QString temp
= index
.data(ProfileModel::DATA_PATH
).toString();
321 if (index
.data(ProfileModel::DATA_PATH_IS_NOT_DESCRIPTION
).toBool() && QFileInfo(temp
).isDir())
322 hintUrl
= QUrl::fromLocalFile(temp
).toString();
323 pd_ui_
->hintLabel
->setText(temp
);
324 pd_ui_
->hintLabel
->setToolTip(index
.data(Qt::ToolTipRole
).toString());
326 if (! index
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() && ! index
.data(ProfileModel::DATA_IS_DEFAULT
).toBool())
327 msg
= tr("%Ln Selected Personal Profile(s)...", "", 1);
330 pd_ui_
->copyToolButton
->setEnabled(true);
331 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
332 export_selected_entry_
->setText(msg
);
336 /* Ensure, that the ok button is disabled, if an invalid name is used or if duplicate global profiles exist */
337 if (model_
&& model_
->rowCount() > 0)
340 for (int row
= 0; row
< model_
->rowCount() && enable_ok
; row
++)
342 QModelIndex idx
= model_
->index(row
, ProfileModel::COL_NAME
);
343 QString name
= idx
.data().toString();
345 if (! ProfileModel::checkNameValidity(name
, &msg
))
347 if (idx
== index
|| selectedProfiles().contains(idx
))
350 pd_ui_
->hintLabel
->setText(msg
);
357 if (model_
->checkInvalid(idx
) || (! idx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() && model_
->checkIfDeleted(idx
)) )
365 if (idx
!= index
&& idx
.data().toString().compare(index
.data().toString()) == 0)
367 if (idx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() == index
.data(ProfileModel::DATA_IS_GLOBAL
).toBool())
371 QList
<int> rows
= model_
->findAllByNameAndVisibility(name
, idx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool());
372 if (rows
.count() > 1)
376 if (enable_ok
&& ! model_
->checkIfDeleted(index
) && index
.data(ProfileModel::DATA_STATUS
).toInt() == PROF_STAT_CHANGED
)
380 pd_ui_
->hintLabel
->setUrl(hintUrl
);
382 pd_ui_
->deleteToolButton
->setEnabled(enable_del
);
383 ok_button_
->setEnabled(enable_ok
);
386 void ProfileDialog::currentItemChanged(const QModelIndex
&, const QModelIndex
&)
391 void ProfileDialog::newToolButtonClicked()
393 pd_ui_
->lineProfileFilter
->setText("");
394 pd_ui_
->cmbProfileTypes
->setCurrentIndex(ProfileSortModel::AllProfiles
);
395 sort_model_
->setFilterString();
397 QModelIndex ridx
= sort_model_
->mapFromSource(model_
->addNewProfile(tr("New profile")));
400 pd_ui_
->profileTreeView
->setCurrentIndex(ridx
);
401 pd_ui_
->profileTreeView
->scrollTo(ridx
);
402 pd_ui_
->profileTreeView
->edit(ridx
);
403 currentItemChanged();
409 void ProfileDialog::deleteToolButtonClicked()
411 QModelIndexList profiles
= selectedProfiles();
412 if (profiles
.count() <= 0)
415 model_
->deleteEntries(profiles
);
417 bool isGlobal
= model_
->activeProfile().data(ProfileModel::DATA_IS_GLOBAL
).toBool();
418 int row
= model_
->findByName(model_
->activeProfile().data().toString());
419 /* If the active profile is deleted, the default is selected next */
422 QModelIndex newIdx
= sort_model_
->mapFromSource(model_
->index(row
, 0));
423 if (newIdx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() != isGlobal
)
424 newIdx
= sort_model_
->mapFromSource(model_
->index(0, 0));
426 pd_ui_
->profileTreeView
->setCurrentIndex(newIdx
);
431 void ProfileDialog::copyToolButtonClicked()
433 QModelIndexList profiles
= selectedProfiles();
434 if (profiles
.count() > 1)
437 pd_ui_
->lineProfileFilter
->setText("");
438 pd_ui_
->cmbProfileTypes
->setCurrentIndex(ProfileSortModel::AllProfiles
);
439 sort_model_
->setFilterString();
441 QModelIndex current
= pd_ui_
->profileTreeView
->currentIndex();
442 if (current
.column() != ProfileModel::COL_NAME
)
443 current
= current
.sibling(current
.row(), ProfileModel::COL_NAME
);
445 QModelIndex source
= sort_model_
->mapToSource(current
);
446 QModelIndex ridx
= model_
->duplicateEntry(source
);
449 pd_ui_
->profileTreeView
->setCurrentIndex(sort_model_
->mapFromSource(ridx
));
450 pd_ui_
->profileTreeView
->scrollTo(sort_model_
->mapFromSource(ridx
));
451 pd_ui_
->profileTreeView
->edit(sort_model_
->mapFromSource(ridx
));
452 currentItemChanged();
458 void ProfileDialog::buttonBoxAccepted()
460 bool write_recent
= true;
461 bool item_data_removed
= false;
463 recent
.gui_profile_switch_check_count
= pd_ui_
->autoSwitchSpinBox
->value();
465 QModelIndex index
= sort_model_
->mapToSource(pd_ui_
->profileTreeView
->currentIndex());
467 pd_ui_
->buttonBox
->setFocus();
469 QModelIndexList profiles
= selectedProfiles();
470 if (profiles
.count() <= 0)
471 index
= QModelIndex();
473 QModelIndex default_item
= sort_model_
->mapFromSource(model_
->index(0, ProfileModel::COL_NAME
));
474 if (index
.isValid() && index
.column() != ProfileModel::COL_NAME
)
475 index
= index
.sibling(index
.row(), ProfileModel::COL_NAME
);
477 if (default_item
.data(ProfileModel::DATA_STATUS
).toInt() == PROF_STAT_DEFAULT
&& model_
->resetDefault())
479 // Reset Default profile.
480 GList
*fl_entry
= model_
->at(0);
481 remove_from_profile_list(fl_entry
);
483 // Don't write recent file if leaving the Default profile after this has been reset.
484 write_recent
= !is_default_profile();
486 // Don't fetch profile data if removed.
487 item_data_removed
= (index
.row() == 0);
491 /* Get the current geometry, before writing it to disk */
492 mainApp
->emitAppSignal(MainApplication::ProfileChanging
);
494 /* Write recent file for current profile now because
495 * the profile may be renamed in apply_profile_changes() */
496 write_profile_recent();
499 char * err_msg
= Q_NULLPTR
;
500 if ((err_msg
= apply_profile_changes()) != Q_NULLPTR
) {
501 QMessageBox::critical(this, tr("Profile Error"),
506 model_
->doResetModel();
510 model_
->doResetModel();
514 if (! index
.isValid() && model_
->lastSetRow() >= 0)
516 QModelIndex original
= model_
->index(model_
->lastSetRow(), ProfileModel::COL_NAME
);
517 index
= sort_model_
->mapFromSource(original
);
520 /* If multiple profiles are selected, do not change the selected profile */
521 if (index
.isValid() && ! item_data_removed
&& profiles
.count() <= 1)
523 profileName
= model_
->data(index
).toString();
526 if (profileName
.length() > 0 && model_
->findByName(profileName
) >= 0) {
527 // The new profile exists, change.
528 mainApp
->setConfigurationProfile (profileName
.toUtf8().constData(), false);
529 } else if (!model_
->activeProfile().isValid()) {
530 // The new profile does not exist, and the previous profile has
531 // been deleted. Change to the default profile.
532 mainApp
->setConfigurationProfile (Q_NULLPTR
, false);
536 void ProfileDialog::buttonBoxRejected()
539 if (! model_
->clearImported(&msg
))
540 QMessageBox::critical(this, tr("Error"), msg
);
543 void ProfileDialog::buttonBoxHelpRequested()
545 mainApp
->helpTopicAction(HELP_CONFIG_PROFILES_DIALOG
);
548 void ProfileDialog::dataChanged(const QModelIndex
&)
550 pd_ui_
->lineProfileFilter
->setText("");
551 pd_ui_
->cmbProfileTypes
->setCurrentIndex(ProfileSortModel::AllProfiles
);
553 pd_ui_
->profileTreeView
->setFocus();
554 if (model_
->lastSetRow() >= 0)
556 QModelIndex original
= model_
->index(model_
->lastSetRow(), ProfileModel::COL_NAME
);
557 pd_ui_
->profileTreeView
->setCurrentIndex(sort_model_
->mapFromSource(original
));
558 pd_ui_
->profileTreeView
->selectRow(sort_model_
->mapFromSource(original
).row());
564 void ProfileDialog::filterChanged(const QString
&text
)
566 if (qobject_cast
<QComboBox
*>(sender()))
568 QComboBox
* cmb
= qobject_cast
<QComboBox
*>(sender());
569 sort_model_
->setFilterType(static_cast<ProfileSortModel::FilterType
>(cmb
->currentIndex()));
571 else if (qobject_cast
<QLineEdit
*>(sender()))
572 sort_model_
->setFilterString(text
);
574 QModelIndex active
= sort_model_
->mapFromSource(model_
->activeProfile());
575 if (active
.isValid())
576 pd_ui_
->profileTreeView
->setCurrentIndex(active
);
579 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
580 void ProfileDialog::exportProfiles(bool exportAllPersonalProfiles
)
582 QAction
* action
= qobject_cast
<QAction
*>(sender());
583 if (action
&& action
->property(PROFILE_EXPORT_PROPERTY
).isValid())
584 exportAllPersonalProfiles
= action
->property(PROFILE_EXPORT_PROPERTY
).toString().compare(PROFILE_EXPORT_ALL
) == 0;
586 QModelIndexList items
;
589 if (! exportAllPersonalProfiles
)
591 foreach (QModelIndex idx
, selectedProfiles())
593 QModelIndex baseIdx
= sort_model_
->index(idx
.row(), ProfileModel::COL_NAME
);
594 if (! baseIdx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() && ! baseIdx
.data(ProfileModel::DATA_IS_DEFAULT
).toBool())
595 items
<< sort_model_
->mapToSource(baseIdx
);
600 else if (exportAllPersonalProfiles
)
602 for (int cnt
= 0; cnt
< sort_model_
->rowCount(); cnt
++)
604 QModelIndex idx
= sort_model_
->index(cnt
, ProfileModel::COL_NAME
);
605 if (! idx
.data(ProfileModel::DATA_IS_GLOBAL
).toBool() && ! idx
.data(ProfileModel::DATA_IS_DEFAULT
).toBool())
606 items
<< sort_model_
->mapToSource(idx
);
609 if (items
.count() == 0)
611 QString msg
= tr("No profiles found for export");
613 msg
.append(tr(", %Ln profile(s) skipped", "", skipped
));
614 QMessageBox::critical(this, tr("Exporting profiles"), msg
);
618 QString zipFile
= WiresharkFileDialog::getSaveFileName(this, tr("Select zip file for export"), openDialogInitialDir(), tr("Zip File (*.zip)"));
620 if (zipFile
.length() > 0)
622 QFileInfo
fi(zipFile
);
623 if (fi
.suffix().length() == 0 || fi
.suffix().toLower().compare("zip") != 0)
627 if (model_
->exportProfiles(zipFile
, items
, &err
))
629 QString msg
= tr("%Ln profile(s) exported", "", static_cast<int>(items
.count()));
631 msg
.append(tr(", %Ln profile(s) skipped", "", skipped
));
632 QMessageBox::information(this, tr("Exporting profiles"), msg
);
634 QFileInfo
zip(zipFile
);
635 storeLastDir(zip
.absolutePath());
639 QString msg
= tr("An error has occurred while exporting profiles");
640 if (err
.length() > 0)
641 msg
.append(QStringLiteral("\n\n%1: %2").arg(tr("Error"), err
));
642 QMessageBox::critical(this, tr("Exporting profiles"), msg
);
647 void ProfileDialog::importFromZip()
649 QString zipFile
= WiresharkFileDialog::getOpenFileName(this, tr("Select zip file for import"), openDialogInitialDir(), tr("Zip File (*.zip)"));
651 QFileInfo
fi(zipFile
);
657 int count
= model_
->importProfilesFromZip(zipFile
, &skipped
, &import
);
659 finishImport(fi
, count
, skipped
, import
);
663 void ProfileDialog::importFromDirectory()
665 QString importDir
= WiresharkFileDialog::getExistingDirectory(this, tr("Select directory for import"), openDialogInitialDir());
667 QFileInfo
fi(importDir
);
673 int count
= model_
->importProfilesFromDir(importDir
, &skipped
, false, &import
);
675 finishImport(fi
, count
, skipped
, import
);
678 void ProfileDialog::finishImport(QFileInfo fi
, int count
, int skipped
, QStringList import
)
681 QMessageBox::Icon icon
;
683 if (count
== 0 && skipped
== 0)
685 icon
= QMessageBox::Warning
;
686 msg
= tr("No profiles found for import in %1").arg(fi
.fileName());
690 icon
= QMessageBox::Information
;
691 msg
= tr("%Ln profile(s) imported", "", count
);
693 msg
.append(tr(", %Ln profile(s) skipped", "", skipped
));
695 QMessageBox
msgBox(icon
, tr("Importing profiles"), msg
, QMessageBox::Ok
, this);
698 storeLastDir(fi
.absolutePath());
704 model_
->markAsImported(import
);
705 int rowFirstImported
= model_
->findByName(import
.at(0));
706 QModelIndex idx
= sort_model_
->mapFromSource(model_
->index(rowFirstImported
, ProfileModel::COL_NAME
));
707 pd_ui_
->profileTreeView
->selectRow(idx
.isValid() ? idx
.row() : 0);
713 void ProfileDialog::resetTreeView()
717 pd_ui_
->profileTreeView
->setModel(Q_NULLPTR
);
718 sort_model_
->setSourceModel(Q_NULLPTR
);
719 model_
->disconnect();
720 if (pd_ui_
->profileTreeView
->selectionModel())
721 pd_ui_
->profileTreeView
->selectionModel()->disconnect();
726 model_
= new ProfileModel(pd_ui_
->profileTreeView
);
727 sort_model_
= new ProfileSortModel(pd_ui_
->profileTreeView
);
728 sort_model_
->setSourceModel(model_
);
729 pd_ui_
->profileTreeView
->setModel(sort_model_
);
731 connect(model_
, &ProfileModel::itemChanged
, this, &ProfileDialog::dataChanged
, Qt::QueuedConnection
);
732 QItemSelectionModel
*selModel
= pd_ui_
->profileTreeView
->selectionModel();
733 connect(selModel
, &QItemSelectionModel::currentChanged
,
734 this, &ProfileDialog::currentItemChanged
, Qt::QueuedConnection
);
735 connect(selModel
, &QItemSelectionModel::selectionChanged
,
736 this, &ProfileDialog::selectionChanged
);
740 if (sort_model_
->columnCount() <= 1) {
741 pd_ui_
->profileTreeView
->header()->hide();