From 43d16fc87adfe58aa78d924e3ab8488ebd729c54 Mon Sep 17 00:00:00 2001 From: Mark Ganson TheMarkster <39143564+mwganson@users.noreply.github.com> Date: Sun, 2 Sep 2018 13:10:22 -0500 Subject: [PATCH] Add Duplicate button to Execute Macro dialog With the Duplicate button a macro is duplicated with a new name, e.g. duplicate a macro named "MyMacro.FCMacro" and you get a new duplicate file named "MyMacro@001.FCMacro", but the user has opportunity to override the new name with a name of his own or to cancel the operation. Functionality is similar to already existing ability to create copies of the .FCStd file, only for macros, and this must be done manually for each new file. Will be useful to coders mostly. Expected use case could be to save a history of the macro periodically as changes are made or perhaps to duplicate the macro first, and then make changes to the duplicate, eventually replacing the original once satisfied with the changes. New code is based largely on existing code from rename operation, but with QFile.copy() instead of QFile.rename() used, along with other changes needed, such as generating the new suggested filenames. link to forum discussion and demonstration video: https://forum.freecadweb.org/viewtopic.php?f=8&p=254014&sid=98243801791920b69086a3fcd4699e34#p254014 Not sure how to make the Duplicate button label text translate when changing languages. --- src/Gui/DlgMacroExecute.ui | 15 ++++-- src/Gui/DlgMacroExecuteImp.cpp | 95 ++++++++++++++++++++++++++++++++++ src/Gui/DlgMacroExecuteImp.h | 1 + 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/Gui/DlgMacroExecute.ui b/src/Gui/DlgMacroExecute.ui index ed756ca81c..6ecd00c072 100644 --- a/src/Gui/DlgMacroExecute.ui +++ b/src/Gui/DlgMacroExecute.ui @@ -166,9 +166,6 @@ Qt::StrongFocus - - Gui::FileChooser::Directory - @@ -264,6 +261,16 @@ + + + + Duplicate + + + false + + + @@ -309,9 +316,9 @@ deleteButton editButton renameButton + duplicateButton addonsButton fileChooser - diff --git a/src/Gui/DlgMacroExecuteImp.cpp b/src/Gui/DlgMacroExecuteImp.cpp index 1a46a96e6b..5d4c7e3c32 100644 --- a/src/Gui/DlgMacroExecuteImp.cpp +++ b/src/Gui/DlgMacroExecuteImp.cpp @@ -139,6 +139,7 @@ void DlgMacroExecuteImp::on_userMacroListBox_currentItemChanged(QTreeWidgetItem* createButton->setEnabled(true); editButton->setEnabled(true); renameButton->setEnabled(true); + duplicateButton->setEnabled(true); } else { executeButton->setEnabled(false); @@ -146,6 +147,7 @@ void DlgMacroExecuteImp::on_userMacroListBox_currentItemChanged(QTreeWidgetItem* createButton->setEnabled(true); editButton->setEnabled(false); renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } } @@ -159,6 +161,7 @@ void DlgMacroExecuteImp::on_systemMacroListBox_currentItemChanged(QTreeWidgetIte createButton->setEnabled(false); editButton->setEnabled(true); //look but don't touch renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } else { executeButton->setEnabled(false); @@ -166,6 +169,7 @@ void DlgMacroExecuteImp::on_systemMacroListBox_currentItemChanged(QTreeWidgetIte createButton->setEnabled(false); editButton->setEnabled(false); renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } } @@ -181,6 +185,7 @@ void DlgMacroExecuteImp::on_tabMacroWidget_currentChanged(int index) createButton->setEnabled(true); editButton->setEnabled(true); renameButton->setEnabled(true); + duplicateButton->setEnabled(true); } else { executeButton->setEnabled(false); @@ -188,6 +193,7 @@ void DlgMacroExecuteImp::on_tabMacroWidget_currentChanged(int index) createButton->setEnabled(true); editButton->setEnabled(false); renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } } else { //index==1 system-wide @@ -199,6 +205,7 @@ void DlgMacroExecuteImp::on_tabMacroWidget_currentChanged(int index) createButton->setEnabled(false); editButton->setEnabled(true); //but you can't save it renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } else { executeButton->setEnabled(false); @@ -206,6 +213,7 @@ void DlgMacroExecuteImp::on_tabMacroWidget_currentChanged(int index) createButton->setEnabled(false); editButton->setEnabled(false); renameButton->setEnabled(false); + duplicateButton->setEnabled(false); } } @@ -438,6 +446,93 @@ void DlgMacroExecuteImp::on_renameButton_clicked() } } } +/**Duplicates selected macro + * New file has same name as original but with "@" and 3-digit number appended + * Begins with "@001" and increments until available name is found + * "MyMacro.FCMacro" becomes "MyMacro@001.FCMacro" + * "MyMacro@002.FCMacro.py" becomes "MyMacro@003.FCMacro.py" unless there is + * no already existing "MyMacro@001.FCMacro.py" + */ +void DlgMacroExecuteImp::on_duplicateButton_clicked() +{ + QDir dir; + QTreeWidgetItem* item = 0; + + int index = tabMacroWidget->currentIndex(); + if (index == 0) { //user-specific + item = userMacroListBox->currentItem(); + dir.setPath(this->macroPath); + } + + if (!item){ + return; + } + + QString oldName = item->text(0); + QFileInfo oldfi(dir, oldName); + QFile oldfile(oldfi.absoluteFilePath()); + QString completeSuffix = oldfi.completeSuffix(); //everything after the first "." + QString baseName = oldfi.baseName(); //everything before first "." + QString neutralSymbol = QString::fromStdString("@"); + QString last3 = baseName.right(3); + bool ok = true; //was conversion to int successful? + int nLast3 = last3.toInt(&ok); + last3 = QString::fromStdString("001"); //increment beginning with 001 no matter what + if (ok ){ + //last3 were all digits, so we strip them from the base name + if (baseName.size()>3){ //if <= 3 leave be (e.g. 2.py becomes 2@001.py) + baseName = baseName.left(baseName.size()-3); //strip digits + if (baseName.endsWith(neutralSymbol)){ + baseName = baseName.left(baseName.size()-1); //trim the "@", will be added back later + } + } + } + //at this point baseName = the base name without any digits, e.g. "MyMacro" + //neutralSymbol = "@" + //last3 is a string representing 3 digits, always "001" at this time + //completeSuffix = FCMacro or py or FCMacro.py or else suffix will become FCMacro below + + QString oldNameDigitized = baseName+neutralSymbol+last3+QString::fromStdString(".")+completeSuffix; + QFileInfo fi(dir, oldNameDigitized); + // increment until we find available name with smallest digits + // test from "001" through "999", then give up and let user enter name of choice + while (fi.exists()) { + nLast3 = last3.toInt()+1; + if (nLast3 >=1000){ //avoid infinite loop, 999 files will have to be enough + break; + } + last3 = QString::number(nLast3); + while (last3.size()<3){ + last3.prepend(QString::fromStdString("0")); //pad 0's if needed + } + oldNameDigitized = baseName+neutralSymbol+last3+QString::fromStdString(".")+completeSuffix; + fi = QFileInfo(dir,oldNameDigitized); + } + + // give user a chance to pick a different name from digitized name suggested + QString fn = QInputDialog::getText(this, tr("Duplicate Macro"), + tr("Enter new name:"), QLineEdit::Normal, oldNameDigitized, 0); + if (!fn.isEmpty() && fn != oldName) { + QString suffix = QFileInfo(fn).suffix().toLower(); + if (suffix != QLatin1String("fcmacro") && suffix != QLatin1String("py")){ + fn += QLatin1String(".FCMacro"); + } + QFileInfo fi(dir, fn); + // check again if new name exists in case user changed it + if (fi.exists()) { + QMessageBox::warning(this, tr("Existing file"), + tr("'%1'\n already exists.").arg(fi.absoluteFilePath())); + } + else if (!oldfile.copy(fi.absoluteFilePath())) { + QMessageBox::warning(this, tr("Duplicate Failed"), + tr("Failed to duplicate to '%1'.\nPerhaps a file permission error?").arg(fi.absoluteFilePath())); + } + + this->fillUpList(); //repopulate list to show new file + } + +} + /** * convenience link button to open tools -> addon manager * from within macro dialog diff --git a/src/Gui/DlgMacroExecuteImp.h b/src/Gui/DlgMacroExecuteImp.h index 0f0f3fe0d3..83be29f994 100644 --- a/src/Gui/DlgMacroExecuteImp.h +++ b/src/Gui/DlgMacroExecuteImp.h @@ -51,6 +51,7 @@ public Q_SLOTS: void on_deleteButton_clicked(); void on_editButton_clicked(); void on_renameButton_clicked(); + void on_duplicateButton_clicked(); void on_addonsButton_clicked(); protected Q_SLOTS: