/*************************************************************************** * Copyright (c) 2002 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Action.h" #include "Application.h" #include "Document.h" #include "Command.h" #include "Control.h" #include "FileDialog.h" #include "MainWindow.h" #include "BitmapFactory.h" #include "Selection.h" #include "DlgProjectInformationImp.h" #include "DlgProjectUtility.h" #include "Transform.h" #include "Placement.h" #include "ManualAlignment.h" #include "WaitCursor.h" #include "ViewProvider.h" #include #include #include "MergeDocuments.h" #include "NavigationStyle.h" #include "GraphvizView.h" #include "DlgObjectSelection.h" FC_LOG_LEVEL_INIT("Command", false) using namespace Gui; //=========================================================================== // Std_Open //=========================================================================== DEF_STD_CMD(StdCmdOpen) StdCmdOpen::StdCmdOpen() : Command("Std_Open") { // setting the sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Open..."); sToolTipText = QT_TR_NOOP("Open a document or import files"); sWhatsThis = "Std_Open"; sStatusTip = QT_TR_NOOP("Open a document or import files"); sPixmap = "document-open"; sAccel = keySequenceToAccel(QKeySequence::Open); eType = NoTransaction; } void StdCmdOpen::activated(int iMsg) { Q_UNUSED(iMsg); // fill the list of registered endings QString formatList; const char* supported = QT_TR_NOOP("Supported formats"); const char* allFiles = QT_TR_NOOP("All files (*.*)"); formatList = QObject::tr(supported); formatList += QLatin1String(" ("); std::vector filetypes = App::GetApplication().getImportTypes(); std::vector::iterator it; // Make sure FCStd is the very first fileformat it = std::find(filetypes.begin(), filetypes.end(), "FCStd"); if (it != filetypes.end()) { filetypes.erase(it); filetypes.insert(filetypes.begin(), "FCStd"); } for (it=filetypes.begin();it != filetypes.end();++it) { formatList += QLatin1String(" *."); formatList += QLatin1String(it->c_str()); } formatList += QLatin1String(");;"); std::map FilterList = App::GetApplication().getImportFilters(); std::map::iterator jt; // Make sure the format name for FCStd is the very first in the list for (jt=FilterList.begin();jt != FilterList.end();++jt) { if (jt->first.find("*.FCStd") != std::string::npos) { formatList += QLatin1String(jt->first.c_str()); formatList += QLatin1String(";;"); FilterList.erase(jt); break; } } for (jt=FilterList.begin();jt != FilterList.end();++jt) { formatList += QLatin1String(jt->first.c_str()); formatList += QLatin1String(";;"); } formatList += QObject::tr(allFiles); QString selectedFilter; QStringList fileList = FileDialog::getOpenFileNames(getMainWindow(), QObject::tr("Open document"), QString(), formatList, &selectedFilter); if (fileList.isEmpty()) return; // load the files with the associated modules SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter); if (dict.isEmpty()) { QMessageBox::critical(getMainWindow(), qApp->translate("StdCmdOpen", "Cannot open file"), qApp->translate("StdCmdOpen", "Loading the file %1 is not supported").arg(fileList.front())); } else { for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { getGuiApplication()->open(it.key().toUtf8(), it.value().toLatin1()); } } } //=========================================================================== // Std_Import //=========================================================================== DEF_STD_CMD_A(StdCmdImport) StdCmdImport::StdCmdImport() : Command("Std_Import") { // setting the sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Import..."); sToolTipText = QT_TR_NOOP("Import a file in the active document"); sWhatsThis = "Std_Import"; sStatusTip = QT_TR_NOOP("Import a file in the active document"); //sPixmap = "Open"; sAccel = "Ctrl+I"; } void StdCmdImport::activated(int iMsg) { Q_UNUSED(iMsg); // fill the list of registered endings QString formatList; const char* supported = QT_TR_NOOP("Supported formats"); const char* allFiles = QT_TR_NOOP("All files (*.*)"); formatList = QObject::tr(supported); formatList += QLatin1String(" ("); std::vector filetypes = App::GetApplication().getImportTypes(); std::vector::const_iterator it; for (it=filetypes.begin();it != filetypes.end();++it) { if (*it != "FCStd") { // ignore the project file format formatList += QLatin1String(" *."); formatList += QLatin1String(it->c_str()); } } formatList += QLatin1String(");;"); std::map FilterList = App::GetApplication().getImportFilters(); std::map::const_iterator jt; for (jt=FilterList.begin();jt != FilterList.end();++jt) { // ignore the project file format if (jt->first.find("(*.FCStd)") == std::string::npos) { formatList += QLatin1String(jt->first.c_str()); formatList += QLatin1String(";;"); } } formatList += QObject::tr(allFiles); Base::Reference hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp") ->GetGroup("Preferences")->GetGroup("General"); QString selectedFilter = QString::fromStdString(hPath->GetASCII("FileImportFilter")); QStringList fileList = FileDialog::getOpenFileNames(getMainWindow(), QObject::tr("Import file"), QString(), formatList, &selectedFilter); if (!fileList.isEmpty()) { hPath->SetASCII("FileImportFilter", selectedFilter.toLatin1().constData()); SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter); bool emptyDoc = (getActiveGuiDocument()->getDocument()->countObjects() == 0); // load the files with the associated modules for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { getGuiApplication()->importFrom(it.key().toUtf8(), getActiveGuiDocument()->getDocument()->getName(), it.value().toLatin1()); } if (emptyDoc) { // only do a view fit if the document was empty before. See also parameter 'AutoFitToView' in importFrom() std::list views = getActiveGuiDocument()->getMDIViewsOfType(Gui::View3DInventor::getClassTypeId()); for (std::list::iterator it = views.begin(); it != views.end(); ++it) { (*it)->viewAll(); } } } } bool StdCmdImport::isActive(void) { return (getActiveGuiDocument() ? true : false); } //=========================================================================== // Std_Export //=========================================================================== DEF_STD_CMD_A(StdCmdExport) StdCmdExport::StdCmdExport() : Command("Std_Export") { // setting the sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Export..."); sToolTipText = QT_TR_NOOP("Export an object in the active document"); sWhatsThis = "Std_Export"; sStatusTip = QT_TR_NOOP("Export an object in the active document"); //sPixmap = "Open"; sAccel = "Ctrl+E"; eType = 0; } void StdCmdExport::activated(int iMsg) { Q_UNUSED(iMsg); if (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId()) == 0) { QMessageBox::warning(Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("No selection")), QString::fromUtf8(QT_TR_NOOP("Please select first the objects you want to export."))); return; } // fill the list of registered endings QStringList filterList; std::map FilterList = App::GetApplication().getExportFilters(); std::map::const_iterator jt; for (jt=FilterList.begin();jt != FilterList.end();++jt) { // ignore the project file format if (jt->first.find("(*.FCStd)") == std::string::npos) { filterList << QString::fromLatin1(jt->first.c_str()); } } QString formatList = filterList.join(QLatin1String(";;")); Base::Reference hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp") ->GetGroup("Preferences")->GetGroup("General"); QString selectedFilter = QString::fromStdString(hPath->GetASCII("FileExportFilter")); QString fileName = FileDialog::getSaveFileName(getMainWindow(), QObject::tr("Export file"), QString(), formatList, &selectedFilter); if (!fileName.isEmpty()) { hPath->SetASCII("FileExportFilter", selectedFilter.toLatin1().constData()); SelectModule::Dict dict = SelectModule::exportHandler(fileName, selectedFilter); // export the files with the associated modules for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) { getGuiApplication()->exportTo(it.key().toUtf8(), getActiveGuiDocument()->getDocument()->getName(), it.value().toLatin1()); } } } bool StdCmdExport::isActive(void) { return (getActiveGuiDocument() ? true : false); } //=========================================================================== // Std_MergeProjects //=========================================================================== DEF_STD_CMD_A(StdCmdMergeProjects) StdCmdMergeProjects::StdCmdMergeProjects() : Command("Std_MergeProjects") { sAppModule = "File"; sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Merge project..."); sToolTipText = QT_TR_NOOP("Merge project"); sWhatsThis = "Std_MergeProjects"; sStatusTip = QT_TR_NOOP("Merge project"); } void StdCmdMergeProjects::activated(int iMsg) { Q_UNUSED(iMsg); QString exe = qApp->applicationName(); QString project = FileDialog::getOpenFileName(Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("Merge project")), FileDialog::getWorkingDirectory(), QString::fromUtf8(QT_TR_NOOP("%1 document (*.FCStd)")).arg(exe)); if (!project.isEmpty()) { FileDialog::setWorkingDirectory(project); App::Document* doc = App::GetApplication().getActiveDocument(); QFileInfo info(QString::fromUtf8(doc->FileName.getValue())); QFileInfo proj(project); if (proj == info) { QMessageBox::critical(Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("Merge project")), QString::fromUtf8(QT_TR_NOOP("Cannot merge project with itself."))); return; } doc->openTransaction("Merge project"); Base::FileInfo fi((const char*)project.toUtf8()); Base::ifstream str(fi, std::ios::in | std::ios::binary); MergeDocuments md(doc); md.importObjects(str); str.close(); doc->commitTransaction(); } } bool StdCmdMergeProjects::isActive(void) { return this->hasActiveDocument(); } //=========================================================================== // Std_DependencyGraph //=========================================================================== DEF_STD_CMD_A(StdCmdDependencyGraph) StdCmdDependencyGraph::StdCmdDependencyGraph() : Command("Std_DependencyGraph") { // setting the sGroup = QT_TR_NOOP("Tools"); sMenuText = QT_TR_NOOP("Dependency graph..."); sToolTipText = QT_TR_NOOP("Show the dependency graph of the objects in the active document"); sStatusTip = QT_TR_NOOP("Show the dependency graph of the objects in the active document"); sWhatsThis = "Std_DependencyGraph"; eType = 0; sPixmap = "Std_DependencyGraph"; } void StdCmdDependencyGraph::activated(int iMsg) { Q_UNUSED(iMsg); App::Document* doc = App::GetApplication().getActiveDocument(); Gui::GraphvizView* view = new Gui::GraphvizView(*doc); view->setWindowTitle(qApp->translate("Std_DependencyGraph","Dependency graph")); getMainWindow()->addWindow(view); } bool StdCmdDependencyGraph::isActive(void) { return (getActiveGuiDocument() ? true : false); } //=========================================================================== // Std_New //=========================================================================== DEF_STD_CMD(StdCmdNew) StdCmdNew::StdCmdNew() :Command("Std_New") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&New"); sToolTipText = QT_TR_NOOP("Create a new empty document"); sWhatsThis = "Std_New"; sStatusTip = QT_TR_NOOP("Create a new empty document"); sPixmap = "document-new"; sAccel = keySequenceToAccel(QKeySequence::New); } void StdCmdNew::activated(int iMsg) { Q_UNUSED(iMsg); QString cmd; cmd = QString::fromLatin1("App.newDocument(\"%1\")") .arg(qApp->translate("StdCmdNew","Unnamed")); runCommand(Command::Doc,cmd.toUtf8()); doCommand(Command::Gui,"Gui.activeDocument().activeView().viewDefaultOrientation()"); ParameterGrp::handle hViewGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); if (hViewGrp->GetBool("ShowAxisCross")) doCommand(Command::Gui,"Gui.ActiveDocument.ActiveView.setAxisCross(True)"); } //=========================================================================== // Std_Save //=========================================================================== DEF_STD_CMD_A(StdCmdSave) StdCmdSave::StdCmdSave() :Command("Std_Save") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Save"); sToolTipText = QT_TR_NOOP("Save the active document"); sWhatsThis = "Std_Save"; sStatusTip = QT_TR_NOOP("Save the active document"); sPixmap = "document-save"; sAccel = keySequenceToAccel(QKeySequence::Save); eType = 0; } void StdCmdSave::activated(int iMsg) { Q_UNUSED(iMsg); #if 0 Gui::Document* pActiveDoc = getActiveGuiDocument(); if ( pActiveDoc ) pActiveDoc->save(); else #endif doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"Save\")"); } bool StdCmdSave::isActive(void) { #if 0 if( getActiveGuiDocument() ) return true; else #endif return getGuiApplication()->sendHasMsgToActiveView("Save"); } //=========================================================================== // Std_SaveAs //=========================================================================== DEF_STD_CMD_A(StdCmdSaveAs) StdCmdSaveAs::StdCmdSaveAs() :Command("Std_SaveAs") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Save &As..."); sToolTipText = QT_TR_NOOP("Save the active document under a new file name"); sWhatsThis = "Std_SaveAs"; sStatusTip = QT_TR_NOOP("Save the active document under a new file name"); #if QT_VERSION >= 0x040200 sPixmap = "document-save-as"; #endif sAccel = keySequenceToAccel(QKeySequence::SaveAs); eType = 0; } void StdCmdSaveAs::activated(int iMsg) { Q_UNUSED(iMsg); #if 0 Gui::Document* pActiveDoc = getActiveGuiDocument(); if ( pActiveDoc ) pActiveDoc->saveAs(); else #endif doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"SaveAs\")"); } bool StdCmdSaveAs::isActive(void) { #if 0 if( getActiveGuiDocument() ) return true; else #endif return getGuiApplication()->sendHasMsgToActiveView("SaveAs"); } //=========================================================================== // Std_SaveCopy //=========================================================================== DEF_STD_CMD_A(StdCmdSaveCopy) StdCmdSaveCopy::StdCmdSaveCopy() :Command("Std_SaveCopy") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Save a &Copy..."); sToolTipText = QT_TR_NOOP("Save a copy of the active document under a new file name"); sWhatsThis = "Std_SaveCopy"; sStatusTip = QT_TR_NOOP("Save a copy of the active document under a new file name"); //sPixmap = "document-save-as"; } void StdCmdSaveCopy::activated(int iMsg) { Q_UNUSED(iMsg); #if 0 Gui::Document* pActiveDoc = getActiveGuiDocument(); if ( pActiveDoc ) pActiveDoc->saveCopy(); else #endif doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"SaveCopy\")"); } bool StdCmdSaveCopy::isActive(void) { return ( getActiveGuiDocument() ? true : false ); } //=========================================================================== // Std_SaveAll //=========================================================================== DEF_STD_CMD_A(StdCmdSaveAll) StdCmdSaveAll::StdCmdSaveAll() :Command("Std_SaveAll") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Save All"); sToolTipText = QT_TR_NOOP("Save all opened document"); sWhatsThis = "Std_SaveAll"; sStatusTip = QT_TR_NOOP("Save all opened document"); } void StdCmdSaveAll::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Document::saveAll(); } bool StdCmdSaveAll::isActive(void) { return ( getActiveGuiDocument() ? true : false ); } //=========================================================================== // Std_Revert //=========================================================================== DEF_STD_CMD_A(StdCmdRevert) StdCmdRevert::StdCmdRevert() :Command("Std_Revert") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Revert"); sToolTipText = QT_TR_NOOP("Reverts to the saved version of this file"); sWhatsThis = "Std_Revert"; sStatusTip = QT_TR_NOOP("Reverts to the saved version of this file"); //sPixmap = "document-revert"; eType = NoTransaction; } void StdCmdRevert::activated(int iMsg) { Q_UNUSED(iMsg); QMessageBox msgBox(Gui::getMainWindow()); msgBox.setIcon(QMessageBox::Question); msgBox.setWindowTitle(qApp->translate("Std_Revert","Revert document")); msgBox.setText(qApp->translate("Std_Revert","This will discard all the changes since last file save.")); msgBox.setInformativeText(qApp->translate("Std_Revert","Do you want to continue?")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); if (ret == QMessageBox::Yes) doCommand(Command::App,"App.ActiveDocument.restore()"); } bool StdCmdRevert::isActive(void) { return ( getActiveGuiDocument() ? true : false ); } //=========================================================================== // Std_ProjectInfo //=========================================================================== DEF_STD_CMD_A(StdCmdProjectInfo) StdCmdProjectInfo::StdCmdProjectInfo() :Command("Std_ProjectInfo") { // setting the sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("Project i&nformation..."); sToolTipText = QT_TR_NOOP("Show details of the currently active project"); sWhatsThis = "Std_ProjectInfo"; sStatusTip = QT_TR_NOOP("Show details of the currently active project"); #if QT_VERSION >= 0x040200 sPixmap = "document-properties"; #endif } void StdCmdProjectInfo::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Dialog::DlgProjectInformationImp dlg(getActiveGuiDocument()->getDocument(), getMainWindow()); dlg.exec(); } bool StdCmdProjectInfo::isActive(void) { return ( getActiveGuiDocument() ? true : false ); } //=========================================================================== // Std_ProjectUtil //=========================================================================== DEF_STD_CMD_A(StdCmdProjectUtil) StdCmdProjectUtil::StdCmdProjectUtil() :Command("Std_ProjectUtil") { // setting the sGroup = QT_TR_NOOP("Tools"); sWhatsThis = "Std_ProjectUtil"; sMenuText = QT_TR_NOOP("Project utility..."); sToolTipText = QT_TR_NOOP("Utility to extract or create project files"); sStatusTip = QT_TR_NOOP("Utility to extract or create project files"); sPixmap = "Std_ProjectUtil"; } void StdCmdProjectUtil::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Dialog::DlgProjectUtility dlg(getMainWindow()); dlg.exec(); } bool StdCmdProjectUtil::isActive(void) { return true; } //=========================================================================== // Std_Print //=========================================================================== DEF_STD_CMD_A(StdCmdPrint) StdCmdPrint::StdCmdPrint() :Command("Std_Print") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Print..."); sToolTipText = QT_TR_NOOP("Print the document"); sWhatsThis = "Std_Print"; sStatusTip = QT_TR_NOOP("Print the document"); sPixmap = "document-print"; sAccel = keySequenceToAccel(QKeySequence::Print); eType = 0; } void StdCmdPrint::activated(int iMsg) { Q_UNUSED(iMsg); if (getMainWindow()->activeWindow()) { getMainWindow()->showMessage(QObject::tr("Printing...")); getMainWindow()->activeWindow()->print(); } } bool StdCmdPrint::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("Print"); } //=========================================================================== // Std_PrintPreview //=========================================================================== DEF_STD_CMD_A(StdCmdPrintPreview) StdCmdPrintPreview::StdCmdPrintPreview() :Command("Std_PrintPreview") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Print preview..."); sToolTipText = QT_TR_NOOP("Print the document"); sWhatsThis = "Std_PrintPreview"; sStatusTip = QT_TR_NOOP("Print preview"); sPixmap = "document-print-preview"; eType = 0; } void StdCmdPrintPreview::activated(int iMsg) { Q_UNUSED(iMsg); if (getMainWindow()->activeWindow()) { getMainWindow()->activeWindow()->printPreview(); } } bool StdCmdPrintPreview::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("PrintPreview"); } //=========================================================================== // Std_PrintPdf //=========================================================================== DEF_STD_CMD_A(StdCmdPrintPdf) StdCmdPrintPdf::StdCmdPrintPdf() :Command("Std_PrintPdf") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("&Export PDF..."); sToolTipText = QT_TR_NOOP("Export the document as PDF"); sWhatsThis = "Std_PrintPdf"; sStatusTip = QT_TR_NOOP("Export the document as PDF"); eType = 0; } void StdCmdPrintPdf::activated(int iMsg) { Q_UNUSED(iMsg); if (getMainWindow()->activeWindow()) { getMainWindow()->showMessage(QObject::tr("Exporting PDF...")); getMainWindow()->activeWindow()->printPdf(); } } bool StdCmdPrintPdf::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("PrintPdf"); } //=========================================================================== // Std_Quit //=========================================================================== DEF_STD_CMD(StdCmdQuit) StdCmdQuit::StdCmdQuit() :Command("Std_Quit") { sGroup = QT_TR_NOOP("File"); sMenuText = QT_TR_NOOP("E&xit"); sToolTipText = QT_TR_NOOP("Quits the application"); sWhatsThis = "Std_Quit"; sStatusTip = QT_TR_NOOP("Quits the application"); #if QT_VERSION >= 0x040200 sPixmap = "application-exit"; #endif sAccel = "Alt+F4"; eType = NoTransaction; } void StdCmdQuit::activated(int iMsg) { Q_UNUSED(iMsg); // close the main window and exit the event loop getMainWindow()->close(); } //=========================================================================== // Std_Undo //=========================================================================== DEF_STD_CMD_AC(StdCmdUndo) StdCmdUndo::StdCmdUndo() :Command("Std_Undo") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Undo"); sToolTipText = QT_TR_NOOP("Undo exactly one action"); sWhatsThis = "Std_Undo"; sStatusTip = QT_TR_NOOP("Undo exactly one action"); sPixmap = "edit-undo"; sAccel = keySequenceToAccel(QKeySequence::Undo); eType = ForEdit|NoTransaction; } void StdCmdUndo::activated(int iMsg) { Q_UNUSED(iMsg); // Application::Instance->slotUndo(); getGuiApplication()->sendMsgToActiveView("Undo"); } bool StdCmdUndo::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("Undo"); } Action * StdCmdUndo::createAction(void) { Action *pcAction; pcAction = new UndoAction(this,getMainWindow()); pcAction->setShortcut(QString::fromLatin1(sAccel)); applyCommandData(this->className(), pcAction); if (sPixmap) pcAction->setIcon(Gui::BitmapFactory().iconFromTheme(sPixmap)); return pcAction; } //=========================================================================== // Std_Redo //=========================================================================== DEF_STD_CMD_AC(StdCmdRedo) StdCmdRedo::StdCmdRedo() :Command("Std_Redo") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Redo"); sToolTipText = QT_TR_NOOP("Redoes a previously undone action"); sWhatsThis = "Std_Redo"; sStatusTip = QT_TR_NOOP("Redoes a previously undone action"); sPixmap = "edit-redo"; sAccel = keySequenceToAccel(QKeySequence::Redo); eType = ForEdit|NoTransaction; } void StdCmdRedo::activated(int iMsg) { Q_UNUSED(iMsg); // Application::Instance->slotRedo(); getGuiApplication()->sendMsgToActiveView("Redo"); } bool StdCmdRedo::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("Redo"); } Action * StdCmdRedo::createAction(void) { Action *pcAction; pcAction = new RedoAction(this,getMainWindow()); pcAction->setShortcut(QString::fromLatin1(sAccel)); applyCommandData(this->className(), pcAction); if (sPixmap) pcAction->setIcon(Gui::BitmapFactory().iconFromTheme(sPixmap)); return pcAction; } //=========================================================================== // Std_Cut //=========================================================================== DEF_STD_CMD_A(StdCmdCut) StdCmdCut::StdCmdCut() : Command("Std_Cut") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Cut"); sToolTipText = QT_TR_NOOP("Cut out"); sWhatsThis = "Std_Cut"; sStatusTip = QT_TR_NOOP("Cut out"); sPixmap = "edit-cut"; sAccel = keySequenceToAccel(QKeySequence::Cut); } void StdCmdCut::activated(int iMsg) { Q_UNUSED(iMsg); getGuiApplication()->sendMsgToActiveView("Cut"); } bool StdCmdCut::isActive(void) { return getGuiApplication()->sendHasMsgToActiveView("Cut"); } //=========================================================================== // Std_Copy //=========================================================================== DEF_STD_CMD_A(StdCmdCopy) StdCmdCopy::StdCmdCopy() : Command("Std_Copy") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("C&opy"); sToolTipText = QT_TR_NOOP("Copy operation"); sWhatsThis = "Std_Copy"; sStatusTip = QT_TR_NOOP("Copy operation"); sPixmap = "edit-copy"; sAccel = keySequenceToAccel(QKeySequence::Copy); } void StdCmdCopy::activated(int iMsg) { Q_UNUSED(iMsg); bool done = getGuiApplication()->sendMsgToFocusView("Copy"); if (!done) { QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection(); QClipboard* cb = QApplication::clipboard(); cb->setMimeData(mimeData); } } bool StdCmdCopy::isActive(void) { if (getGuiApplication()->sendHasMsgToFocusView("Copy")) return true; return Selection().hasSelection(); } //=========================================================================== // Std_Paste //=========================================================================== DEF_STD_CMD_A(StdCmdPaste) StdCmdPaste::StdCmdPaste() : Command("Std_Paste") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Paste"); sToolTipText = QT_TR_NOOP("Paste operation"); sWhatsThis = "Std_Paste"; sStatusTip = QT_TR_NOOP("Paste operation"); sPixmap = "edit-paste"; sAccel = keySequenceToAccel(QKeySequence::Paste); } void StdCmdPaste::activated(int iMsg) { Q_UNUSED(iMsg); bool done = getGuiApplication()->sendMsgToFocusView("Paste"); if (!done) { QClipboard* cb = QApplication::clipboard(); const QMimeData* mimeData = cb->mimeData(); if (mimeData) { WaitCursor wc; getMainWindow()->insertFromMimeData(mimeData); } } } bool StdCmdPaste::isActive(void) { if (getGuiApplication()->sendHasMsgToFocusView("Paste")) return true; QClipboard* cb = QApplication::clipboard(); const QMimeData* mime = cb->mimeData(); if (!mime) return false; return getMainWindow()->canInsertFromMimeData(mime); } DEF_STD_CMD_A(StdCmdDuplicateSelection) StdCmdDuplicateSelection::StdCmdDuplicateSelection() :Command("Std_DuplicateSelection") { sAppModule = "Edit"; sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Duplicate selection"); sToolTipText = QT_TR_NOOP("Put duplicates of the selected objects to the active document"); sWhatsThis = "Std_DuplicateSelection"; sStatusTip = QT_TR_NOOP("Put duplicates of the selected objects to the active document"); sPixmap = "Std_DuplicateSelection"; } void StdCmdDuplicateSelection::activated(int iMsg) { Q_UNUSED(iMsg); std::vector sel; std::set objSet; for(auto &s : Selection().getCompleteSelection()) { if(s.pObject && s.pObject->getNameInDocument() && objSet.insert(s.pObject).second) sel.push_back(s.pObject); } if(sel.empty()) return; bool hasXLink = false; Base::FileInfo fi(App::Application::getTempFileName()); { auto all = App::Document::getDependencyList(sel); if (all.size() > sel.size()) { DlgObjectSelection dlg(sel,getMainWindow()); if(dlg.exec()!=QDialog::Accepted) return; sel = dlg.getSelections(); if(sel.empty()) return; } std::vector unsaved; hasXLink = App::PropertyXLink::hasXLink(sel,&unsaved); if(unsaved.size()) { QMessageBox::critical(getMainWindow(), QObject::tr("Unsaved document"), QObject::tr("The exported object contains external link. Please save the document" "at least once before exporting.")); return; } // save stuff to file Base::ofstream str(fi, std::ios::out | std::ios::binary); App::Document* doc = sel.front()->getDocument(); MergeDocuments mimeView(doc); doc->exportObjects(sel, str); str.close(); } App::Document* doc = App::GetApplication().getActiveDocument(); if (doc) { bool proceed = true; if(hasXLink && !doc->isSaved()) { int ret = QMessageBox::question(getMainWindow(), qApp->translate("Std_DuplicateSelection","Object dependencies"), qApp->translate("Std_DuplicateSelection", "To link to external objects, the document must be saved at least once.\n" "Do you want to save the document now?"), QMessageBox::Yes,QMessageBox::No); if(ret == QMessageBox::Yes) proceed = Application::Instance->getDocument(doc)->saveAs(); } if(proceed) { doc->openTransaction("Duplicate"); // restore objects from file and add to active document Base::ifstream str(fi, std::ios::in | std::ios::binary); MergeDocuments mimeView(doc); mimeView.importObjects(str); str.close(); doc->commitTransaction(); } } fi.deleteFile(); } bool StdCmdDuplicateSelection::isActive(void) { return Gui::Selection().hasSelection(); } //=========================================================================== // Std_SelectAll //=========================================================================== DEF_STD_CMD_A(StdCmdSelectAll) StdCmdSelectAll::StdCmdSelectAll() : Command("Std_SelectAll") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Select &All"); sToolTipText = QT_TR_NOOP("Select all"); sWhatsThis = "Std_SelectAll"; sStatusTip = QT_TR_NOOP("Select all"); #if QT_VERSION >= 0x040200 sPixmap = "edit-select-all"; #endif //sAccel = "Ctrl+A"; // superseeds shortcuts for text edits } void StdCmdSelectAll::activated(int iMsg) { Q_UNUSED(iMsg); SelectionSingleton& rSel = Selection(); App::Document* doc = App::GetApplication().getActiveDocument(); std::vector objs = doc->getObjectsOfType(App::DocumentObject::getClassTypeId()); rSel.setSelection(doc->getName(), objs); } bool StdCmdSelectAll::isActive(void) { return App::GetApplication().getActiveDocument() != 0; } //=========================================================================== // Std_Delete //=========================================================================== DEF_STD_CMD_A(StdCmdDelete) StdCmdDelete::StdCmdDelete() :Command("Std_Delete") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Delete"); sToolTipText = QT_TR_NOOP("Deletes the selected objects"); sWhatsThis = "Std_Delete"; sStatusTip = QT_TR_NOOP("Deletes the selected objects"); #if QT_VERSION >= 0x040200 sPixmap = "edit-delete"; #endif sAccel = keySequenceToAccel(QKeySequence::Delete); eType = ForEdit; } void StdCmdDelete::activated(int iMsg) { Q_UNUSED(iMsg); std::set docs; try { openCommand(QT_TRANSLATE_NOOP("Command", "Delete")); if (getGuiApplication()->sendHasMsgToFocusView(getName())) { commitCommand(); return; } App::TransactionLocker tlock; Gui::getMainWindow()->setUpdatesEnabled(false); auto editDoc = Application::Instance->editDocument(); ViewProviderDocumentObject *vpedit = 0; if(editDoc) vpedit = dynamic_cast(editDoc->getInEdit()); if(vpedit) { for(auto &sel : Selection().getSelectionEx(editDoc->getDocument()->getName())) { if(sel.getObject() == vpedit->getObject()) { if (!sel.getSubNames().empty()) { vpedit->onDelete(sel.getSubNames()); docs.insert(editDoc->getDocument()); } break; } } } else { std::set affectedLabels; bool more = false; auto sels = Selection().getSelectionEx(); bool autoDeletion = true; for(auto &sel : sels) { auto obj = sel.getObject(); for(auto parent : obj->getInList()) { if(!Selection().isSelected(parent)) { ViewProvider* vp = Application::Instance->getViewProvider(parent); if (vp && !vp->canDelete(obj)) { autoDeletion = false; QString label; if(parent->getDocument() != obj->getDocument()) label = QLatin1String(parent->getFullName().c_str()); else label = QLatin1String(parent->getNameInDocument()); if(parent->Label.getStrValue() != parent->getNameInDocument()) label += QString::fromLatin1(" (%1)").arg( QString::fromUtf8(parent->Label.getValue())); affectedLabels.insert(label); if(affectedLabels.size()>=10) { more = true; break; } } } } if(more) break; } // The check below is not needed because we now only get selection // from the active document #if 0 //check for inactive objects in selection Mantis #3477 std::set inactiveLabels; App::Application& app = App::GetApplication(); App::Document* actDoc = app.getActiveDocument(); for (std::vector::iterator ft = sels.begin(); ft != sels.end(); ++ft) { App::DocumentObject* obj = ft->getObject(); App::Document* objDoc = obj->getDocument(); if (actDoc != objDoc) { inactiveLabels.insert(QString::fromUtf8(obj->Label.getValue())); autoDeletion = false; } } #endif if (!autoDeletion) { QString bodyMessage; QTextStream bodyMessageStream(&bodyMessage); bodyMessageStream << qApp->translate("Std_Delete", "The following referencing objects might break.\n\n" "Are you sure you want to continue?\n"); for (const auto ¤tLabel : affectedLabels) bodyMessageStream << '\n' << currentLabel; if(more) bodyMessageStream << "\n..."; #if 0 //message for inactive items if (!inactiveLabels.empty()) { if (!affectedLabels.empty()) { bodyMessageStream << "\n"; } std::string thisDoc = pGuiDoc->getDocument()->getName(); bodyMessageStream << qApp->translate("Std_Delete", "These items are selected for deletion, but are not in the active document."); for (const auto ¤tLabel : inactiveLabels) bodyMessageStream << currentLabel << " / " << Base::Tools::fromStdString(thisDoc) << '\n'; } #endif int ret = QMessageBox::warning(Gui::getMainWindow(), qApp->translate("Std_Delete", "Object dependencies"), bodyMessage, QMessageBox::Yes, QMessageBox::No); if (ret == QMessageBox::Yes) autoDeletion = true; } if (autoDeletion) { for(auto &sel : sels) { auto obj = sel.getObject(); Gui::ViewProvider* vp = Application::Instance->getViewProvider(obj); if (vp) { // ask the ViewProvider if it wants to do some clean up if (vp->onDelete(sel.getSubNames())) { FCMD_OBJ_DOC_CMD(obj,"removeObject('" << obj->getNameInDocument() << "')"); docs.insert(obj->getDocument()); } } } } } if(docs.size()) { const auto &outList = App::PropertyXLink::getDocumentOutList(); for(auto it=docs.begin();it!=docs.end();++it) { auto itd = outList.find(*it); if(itd!=outList.end()) { for(auto doc : itd->second) { if(doc != *it) docs.erase(doc); } } } for(auto doc : docs) { FCMD_DOC_CMD(doc,"recompute()"); } } } catch (const Base::Exception& e) { QMessageBox::critical(getMainWindow(), QObject::tr("Delete failed"), QString::fromLatin1(e.what())); e.ReportException(); } catch (...) { QMessageBox::critical(getMainWindow(), QObject::tr("Delete failed"), QString::fromLatin1("Unknown error")); } commitCommand(); Gui::getMainWindow()->setUpdatesEnabled(true); Gui::getMainWindow()->update(); } bool StdCmdDelete::isActive(void) { return Selection().getCompleteSelection().size() > 0; } //=========================================================================== // Std_Refresh //=========================================================================== DEF_STD_CMD_A(StdCmdRefresh) StdCmdRefresh::StdCmdRefresh() : Command("Std_Refresh") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("&Refresh"); sToolTipText = QT_TR_NOOP("Recomputes the current active document"); sWhatsThis = "Std_Refresh"; sStatusTip = QT_TR_NOOP("Recomputes the current active document"); sPixmap = "view-refresh"; sAccel = keySequenceToAccel(QKeySequence::Refresh); eType = AlterDoc | Alter3DView | AlterSelection | ForEdit; bCanLog = false; // Make it optional to create a transaction for a recompute. // The new default behaviour is quite cumbersome in some cases because when // undoing the last transaction the manual recompute will clear the redo stack. ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Document"); bool create = hGrp->GetBool("TransactionOnRecompute", true); if (!create) eType = eType | NoTransaction; } void StdCmdRefresh::activated(int iMsg) { Q_UNUSED(iMsg); if (getActiveGuiDocument()) { App::AutoTransaction trans((eType & NoTransaction) ? nullptr : "Recompute"); try { doCommand(Doc,"App.activeDocument().recompute(None,True,True)"); } catch (Base::Exception& /*e*/) { int ret = QMessageBox::warning(getMainWindow(), QObject::tr("Dependency error"), qApp->translate("Std_Refresh", "The document contains dependency cycles.\n" "Please check the Report View for more details.\n\n" "Do you still want to proceed?"), QMessageBox::Yes, QMessageBox::No); if(ret == QMessageBox::No) return; doCommand(Doc,"App.activeDocument().recompute(None,True)"); } } } bool StdCmdRefresh::isActive(void) { return this->getDocument() && this->getDocument()->mustExecute(); } //=========================================================================== // Std_Transform //=========================================================================== DEF_STD_CMD_A(StdCmdTransform) StdCmdTransform::StdCmdTransform() : Command("Std_Transform") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Transform..."); sToolTipText = QT_TR_NOOP("Transform the geometry of selected objects"); sStatusTip = QT_TR_NOOP("Transform the geometry of selected objects"); sWhatsThis = "Std_Transform"; } void StdCmdTransform::activated(int iMsg) { Q_UNUSED(iMsg); Gui::Control().showDialog(new Gui::Dialog::TaskTransform()); } bool StdCmdTransform::isActive(void) { return (Gui::Control().activeDialog()==0); } //=========================================================================== // Std_Placement //=========================================================================== DEF_STD_CMD_A(StdCmdPlacement) StdCmdPlacement::StdCmdPlacement() : Command("Std_Placement") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Placement..."); sToolTipText = QT_TR_NOOP("Place the selected objects"); sStatusTip = QT_TR_NOOP("Place the selected objects"); sWhatsThis = "Std_Placement"; sPixmap = "Std_Placement"; } void StdCmdPlacement::activated(int iMsg) { Q_UNUSED(iMsg); std::vector sel = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId()); Gui::Dialog::TaskPlacement* plm = new Gui::Dialog::TaskPlacement(); if (!sel.empty()) { App::Property* prop = sel.front()->getPropertyByName("Placement"); if (prop && prop->getTypeId() == App::PropertyPlacement::getClassTypeId()) plm->setPlacement(static_cast(prop)->getValue()); } Gui::Control().showDialog(plm); } bool StdCmdPlacement::isActive(void) { return (Gui::Control().activeDialog()==0); } //=========================================================================== // Std_TransformManip //=========================================================================== DEF_STD_CMD_A(StdCmdTransformManip) StdCmdTransformManip::StdCmdTransformManip() : Command("Std_TransformManip") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Transform"); sToolTipText = QT_TR_NOOP("Transform the selected object in the 3d view"); sStatusTip = QT_TR_NOOP("Transform the selected object in the 3d view"); sWhatsThis = "Std_TransformManip"; } void StdCmdTransformManip::activated(int iMsg) { Q_UNUSED(iMsg); if (getActiveGuiDocument()->getInEdit()) getActiveGuiDocument()->resetEdit(); std::vector sel = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId()); Gui::ViewProvider* vp = Application::Instance->getViewProvider(sel.front()); // FIXME: Need a way to force 'Transform' edit mode // #0000477: Proper interface for edit modes of view provider if (vp) getActiveGuiDocument()->setEdit(vp, Gui::ViewProvider::Transform); } bool StdCmdTransformManip::isActive(void) { return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 1; } //=========================================================================== // Std_Alignment //=========================================================================== DEF_STD_CMD_A(StdCmdAlignment) StdCmdAlignment::StdCmdAlignment() : Command("Std_Alignment") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Alignment..."); sToolTipText = QT_TR_NOOP("Align the selected objects"); sStatusTip = QT_TR_NOOP("Align the selected objects"); sWhatsThis = "Std_Alignment"; sPixmap = "Std_Alignment"; } void StdCmdAlignment::activated(int iMsg) { Q_UNUSED(iMsg); std::vector sel = Gui::Selection().getObjectsOfType (App::GeoFeature::getClassTypeId()); ManualAlignment* align = ManualAlignment::instance(); QObject::connect(align, SIGNAL(emitCanceled()), align, SLOT(deleteLater())); QObject::connect(align, SIGNAL(emitFinished()), align, SLOT(deleteLater())); // Get the fixed and moving meshes FixedGroup fixedGroup; std::map groupMap; fixedGroup.addView(sel[0]); groupMap[0].addView(sel[1]); // add the fixed group align->setFixedGroup(fixedGroup); // create the model of movable groups MovableGroupModel model; model.addGroups(groupMap); align->setModel(model); Base::Type style = Base::Type::fromName("Gui::CADNavigationStyle"); Base::Vector3d upDir(0,1,0), viewDir(0,0,-1); Gui::Document* doc = Application::Instance->activeDocument(); if (doc) { View3DInventor* mdi = qobject_cast(doc->getActiveView()); if (mdi) { View3DInventorViewer* viewer = mdi->getViewer(); SoCamera* camera = viewer->getSoRenderManager()->getCamera(); if (camera) { SbVec3f up(0,1,0), dir(0,0,-1); camera->orientation.getValue().multVec(dir, dir); viewDir.Set(dir[0],dir[1],dir[2]); camera->orientation.getValue().multVec(up, up); upDir.Set(up[0],up[1],up[2]); } style = viewer->navigationStyle()->getTypeId(); } } align->setMinPoints(1); align->startAlignment(style); align->setViewingDirections(viewDir,upDir, viewDir,upDir); Gui::Selection().clearSelection(); } bool StdCmdAlignment::isActive(void) { if (ManualAlignment::hasInstance()) return false; return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 2; } //=========================================================================== // Std_Edit //=========================================================================== DEF_STD_CMD_A(StdCmdEdit) StdCmdEdit::StdCmdEdit() : Command("Std_Edit") { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Toggle &Edit mode"); sToolTipText = QT_TR_NOOP("Toggles the selected object's edit mode"); sWhatsThis = "Std_Edit"; sStatusTip = QT_TR_NOOP("Activates or Deactivates the selected object's edit mode"); sAccel = ""; #if QT_VERSION >= 0x040200 sPixmap = "edit-edit"; #endif eType = ForEdit; } void StdCmdEdit::activated(int iMsg) { Q_UNUSED(iMsg); Gui::MDIView* view = Gui::getMainWindow()->activeWindow(); if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { Gui::View3DInventorViewer* viewer = static_cast(view)->getViewer(); if (viewer->isEditingViewProvider()) { doCommand(Command::Gui,"Gui.activeDocument().resetEdit()"); } else { if (Selection().getCompleteSelection().size() > 0) { SelectionSingleton::SelObj obj = Selection().getCompleteSelection()[0]; doCommand(Command::Gui,"Gui.activeDocument().setEdit(\"%s\",0)",obj.FeatName); } } } } bool StdCmdEdit::isActive(void) { return (Selection().getCompleteSelection().size() > 0) || (Gui::Control().activeDialog() != 0); } //====================================================================== // StdCmdExpression //=========================================================================== class StdCmdExpression : public Gui::Command { public: StdCmdExpression() : Command("Std_Expressions") , pcActionCopyAll(nullptr) , pcActionCopySel(nullptr) , pcActionCopyActive(nullptr) , pcActionPaste(nullptr) { sGroup = QT_TR_NOOP("Edit"); sMenuText = QT_TR_NOOP("Expression actions"); sToolTipText = QT_TR_NOOP("Expression actions"); sWhatsThis = "Std_Expressions"; sStatusTip = QT_TR_NOOP("Expression actions"); eType = ForEdit; } virtual const char* className() const {return "StdCmdExpression";} protected: virtual void activated(int iMsg) { std::map > objs; switch(iMsg) { case 0: for(auto &sel : Selection().getCompleteSelection()) objs[sel.pObject->getDocument()].insert(sel.pObject); break; case 1: if(App::GetApplication().getActiveDocument()) { auto doc = App::GetApplication().getActiveDocument(); auto array = doc->getObjects(); auto &set = objs[doc]; set.insert(array.begin(),array.end()); } break; case 2: for(auto doc : App::GetApplication().getDocuments()) { auto &set = objs[doc]; auto array = doc->getObjects(); set.insert(array.begin(),array.end()); } break; case 3: pasteExpressions(); break; } copyExpressions(objs); } virtual Gui::Action * createAction(void) { ActionGroup* pcAction = new ActionGroup(this, getMainWindow()); pcAction->setDropDownMenu(true); applyCommandData(this->className(), pcAction); pcActionCopySel = pcAction->addAction(QObject::tr("Copy selected")); pcActionCopyActive = pcAction->addAction(QObject::tr("Copy active document")); pcActionCopyAll = pcAction->addAction(QObject::tr("Copy all documents")); pcActionPaste = pcAction->addAction(QObject::tr("Paste")); return pcAction; } void copyExpressions(const std::map > &objs) { std::ostringstream ss; std::vector props; for(auto &v : objs) { for(auto obj : v.second) { props.clear(); obj->getPropertyList(props); for(auto prop : props) { auto p = dynamic_cast(prop); if(!p) continue; for(auto &v : p->getExpressions()) { ss << "##@@ " << v.first.toString() << ' ' << obj->getFullName() << '.' << p->getName() << " (" << obj->Label.getValue() << ')' << std::endl; ss << "##@@"; if(v.second->comment.size()) { if(v.second->comment[0] == '&' || v.second->comment.find('\n') != std::string::npos || v.second->comment.find('\r') != std::string::npos) { std::string comment = v.second->comment; boost::replace_all(comment,"&","&"); boost::replace_all(comment,"\n"," "); boost::replace_all(comment,"\r"," "); ss << '&' << comment; }else ss << v.second->comment; } ss << std::endl << v.second->toString(true) << std::endl << std::endl; } } } } QApplication::clipboard()->setText(QString::fromUtf8(ss.str().c_str())); } void pasteExpressions() { std::map > > exprs; bool failed = false; std::string txt = QApplication::clipboard()->text().toUtf8().constData(); const char *tstart = txt.c_str(); const char *tend = tstart + txt.size(); static boost::regex rule("^##@@ ([^ ]+) (\\w+)#(\\w+)\\.(\\w+) [^\n]+\n##@@([^\n]*)\n"); boost::cmatch m; if(!boost::regex_search(tstart,m,rule)) { FC_WARN("No expression header found"); return; } boost::cmatch m2; bool found = true; for(;found;m=m2) { found = boost::regex_search(m[0].second,tend,m2,rule); auto pathName = m.str(1); auto docName = m.str(2); auto objName = m.str(3); auto propName = m.str(4); auto comment = m.str(5); App::Document *doc = App::GetApplication().getDocument(docName.c_str()); if(!doc) { FC_WARN("Cannot find document '" << docName << "'"); continue; } auto obj = doc->getObject(objName.c_str()); if(!obj) { FC_WARN("Cannot find object '" << docName << '#' << objName << "'"); continue; } auto prop = dynamic_cast( obj->getPropertyByName(propName.c_str())); if(!prop) { FC_WARN("Invalid property '" << docName << '#' << objName << '.' << propName << "'"); continue; } size_t len = (found?m2[0].first:tend) - m[0].second; try { App::ExpressionPtr expr(App::Expression::parse(obj,std::string(m[0].second,len))); if(expr && comment.size()) { if(comment[0] == '&') { expr->comment = comment.c_str()+1; boost::replace_all(expr->comment,"&","&"); boost::replace_all(expr->comment," ","\n"); boost::replace_all(expr->comment," ","\r"); } else expr->comment = comment; } exprs[doc][prop][App::ObjectIdentifier::parse(obj,pathName)] = std::move(expr); } catch(Base::Exception &e) { FC_ERR(e.what() << std::endl << m[0].str()); failed = true; } } if(failed) { QMessageBox::critical(getMainWindow(), QObject::tr("Expression error"), QObject::tr("Failed to parse some of the expressions.\n" "Please check the Report View for more details.")); return; } openCommand(QT_TRANSLATE_NOOP("Command", "Paste expressions")); try { for(auto &v : exprs) { for(auto &v2 : v.second) { auto &expressions = v2.second; auto old = v2.first->getExpressions(); for(auto it=expressions.begin(),itNext=it;it!=expressions.end();it=itNext) { ++itNext; auto iter = old.find(it->first); if(iter != old.end() && it->second->isSame(*iter->second)) expressions.erase(it); } if(expressions.size()) v2.first->setExpressions(std::move(expressions)); } } commitCommand(); } catch (const Base::Exception& e) { abortCommand(); QMessageBox::critical(getMainWindow(), QObject::tr("Failed to paste expressions"), QString::fromLatin1(e.what())); e.ReportException(); } } bool isActive() { if(!App::GetApplication().getActiveDocument()) { pcActionCopyAll->setEnabled(false); pcActionCopySel->setEnabled(false); pcActionCopyActive->setEnabled(false); pcActionPaste->setEnabled(false); return true; } pcActionCopyActive->setEnabled(true); pcActionCopyAll->setEnabled(true); pcActionCopySel->setEnabled(Selection().hasSelection()); pcActionPaste->setEnabled( QApplication::clipboard()->text().startsWith(QLatin1String("##@@ "))); return true; } QAction *pcActionCopyAll; QAction *pcActionCopySel; QAction *pcActionCopyActive; QAction *pcActionPaste; }; namespace Gui { void CreateDocCommands(void) { CommandManager &rcCmdMgr = Application::Instance->commandManager(); rcCmdMgr.addCommand(new StdCmdNew()); rcCmdMgr.addCommand(new StdCmdOpen()); rcCmdMgr.addCommand(new StdCmdImport()); rcCmdMgr.addCommand(new StdCmdExport()); rcCmdMgr.addCommand(new StdCmdMergeProjects()); rcCmdMgr.addCommand(new StdCmdDependencyGraph()); rcCmdMgr.addCommand(new StdCmdSave()); rcCmdMgr.addCommand(new StdCmdSaveAs()); rcCmdMgr.addCommand(new StdCmdSaveCopy()); rcCmdMgr.addCommand(new StdCmdSaveAll()); rcCmdMgr.addCommand(new StdCmdRevert()); rcCmdMgr.addCommand(new StdCmdProjectInfo()); rcCmdMgr.addCommand(new StdCmdProjectUtil()); rcCmdMgr.addCommand(new StdCmdUndo()); rcCmdMgr.addCommand(new StdCmdRedo()); rcCmdMgr.addCommand(new StdCmdPrint()); rcCmdMgr.addCommand(new StdCmdPrintPreview()); rcCmdMgr.addCommand(new StdCmdPrintPdf()); rcCmdMgr.addCommand(new StdCmdQuit()); rcCmdMgr.addCommand(new StdCmdCut()); rcCmdMgr.addCommand(new StdCmdCopy()); rcCmdMgr.addCommand(new StdCmdPaste()); rcCmdMgr.addCommand(new StdCmdDuplicateSelection()); rcCmdMgr.addCommand(new StdCmdSelectAll()); rcCmdMgr.addCommand(new StdCmdDelete()); rcCmdMgr.addCommand(new StdCmdRefresh()); rcCmdMgr.addCommand(new StdCmdTransform()); rcCmdMgr.addCommand(new StdCmdPlacement()); rcCmdMgr.addCommand(new StdCmdTransformManip()); rcCmdMgr.addCommand(new StdCmdAlignment()); rcCmdMgr.addCommand(new StdCmdEdit()); rcCmdMgr.addCommand(new StdCmdExpression()); } } // namespace Gui