diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 92903b48d..edc3dcf32 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,6 +12,8 @@ set(LAUNCHER utils/filedialog.cpp utils/naturalsort.cpp utils/lineedit.cpp + utils/profilescombobox.cpp + utils/textinputdialog.cpp launcher.rc ) @@ -26,10 +28,12 @@ set(LAUNCHER_HEADER model/modelitem.hpp model/esm/esmfile.hpp - utils/combobox.hpp utils/lineedit.hpp utils/filedialog.hpp utils/naturalsort.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp + ) # Headers that must be pre-processed @@ -43,9 +47,10 @@ set(LAUNCHER_HEADER_MOC model/modelitem.hpp model/esm/esmfile.hpp - utils/combobox.hpp utils/lineedit.hpp utils/filedialog.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ce3d6b31d..01b879842 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -6,10 +6,11 @@ #include "model/datafilesmodel.hpp" #include "model/esm/esmfile.hpp" -#include "utils/combobox.hpp" +#include "utils/profilescombobox.hpp" #include "utils/filedialog.hpp" #include "utils/lineedit.hpp" #include "utils/naturalsort.hpp" +#include "utils/textinputdialog.hpp" #include "datafilespage.hpp" @@ -139,9 +140,11 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) // Bottom part with profile options QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); - mProfilesComboBox = new ComboBox(this); + mProfilesComboBox = new ProfilesComboBox(this); mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - mProfilesComboBox->setInsertPolicy(QComboBox::InsertAtBottom); + mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); + mProfilesComboBox->setDuplicatesEnabled(false); + mProfilesComboBox->setEditEnabled(false); mProfileToolBar = new QToolBar(this); mProfileToolBar->setMovable(false); @@ -156,16 +159,22 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) pageLayout->addWidget(splitter); pageLayout->addWidget(mProfileToolBar); + // Create a dialog for the new profile name input + mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + + connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mMastersModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); - connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(const QString))); + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mPluginsTable, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); + connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&))); + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); createActions(); setupConfig(); @@ -230,12 +239,21 @@ void DataFilesPage::setupConfig() mLauncherConfig->beginGroup("Profiles"); QStringList profiles = mLauncherConfig->childGroups(); - if (profiles.isEmpty()) { - // Add a default profile - profiles.append("Default"); + // Add the profiles to the combobox + foreach (const QString &profile, profiles) { + + if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) + continue; // Profile name contains garbage + + + qDebug() << "adding " << profile; + mProfilesComboBox->addItem(profile); } - mProfilesComboBox->addItems(profiles); + // Add a default profile + if (mProfilesComboBox->count() == 0) { + mProfilesComboBox->addItem(QString("Default")); + } QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); @@ -572,33 +590,37 @@ void DataFilesPage::writeConfig(QString profile) void DataFilesPage::newProfile() { - bool ok; - QString text = QInputDialog::getText(this, tr("New Profile"), - tr("Profile Name:"), QLineEdit::Normal, - tr("New Profile"), &ok); - if (ok && !text.isEmpty()) { - if (mProfilesComboBox->findText(text) != -1) { - QMessageBox::warning(this, tr("Profile already exists"), - tr("the profile %0 already exists.").arg(text), - QMessageBox::Ok); - } else { - // Add the new profile to the combobox - mProfilesComboBox->addItem(text); - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); + if (mNewProfileDialog->exec() == QDialog::Accepted) { - } + const QString text = mNewProfileDialog->lineEdit()->text(); + mProfilesComboBox->addItem(text); + // Copy the currently checked items to cfg + writeConfig(text); + mLauncherConfig->sync(); + + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); } } +void DataFilesPage::updateOkButton(const QString &text) +{ + if (text.isEmpty()) { + mNewProfileDialog->setOkButtonEnabled(false); + return; + } + + (mProfilesComboBox->findText(text) == -1) + ? mNewProfileDialog->setOkButtonEnabled(true) + : mNewProfileDialog->setOkButtonEnabled(false); +} + void DataFilesPage::deleteProfile() { QString profile = mProfilesComboBox->currentText(); - - if (profile.isEmpty()) { + if (profile.isEmpty()) return; - } QMessageBox msgBox(this); msgBox.setWindowTitle(tr("Delete Profile")); @@ -694,19 +716,17 @@ void DataFilesPage::setCheckState(QModelIndex index) return; if (object->objectName() == QLatin1String("PluginsTable")) { - if (mPluginsModel->checkState(index) == Qt::Checked) { - mPluginsModel->setCheckState(index, Qt::Unchecked); - } else { - mPluginsModel->setCheckState(index, Qt::Checked); - } + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index); + + (mPluginsModel->checkState(sourceIndex) == Qt::Checked) + ? mPluginsModel->setCheckState(index, Qt::Unchecked) + : mPluginsModel->setCheckState(index, Qt::Checked); } if (object->objectName() == QLatin1String("MastersTable")) { - if (mMastersModel->checkState(index) == Qt::Checked) { - mMastersModel->setCheckState(index, Qt::Unchecked); - } else { - mMastersModel->setCheckState(index, Qt::Checked); - } + (mMastersModel->checkState(index) == Qt::Checked) + ? mMastersModel->setCheckState(index, Qt::Unchecked) + : mMastersModel->setCheckState(index, Qt::Checked); } return; @@ -721,13 +741,23 @@ void DataFilesPage::filterChanged(const QString filter) void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) { + qDebug() << "Profile is changed from: " << previous << " to " << current; // Prevent the deletion of the default profile - (current == QLatin1String("Default")) ? mDeleteProfileAction->setEnabled(false) - : mDeleteProfileAction->setEnabled(true); + if (current == QLatin1String("Default")) { + mDeleteProfileAction->setEnabled(false); + mProfilesComboBox->setEditEnabled(false); + } else { + mDeleteProfileAction->setEnabled(true); + mProfilesComboBox->setEditEnabled(true); + } if (!previous.isEmpty()) { writeConfig(previous); mLauncherConfig->sync(); + + if (mProfilesComboBox->currentIndex() == -1) + return; + } else { return; } @@ -737,6 +767,36 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre readConfig(); } +void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) +{ + if (previous.isEmpty()) + return; + + // Save the new profile name + writeConfig(current); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(previous); + mLauncherConfig->remove(""); // Clear the subgroup + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + mLauncherConfig->sync(); + + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); + + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); + readConfig(); +} + void DataFilesPage::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view @@ -756,11 +816,9 @@ void DataFilesPage::showContextMenu(const QPoint &point) if (!index.isValid()) return; - if (mPluginsModel->checkState(index) == Qt::Checked) { - mUncheckAction->setEnabled(true); - } else { - mCheckAction->setEnabled(true); - } + (mPluginsModel->checkState(index) == Qt::Checked) + ? mUncheckAction->setEnabled(true) + : mCheckAction->setEnabled(true); } // Show menu diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 64f255b57..8b48c1e12 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -3,7 +3,7 @@ #include #include - +#include "utils/profilescombobox.hpp" #include @@ -13,9 +13,10 @@ class QSettings; class QAction; class QToolBar; class QMenu; -class ComboBox; +class ProfilesComboBox; class DataFilesModel; +class TextInputDialog; namespace Files { struct ConfigurationManager; } @@ -26,7 +27,7 @@ class DataFilesPage : public QWidget public: DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); - ComboBox *mProfilesComboBox; + ProfilesComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); bool setupDataFiles(); @@ -37,6 +38,8 @@ public slots: void filterChanged(const QString filter); void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); + void profileRenamed(const QString &previous, const QString ¤t); + void updateOkButton(const QString &text); // Action slots void newProfile(); @@ -77,6 +80,8 @@ private: QSettings *mLauncherConfig; + TextInputDialog *mNewProfileDialog; + // const QStringList checkedPlugins(); // const QStringList selectedMasters(); diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 4ae09f844..7c4cb5f7e 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -11,7 +11,7 @@ int main(int argc, char *argv[]) // Now we make sure the current dir is set to application path QDir dir(QCoreApplication::applicationDirPath()); - #if defined(Q_OS_MAC) + #ifdef Q_OS_MAC if (dir.dirName() == "MacOS") { dir.cdUp(); dir.cdUp(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index d65e51f24..3ce418ddf 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,7 +1,5 @@ #include -#include "utils/combobox.hpp" - #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" diff --git a/apps/launcher/utils/combobox.hpp b/apps/launcher/utils/combobox.hpp deleted file mode 100644 index bc99575d7..000000000 --- a/apps/launcher/utils/combobox.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef COMBOBOX_H -#define COMBOBOX_H - -#include - -class ComboBox : public QComboBox -{ - Q_OBJECT -private: - QString oldText; -public: - ComboBox(QWidget *parent=0) : QComboBox(parent), oldText() - { - connect(this,SIGNAL(editTextChanged(const QString&)), this, - SLOT(textChangedSlot(const QString&))); - connect(this,SIGNAL(currentIndexChanged(const QString&)), this, - SLOT(textChangedSlot(const QString&))); - } -private slots: - void textChangedSlot(const QString &newText) - { - emit textChanged(oldText, newText); - oldText = newText; - } -signals: - void textChanged(const QString &oldText, const QString &newText); -}; -#endif \ No newline at end of file diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp new file mode 100644 index 000000000..8354d4a78 --- /dev/null +++ b/apps/launcher/utils/profilescombobox.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "profilescombobox.hpp" + +ProfilesComboBox::ProfilesComboBox(QWidget *parent) : + QComboBox(parent) +{ + mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore + + setEditable(true); + setValidator(mValidator); + setCompleter(0); + + connect(this, SIGNAL(currentIndexChanged(int)), this, + SLOT(slotIndexChanged(int))); + connect(lineEdit(), SIGNAL(returnPressed()), this, + SLOT(slotReturnPressed())); +} + +void ProfilesComboBox::setEditEnabled(bool editable) +{ + if (!editable) + return setEditable(false); + + // Reset the completer and validator + setEditable(true); + setValidator(mValidator); + setCompleter(0); +} + +void ProfilesComboBox::slotReturnPressed() +{ + QString current = currentText(); + QString previous = itemText(currentIndex()); + + if (findText(current) != -1) + return; + + setItemText(currentIndex(), current); + emit(profileRenamed(previous, current)); +} + +void ProfilesComboBox::slotIndexChanged(int index) +{ + if (index == -1) + return; + + emit(profileChanged(mOldProfile, currentText())); + mOldProfile = itemText(index); +} diff --git a/apps/launcher/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp new file mode 100644 index 000000000..c7da60d2a --- /dev/null +++ b/apps/launcher/utils/profilescombobox.hpp @@ -0,0 +1,30 @@ +#ifndef PROFILESCOMBOBOX_HPP +#define PROFILESCOMBOBOX_HPP + +#include + +class QString; + +class QRegExpValidator; + +class ProfilesComboBox : public QComboBox +{ + Q_OBJECT +public: + explicit ProfilesComboBox(QWidget *parent = 0); + void setEditEnabled(bool editable); + +signals: + void profileChanged(const QString &previous, const QString ¤t); + void profileRenamed(const QString &oldName, const QString &newName); + +private slots: + void slotReturnPressed(); + void slotIndexChanged(int index); + +private: + QString mOldProfile; + QRegExpValidator *mValidator; +}; + +#endif // PROFILESCOMBOBOX_HPP diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp new file mode 100644 index 000000000..16cadb661 --- /dev/null +++ b/apps/launcher/utils/textinputdialog.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + +#include "lineedit.hpp" + +#include "textinputdialog.hpp" + +TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) : + QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + mButtonBox = new QDialogButtonBox(this); + mButtonBox->addButton(QDialogButtonBox::Ok); + mButtonBox->addButton(QDialogButtonBox::Cancel); + + setMaximumHeight(height()); + setOkButtonEnabled(false); + setModal(true); + + // Messageboxes on mac have no title +#ifndef Q_OS_MAC + setWindowTitle(title); +#else + Q_UNUSED(title); +#endif + + QLabel *label = new QLabel(this); + label->setText(text); + + // Line edit + QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore + mLineEdit = new LineEdit(this); + mLineEdit->setValidator(validator); + mLineEdit->setCompleter(0); + + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->addWidget(label); + dialogLayout->addWidget(mLineEdit); + dialogLayout->addWidget(mButtonBox); + + connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +int TextInputDialog::exec() +{ + mLineEdit->clear(); + mLineEdit->setFocus(); + return QDialog::exec(); +} + +void TextInputDialog::setOkButtonEnabled(bool enabled) +{ + + QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok); + okButton->setEnabled(enabled); +} diff --git a/apps/launcher/utils/textinputdialog.hpp b/apps/launcher/utils/textinputdialog.hpp new file mode 100644 index 000000000..cbb453ac8 --- /dev/null +++ b/apps/launcher/utils/textinputdialog.hpp @@ -0,0 +1,28 @@ +#ifndef TEXTINPUTDIALOG_HPP +#define TEXTINPUTDIALOG_HPP + +#include +//#include "lineedit.hpp" + +class QDialogButtonBox; +class LineEdit; + +class TextInputDialog : public QDialog +{ + Q_OBJECT +public: + explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0); + inline LineEdit *lineEdit() { return mLineEdit; } + void setOkButtonEnabled(bool enabled); + + LineEdit *mLineEdit; + + int exec(); + +private: + QDialogButtonBox *mButtonBox; + + +}; + +#endif // TEXTINPUTDIALOG_HPP