diff --git a/src/error.h b/src/error.h index 41b4347..fca29dc 100644 --- a/src/error.h +++ b/src/error.h @@ -7,8 +7,8 @@ //a nice simple way of throwing up an error message if something goes wrong. -inline void errorBox(const QString &type, const QString &message, QWidget *parent = 0) { - QMessageBox::warning(parent, QString("%1 - %2").arg(QJOYPAD_DEVDIR, type), +inline void errorBox(const QString &title, const QString &message, QWidget *parent = 0) { + QMessageBox::warning(parent, QString("%1 - %2").arg(title, QJOYPAD_NAME), message, QMessageBox::Ok, Qt::NoButton); } diff --git a/src/layout.cpp b/src/layout.cpp index ed12be6..987523f 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -1,11 +1,14 @@ -#include "layout.h" -#include "config.h" - #include #include #include #include +#include + +#include "layout.h" +#include "config.h" + + //initialize things and set up an icon :) LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QString &settingsDir ) : devdir(devdir), settingsDir(settingsDir), @@ -168,13 +171,13 @@ bool LayoutManager::load(const QString& name) { //if the file isn't available, if (!file.exists()) { - errorBox("Load error","Failed to find a layout named " + name); + errorBox(tr("Load error"), tr("Failed to find a layout named %1.").arg(name), le); return false; } //if the file isn't readable, if (!file.open(QIODevice::ReadOnly)) { - errorBox("Load error","Error reading from file " + file.fileName()); + errorBox(tr("Load error"), tr("Error reading from file: %1").arg(file.fileName()), le); return false; } @@ -205,7 +208,9 @@ bool LayoutManager::load(const QString& name) { num = word.toInt(&okay); //make sure the number of the joystick is valid if (!okay || num < 1) { - errorBox( tr("Load error"), tr("Error reading joystick definition. Unexpected token \"%1\". Expected a positive number.").arg(word)); + errorBox(tr("Load error"), + tr("Error reading joystick definition. Unexpected token \"%1\". Expected a positive number.").arg(word), + le); if (name != currentLayout) reload(); else clear(); return false; @@ -213,7 +218,9 @@ bool LayoutManager::load(const QString& name) { stream.skipWhiteSpace(); stream >> ch; if (ch != QChar('{')) { - errorBox( tr("Load error"), tr("Error reading joystick definition. Unexpected character \"%1\". Expected '{'.").arg(ch)); + errorBox(tr("Load error"), + tr("Error reading joystick definition. Unexpected character \"%1\". Expected '{'.").arg(ch), + le); if (name != currentLayout) reload(); else clear(); return false; @@ -225,7 +232,7 @@ bool LayoutManager::load(const QString& name) { } //try to read the joypad, report error on fail. if (!joypads[index]->readConfig(stream)) { - errorBox( tr("Load error"), tr("Error reading definition for joystick %1.").arg(index)); + errorBox(tr("Load error"), tr("Error reading definition for joystick %1.").arg(index), le); //if this was attempting to change to a new layout and it failed, //revert back to the old layout. if (name != currentLayout) reload(); @@ -240,7 +247,9 @@ bool LayoutManager::load(const QString& name) { stream.readLine(); } else { - errorBox(tr("Load error"), tr("Error reading joystick definition. Unexpected token \"%1\". Expected \"Joystick\".").arg(word)); + errorBox(tr("Load error"), + tr("Error reading joystick definition. Unexpected token \"%1\". Expected \"Joystick\".").arg(word), + le); if (name != currentLayout) reload(); else clear(); return false; @@ -288,12 +297,18 @@ void LayoutManager::clear() { void LayoutManager::save() { if (currentLayout.isNull()) { saveAs(); - return; } + else { + save(getFileName(currentLayout)); + } +} - //get a filename - QString filename = getFileName( currentLayout ); +void LayoutManager::save(const QString &filename) { QFile file(filename); + save(file); +} + +void LayoutManager::save(QFile &file) { //if it's good, start writing the file if (file.open(QIODevice::WriteOnly)) { QTextStream stream( &file ); @@ -305,25 +320,32 @@ void LayoutManager::save() { } //if it's not, error. else { - errorBox(tr("Save error"), tr("Could not open file %1, layout not saved.").arg(filename)); + errorBox(tr("Save error"), tr("Could not open file %1, layout not saved.").arg(file.fileName()), le); } } - void LayoutManager::saveAs() { - bool ok; + bool ok = false; //request a new name! QString name = QInputDialog::getText(le, - tr("%1 - Name new layout").arg(QJOYPAD_NAME), + tr("Name new layout - %1").arg(QJOYPAD_NAME), tr("Enter a name for the new layout:"), - QLineEdit::Normal, QString::null, &ok ); + QLineEdit::Normal, QString::null, &ok); if (!ok) { return; } - QFile file(settingsDir + name + ".lyt"); + else if (name.isEmpty()) { + errorBox(tr("Save error"), tr("Layout name cannot be empty."), le); + return; + } + else if (name.contains('/')) { + errorBox(tr("Save error"), tr("Layout name may not contain a '/' (slash)."), le); + return; + } + QFile file(getFileName(name)); //don't overwrite an existing layout. if (file.exists()) { - errorBox(tr("Save error"), tr("That name's already taken!")); + errorBox(tr("Save error"), tr("That name's already taken!"), le); return; } @@ -331,7 +353,7 @@ void LayoutManager::saveAs() { setLayoutName(name); //since we have a new name for this layout now, we can save it normally :) - save(); + save(file); //add the new name to our lists fillPopup(); @@ -340,6 +362,67 @@ void LayoutManager::saveAs() { } } +void LayoutManager::importLayout() { + QFileDialog dialog(le); + dialog.setWindowTitle(tr("Import layout - %1").arg(QJOYPAD_NAME)); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + QStringList filters; + filters.append(tr("QJoyPad layout files (*.lyt)")); + filters.append(tr("Any files (*)")); + dialog.setNameFilters(filters); + dialog.setDefaultSuffix("lyt"); + if (dialog.exec() && !dialog.selectedFiles().isEmpty()) { + QString sourceFile = dialog.selectedFiles()[0]; + QFileInfo info(sourceFile); + QString layoutName = info.baseName(); + + if (layoutName.endsWith(".lyt",Qt::CaseInsensitive)) { + layoutName.truncate(layoutName.size() - 4); + } + + QString filename = getFileName(layoutName); + + if (info == QFileInfo(filename)) { + errorBox(tr("Import error"), tr("Cannot import file from QJoyPad settings directory.")); + return; + } + + if (QFile::exists(filename)) { + if (QMessageBox::warning(le, + QString("%1 - %2").arg(tr("Layout exists"), QJOYPAD_NAME), + tr("Layout %1 exists. Do you want to overwrite it?"), + tr("Over&write"), tr("&Cancel"), QString::null, 0, 1) == 1) { + return; + } + QFile::remove(filename); + } + QFile::copy(sourceFile, filename); + + fillPopup(); + if (le) { + le->updateLayoutList(); + } + + load(layoutName); + } +} + +void LayoutManager::exportLayout() { + QFileDialog dialog(le); + dialog.setWindowTitle(tr("Export layout - %1").arg(QJOYPAD_NAME)); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setAcceptMode(QFileDialog::AcceptSave); + QStringList filters; + filters.append(tr("QJoyPad layout files (*.lyt)")); + filters.append(tr("Any files (*)")); + dialog.setNameFilters(filters); + dialog.setDefaultSuffix("lyt"); + if (dialog.exec() && !dialog.selectedFiles().isEmpty()) { + save(dialog.selectedFiles()[0]); + } +} + void LayoutManager::saveDefault() { QFile file( settingsDir + "layout"); if (file.open(QIODevice::WriteOnly)) { @@ -350,12 +433,13 @@ void LayoutManager::saveDefault() { void LayoutManager::remove() { if (currentLayout.isNull()) return; - if (QMessageBox::warning(le, tr("%1 - Delete layout?").arg(QJOYPAD_NAME), - tr("Remove layout %1 permanently from your hard drive?").arg(currentLayout), tr("Delete"), tr("Cancel"), 0, 0, 1 ) == 1) + if (QMessageBox::warning(le, tr("Delete layout? - %1").arg(QJOYPAD_NAME), + tr("Remove layout %1 permanently from your hard drive?").arg(currentLayout), tr("&Delete"), tr("&Cancel"), QString::null, 0, 1 ) == 1) { return; + } QString filename = getFileName( currentLayout ); if (!QFile(filename).remove()) { - errorBox(tr("Remove error"), tr("Could not remove file %1").arg(filename)); + errorBox(tr("Remove error"), tr("Could not remove file %1").arg(filename), le); } fillPopup(); @@ -365,6 +449,45 @@ void LayoutManager::remove() { clear(); } +void LayoutManager::rename() { + if (currentLayout.isNull()) return; + bool ok = false; + QString name = QInputDialog::getText(le, + tr("Rename layout - %1").arg(QJOYPAD_NAME), + tr("Enter a new name for the layout:"), + QLineEdit::Normal, currentLayout, &ok); + if (!ok) { + return; + } + else if (name.isEmpty()) { + errorBox(tr("Rename error"), tr("Layout name cannot be empty."), le); + return; + } + else if (name.contains('/')) { + errorBox(tr("Rename error"), tr("Layout name may not contain a '/' (slash)."), le); + return; + } + + QString filename = getFileName(name); + + if (QFile::exists(filename)) { + errorBox(tr("Rename error"), tr("Layout with name %1 already exists.").arg(name), le); + return; + } + + if (!QFile::rename(getFileName(currentLayout), filename)) { + errorBox(tr("Rename error"), tr("Error renaming layout."), le); + return; + } + + fillPopup(); + if (le) { + le->updateLayoutList(); + } + + load(name); +} + QStringList LayoutManager::getLayoutNames() const { //goes through the list of .lyt files and removes the file extensions ;) QStringList result = QDir(settingsDir).entryList(QStringList("*.lyt")); @@ -397,7 +520,8 @@ void LayoutManager::iconClick() { //don't show the dialog if there aren't any joystick devices plugged in if (available.isEmpty()) { errorBox(tr("No joystick devices available"), - tr("No joystick devices are currently available to configure.\nPlease plug in a gaming device and select\n\"Update Joystick Devices\" from the popup menu.")); + tr("No joystick devices are currently available to configure.\nPlease plug in a gaming device and select\n\"Update Joystick Devices\" from the popup menu."), + le); return; } if (le) { diff --git a/src/layout.h b/src/layout.h index 63a43a7..e586949 100644 --- a/src/layout.h +++ b/src/layout.h @@ -54,13 +54,19 @@ class LayoutManager : public QObject { //save the current layout with its current name void save(); + void save(const QString& filename); + void save(QFile& file); //save the current layout with a new name void saveAs(); + void exportLayout(); + void importLayout(); //save the currently loaded layout so it can be recalled later void saveDefault(); //get rid of a layout void remove(); + //rename current layout + void rename(); //when the tray icon is clicked void iconClick(); diff --git a/src/layout_edit.cpp b/src/layout_edit.cpp index b3e9639..2e13b8d 100644 --- a/src/layout_edit.cpp +++ b/src/layout_edit.cpp @@ -2,35 +2,80 @@ #include "config.h" //build the dialog -LayoutEdit::LayoutEdit( LayoutManager* l ): QWidget(NULL) { - lm = l; +LayoutEdit::LayoutEdit( LayoutManager* l ) + : QWidget(0), + lm(l), + mainLayout(0), + padStack(0), + joyButtons(0), + cmbLayouts(0), + btnAdd(0), + btnRem(0), + btnUpd(0), + btnRev(0), + btnExport(0), + btnImport(0), + btnRename(0) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle( QJOYPAD_NAME ); setWindowIcon(QPixmap(QJOYPAD_ICON64)); - mainLayout = new QVBoxLayout( this); + mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(5); mainLayout->setMargin(5); QFrame* frame = new QFrame(this); - frame->setFrameStyle(QFrame::Box | QFrame::Sunken ); + frame->setFrameStyle(QFrame::Box | QFrame::Sunken); QGridLayout* g = new QGridLayout(frame); g->setMargin(5); g->setSpacing(5); cmbLayouts = new QComboBox(frame); connect(cmbLayouts, SIGNAL(activated(int)), this, SLOT(load(int))); - g->addWidget(cmbLayouts,0,0,1,4); + + QHBoxLayout *layoutLayout = new QHBoxLayout(this); //most of these buttons can link directly into slots in the LayoutManager - btnAdd = new QPushButton(QIcon::fromTheme("list-add"), tr("&Add"), frame); + btnAdd = new QPushButton(frame); + btnAdd->setIcon(QIcon::fromTheme("list-add")); + btnAdd->setToolTip(tr("Add Layout")); + if (btnAdd->icon().isNull()) { + btnAdd->setText("+"); + } + btnAdd->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(btnAdd, SIGNAL(clicked()), lm, SLOT(saveAs())); - g->addWidget(btnAdd,1,0); - btnRem = new QPushButton(QIcon::fromTheme("list-remove"), tr("&Remove"), frame); + + btnRem = new QPushButton(frame); + btnRem->setIcon(QIcon::fromTheme("list-remove")); + if (btnRem->icon().isNull()) { + btnRem->setText("-"); + } + btnRem->setToolTip(tr("Remove Layout")); + btnRem->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(btnRem, SIGNAL(clicked()), lm, SLOT(remove())); - g->addWidget(btnRem,1,1); + + btnRename = new QPushButton(tr("&Rename"), frame); + btnRename->setToolTip(tr("Rename Layout")); + btnRename->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(btnRename, SIGNAL(clicked()), lm, SLOT(rename())); + + layoutLayout->addWidget(cmbLayouts); + layoutLayout->addWidget(btnAdd); + layoutLayout->addWidget(btnRem); + layoutLayout->addWidget(btnRename); + mainLayout->addLayout(layoutLayout); + + btnImport = new QPushButton(QIcon::fromTheme("document-open"), tr("&Import"), frame); + connect(btnImport, SIGNAL(clicked()), lm, SLOT(importLayout())); + g->addWidget(btnImport,1,0); + + btnExport = new QPushButton(QIcon::fromTheme("document-save-as"), tr("E&xport"), frame); + connect(btnExport, SIGNAL(clicked()), lm, SLOT(exportLayout())); + g->addWidget(btnExport,1,1); + btnUpd = new QPushButton(QIcon::fromTheme("document-save"), tr("&Save"), frame); connect(btnUpd, SIGNAL(clicked()), lm, SLOT(save())); g->addWidget(btnUpd,1,2); + btnRev = new QPushButton(QIcon::fromTheme("document-revert"), tr("Re&vert"), frame); connect(btnRev, SIGNAL(clicked()), lm, SLOT(reload())); g->addWidget(btnRev,1,3); @@ -70,7 +115,7 @@ LayoutEdit::LayoutEdit( LayoutManager* l ): QWidget(NULL) { updateLayoutList(); //add the buttons at the bottom. - QHBoxLayout* h = new QHBoxLayout(0); + QHBoxLayout* h = new QHBoxLayout(this); h->setMargin(0); h->setSpacing(5); QPushButton* close = new QPushButton(QIcon::fromTheme("window-close"), tr("&Close Dialog"), this ); @@ -94,6 +139,10 @@ void LayoutEdit::setLayout(const QString &layout) { } } + bool hasLayout = !layout.isNull(); + btnRem->setEnabled(hasLayout); + btnRename->setEnabled(hasLayout); + //update all the JoyPadWidgets. for (int i = 0, n = lm->available.count(); i < n; i++) { ((JoyPadWidget*)padStack->widget(i))->update(); diff --git a/src/layout_edit.h b/src/layout_edit.h index 5a34f74..7450877 100644 --- a/src/layout_edit.h +++ b/src/layout_edit.h @@ -36,7 +36,7 @@ class LayoutEdit : public QWidget { QStackedWidget *padStack; FlashRadioArray *joyButtons; QComboBox* cmbLayouts; - QPushButton *btnAdd, *btnRem, *btnUpd, *btnRev; + QPushButton *btnAdd, *btnRem, *btnUpd, *btnRev, *btnExport, *btnImport, *btnRename; }; #endif