FreeCAD

Форк
0
/
CommandDoc.cpp 
2013 строк · 73.4 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25
#ifndef _PreComp_
26
# include <Inventor/nodes/SoCamera.h>
27
# include <QApplication>
28
# include <QClipboard>
29
# include <QDateTime>
30
# include <QMessageBox>
31
# include <QTextStream>
32
# include <QTreeWidgetItem>
33
#endif
34

35
#include <boost/regex.hpp>
36
#include <boost/algorithm/string/replace.hpp>
37

38
#include <App/AutoTransaction.h>
39
#include <App/Document.h>
40
#include <App/DocumentObject.h>
41
#include <App/Expression.h>
42
#include <App/GeoFeature.h>
43
#include <Base/Exception.h>
44
#include <Base/FileInfo.h>
45
#include <Base/Stream.h>
46
#include <Base/Tools.h>
47

48
#include "Action.h"
49
#include "Application.h"
50
#include "BitmapFactory.h"
51
#include "Command.h"
52
#include "Control.h"
53
#include "DockWindowManager.h"
54
#include "FileDialog.h"
55
#include "MainWindow.h"
56
#include "Selection.h"
57
#include "DlgObjectSelection.h"
58
#include "DlgProjectInformationImp.h"
59
#include "DlgProjectUtility.h"
60
#include "GraphvizView.h"
61
#include "ManualAlignment.h"
62
#include "MergeDocuments.h"
63
#include "NavigationStyle.h"
64
#include "Placement.h"
65
#include "Transform.h"
66
#include "View3DInventor.h"
67
#include "View3DInventorViewer.h"
68
#include "ViewProvider.h"
69
#include "WaitCursor.h"
70

71
FC_LOG_LEVEL_INIT("Command", false)
72

73
using namespace Gui;
74

75

76
//===========================================================================
77
// Std_Open
78
//===========================================================================
79

80
DEF_STD_CMD(StdCmdOpen)
81

82
StdCmdOpen::StdCmdOpen()
83
  : Command("Std_Open")
84
{
85
    // setting the
86
    sGroup        = "File";
87
    sMenuText     = QT_TR_NOOP("&Open...");
88
    sToolTipText  = QT_TR_NOOP("Open a document or import files");
89
    sWhatsThis    = "Std_Open";
90
    sStatusTip    = QT_TR_NOOP("Open a document or import files");
91
    sPixmap       = "document-open";
92
    sAccel        = keySequenceToAccel(QKeySequence::Open);
93
    eType         = NoTransaction;
94
}
95

96
void StdCmdOpen::activated(int iMsg)
97
{
98
    Q_UNUSED(iMsg);
99

100
    // fill the list of registered endings
101
    QString formatList;
102
    const char* supported = QT_TR_NOOP("Supported formats");
103
    const char* allFiles = QT_TR_NOOP("All files (*.*)");
104
    formatList = QObject::tr(supported);
105
    formatList += QLatin1String(" (");
106

107
    std::vector<std::string> filetypes = App::GetApplication().getImportTypes();
108
    std::vector<std::string>::iterator it;
109
    // Make sure FCStd is the very first fileformat
110
    it = std::find(filetypes.begin(), filetypes.end(), "FCStd");
111
    if (it != filetypes.end()) {
112
        filetypes.erase(it);
113
        filetypes.insert(filetypes.begin(), "FCStd");
114
    }
115
    for (it=filetypes.begin();it != filetypes.end();++it) {
116
        formatList += QLatin1String(" *.");
117
        formatList += QLatin1String(it->c_str());
118
    }
119

120
    formatList += QLatin1String(");;");
121

122
    std::map<std::string, std::string> FilterList = App::GetApplication().getImportFilters();
123
    std::map<std::string, std::string>::iterator jt;
124
    // Make sure the format name for FCStd is the very first in the list
125
    for (jt=FilterList.begin();jt != FilterList.end();++jt) {
126
        if (jt->first.find("*.FCStd") != std::string::npos) {
127
            formatList += QLatin1String(jt->first.c_str());
128
            formatList += QLatin1String(";;");
129
            FilterList.erase(jt);
130
            break;
131
        }
132
    }
133
    for (jt=FilterList.begin();jt != FilterList.end();++jt) {
134
        formatList += QLatin1String(jt->first.c_str());
135
        formatList += QLatin1String(";;");
136
    }
137
    formatList += QObject::tr(allFiles);
138

139
    QString selectedFilter;
140
    QStringList fileList = FileDialog::getOpenFileNames(getMainWindow(),
141
        QObject::tr("Open document"), QString(), formatList, &selectedFilter);
142
    if (fileList.isEmpty())
143
        return;
144

145
    // load the files with the associated modules
146
    SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter);
147
    if (dict.isEmpty()) {
148
        QMessageBox::critical(getMainWindow(),
149
            qApp->translate("StdCmdOpen", "Cannot open file"),
150
            qApp->translate("StdCmdOpen", "Loading the file %1 is not supported").arg(fileList.front()));
151
    }
152
    else {
153
        for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
154

155
            // Set flag indicating that this load/restore has been initiated by the user (not by a macro)
156
            getGuiApplication()->setStatus(Gui::Application::UserInitiatedOpenDocument, true);
157

158
            getGuiApplication()->open(it.key().toUtf8(), it.value().toLatin1());
159

160
            getGuiApplication()->setStatus(Gui::Application::UserInitiatedOpenDocument, false);
161

162
            App::Document *doc = App::GetApplication().getActiveDocument();
163

164
            if(doc && doc->testStatus(App::Document::PartialRestore)) {
165
                QMessageBox::critical(getMainWindow(), QObject::tr("Error"),
166
                                      QObject::tr("There were errors while loading the file. Some data might have been modified or not recovered at all. Look in the report view for more specific information about the objects involved."));
167
            }
168

169
            if(doc && doc->testStatus(App::Document::RestoreError)) {
170
                QMessageBox::critical(getMainWindow(), QObject::tr("Error"),
171
                                      QObject::tr("There were serious errors while loading the file. Some data might have been modified or not recovered at all. Saving the project will most likely result in loss of data."));
172
            }
173
        }
174
    }
175
}
176

177
//===========================================================================
178
// Std_Import
179
//===========================================================================
180

181
DEF_STD_CMD_A(StdCmdImport)
182

183
StdCmdImport::StdCmdImport()
184
  : Command("Std_Import")
185
{
186
    // setting the
187
    sGroup        = "File";
188
    sMenuText     = QT_TR_NOOP("&Import...");
189
    sToolTipText  = QT_TR_NOOP("Import a file in the active document");
190
    sWhatsThis    = "Std_Import";
191
    sStatusTip    = QT_TR_NOOP("Import a file in the active document");
192
    sPixmap       = "Std_Import";
193
    sAccel        = "Ctrl+I";
194
}
195

196
void StdCmdImport::activated(int iMsg)
197
{
198
    Q_UNUSED(iMsg);
199

200
    // fill the list of registered endings
201
    QString formatList;
202
    const char* supported = QT_TR_NOOP("Supported formats");
203
    const char* allFiles = QT_TR_NOOP("All files (*.*)");
204
    formatList = QObject::tr(supported);
205
    formatList += QLatin1String(" (");
206

207
    std::vector<std::string> filetypes = App::GetApplication().getImportTypes();
208
    std::vector<std::string>::const_iterator it;
209
    for (it=filetypes.begin();it != filetypes.end();++it) {
210
        if (*it != "FCStd") {
211
            // ignore the project file format
212
            formatList += QLatin1String(" *.");
213
            formatList += QLatin1String(it->c_str());
214
        }
215
    }
216

217
    formatList += QLatin1String(");;");
218

219
    std::map<std::string, std::string> FilterList = App::GetApplication().getImportFilters();
220
    std::map<std::string, std::string>::const_iterator jt;
221
    for (jt=FilterList.begin();jt != FilterList.end();++jt) {
222
        // ignore the project file format
223
        if (jt->first.find("(*.FCStd)") == std::string::npos) {
224
            formatList += QLatin1String(jt->first.c_str());
225
            formatList += QLatin1String(";;");
226
        }
227
    }
228
    formatList += QObject::tr(allFiles);
229

230
    Base::Reference<ParameterGrp> hPath = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
231
                               ->GetGroup("Preferences")->GetGroup("General");
232
    QString selectedFilter = QString::fromStdString(hPath->GetASCII("FileImportFilter"));
233
    QStringList fileList = FileDialog::getOpenFileNames(getMainWindow(),
234
        QObject::tr("Import file"), QString(), formatList, &selectedFilter);
235
    if (!fileList.isEmpty()) {
236
        hPath->SetASCII("FileImportFilter", selectedFilter.toLatin1().constData());
237
        SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter);
238

239
        bool emptyDoc = (getActiveGuiDocument()->getDocument()->countObjects() == 0);
240
        // load the files with the associated modules
241
        for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
242
            getGuiApplication()->importFrom(it.key().toUtf8(),
243
                getActiveGuiDocument()->getDocument()->getName(),
244
                it.value().toLatin1());
245
        }
246

247
        if (emptyDoc) {
248
            // only do a view fit if the document was empty before. See also parameter 'AutoFitToView' in importFrom()
249
            std::list<Gui::MDIView*> views = getActiveGuiDocument()->getMDIViewsOfType(Gui::View3DInventor::getClassTypeId());
250
            for (const auto & view : views) {
251
                view->viewAll();
252
            }
253
        }
254
    }
255
}
256

257
bool StdCmdImport::isActive()
258
{
259
    return (getActiveGuiDocument() ? true : false);
260
}
261

262

263
//===========================================================================
264
// Std_Export
265
//===========================================================================
266

267
DEF_STD_CMD_A(StdCmdExport)
268

269
StdCmdExport::StdCmdExport()
270
  : Command("Std_Export")
271
{
272
    // setting the
273
    sGroup        = "File";
274
    sMenuText     = QT_TR_NOOP("&Export...");
275
    sToolTipText  = QT_TR_NOOP("Export an object in the active document");
276
    sWhatsThis    = "Std_Export";
277
    sStatusTip    = QT_TR_NOOP("Export an object in the active document");
278
    //sPixmap       = "Open";
279
    sAccel        = "Ctrl+E";
280
    sPixmap       = "Std_Export";
281
    eType         = 0;
282
}
283

284
/**
285
Create a default filename from a user-specified format string
286

287
Format options are:
288
%F - the basename of the .FCStd file (or the label, if it is not saved yet)
289
%Lx - the label of the selected object(s), separated by character 'x'
290
%Px - the label of the selected object(s) and their first parent, separated by character 'x'
291
%U - the date and time, in UTC, ISO 8601
292
%D - the date and time, in local timezone, ISO 8601
293
Any other characters are treated literally, though if the filename is illegal
294
it will be changed on saving.
295

296
The format string is stored in two user preferences (not currently exposed in the GUI):
297
* BaseApp/Preferences/General/ExportDefaultFilenameSingle
298
* BaseApp/Preferences/General/ExportDefaultFilenameMultiple
299
*/
300
QString createDefaultExportBasename()
301
{
302
    QString defaultFilename;
303

304
    auto selection = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId());
305
    QString exportFormatString;
306
    if (selection.size() == 1) {
307
        exportFormatString = QString::fromStdString (App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
308
            GetASCII("ExportDefaultFilenameSingle", "%F-%P-"));
309
    }
310
    else {
311
        exportFormatString = QString::fromStdString (App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
312
            GetASCII("ExportDefaultFilenameMultiple", "%F"));
313
    }
314

315
    // For code simplicity, pull all values we might need
316

317
    // %F - the basename of the.FCStd file(or the label, if it is not saved yet)
318
    QString docFilename = QString::fromUtf8(App::GetApplication().getActiveDocument()->getFileName());
319
    QFileInfo fi(docFilename);
320
    QString fcstdBasename = fi.completeBaseName();
321
    if (fcstdBasename.isEmpty())
322
        fcstdBasename = QString::fromStdString(App::GetApplication().getActiveDocument()->Label.getStrValue());
323

324
    // %L - the label of the selected object(s)
325
    QStringList objectLabels;
326
    for (const auto& object : selection)
327
        objectLabels.push_back(QString::fromStdString(object->Label.getStrValue()));
328

329
    // %P - the label of the selected objects and their first parent
330
    QStringList parentLabels;
331
    for (const auto& object : selection) {
332
        auto parents = object->getParents();
333
        QString firstParent;
334
        if (!parents.empty())
335
            firstParent = QString::fromStdString(parents.front().first->Label.getStrValue());
336
        parentLabels.append(firstParent + QString::fromStdString(object->Label.getStrValue()));
337
    }
338

339
    // %U - the date and time, in UTC, ISO 8601
340
    QDateTime utc = QDateTime(QDateTime::currentDateTimeUtc());
341
    QString utcISO8601 = utc.toString(Qt::ISODate);
342

343
    // %D - the date and time, in local timezone, ISO 8601
344
    QDateTime local = utc.toLocalTime();
345
    QString localISO8601 = local.toString(Qt::ISODate);
346

347
    // Parse the format string one character at a time:
348
    for (int i = 0; i < exportFormatString.size(); ++i) {
349
        auto c = exportFormatString.at(i);
350
        if (c != QLatin1Char('%')) {
351
            // Anything that's not a format start character is just a literal
352
            defaultFilename.append(c);
353
        }
354
        else {
355
            // The format start character now requires us to look at at least the next single
356
            // character (if there isn't another character, the % just gets eaten)
357
            if (i < exportFormatString.size() - 1) {
358
                ++i;
359
                auto formatChar = exportFormatString.at(i);
360
                QChar separatorChar = QLatin1Char('-');
361
                // If this format type requires an additional char, read that now (or default to
362
                // '-' if the format string ends)
363
                if (formatChar == QLatin1Char('L') ||
364
                    formatChar == QLatin1Char('P')) {
365
                    if (i < exportFormatString.size() - 1) {
366
                        ++i;
367
                        separatorChar = exportFormatString.at(i);
368
                    }
369
                }
370

371
                // Handle our format characters:
372
                if (formatChar == QLatin1Char('F')) {
373
                    defaultFilename.append(fcstdBasename);
374
                }
375
                else if (formatChar == QLatin1Char('L')) {
376
                    defaultFilename.append(objectLabels.join(separatorChar));
377
                }
378
                else if (formatChar == QLatin1Char('P')) {
379
                    defaultFilename.append(parentLabels.join(separatorChar));
380
                }
381
                else if (formatChar == QLatin1Char('U')) {
382
                    defaultFilename.append(utcISO8601);
383
                }
384
                else if (formatChar == QLatin1Char('D')) {
385
                    defaultFilename.append(localISO8601);
386
                }
387
                else {
388
                    FC_WARN("When parsing default export filename format string, %"
389
                        << QString(formatChar).toStdString()
390
                        << " is not a known format string.");
391
                }
392
            }
393
        }
394
    }
395

396
    // Finally, clean the string so it's valid for all operating systems:
397
    QString invalidCharacters = QLatin1String("/\\?%*:|\"<>");
398
    for (const auto &c : invalidCharacters)
399
        defaultFilename.replace(c,QLatin1String("_"));
400

401
    return defaultFilename;
402
}
403

404
void StdCmdExport::activated(int iMsg)
405
{
406
    Q_UNUSED(iMsg);
407

408
    static QString lastExportFullPath = QString();
409
    static bool lastExportUsedGeneratedFilename = true;
410
    static QString lastExportFilterUsed = QString();
411

412
    auto selection = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId());
413
    if (selection.empty()) {
414
        QMessageBox::warning(Gui::getMainWindow(),
415
            QCoreApplication::translate("StdCmdExport", "No selection"),
416
            QCoreApplication::translate("StdCmdExport", "Select the objects to export before choosing Export."));
417
        return;
418
    }
419

420
    // fill the list of registered suffixes
421
    QStringList filterList;
422
    std::map<std::string, std::string> filterMap = App::GetApplication().getExportFilters();
423
    for (const auto &filter : filterMap) {
424
        // ignore the project file format
425
        if (filter.first.find("(*.FCStd)") == std::string::npos)
426
            filterList << QString::fromStdString(filter.first);
427
    }
428
    QString formatList = filterList.join(QLatin1String(";;"));
429
    Base::Reference<ParameterGrp> hPath =
430
        App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General");
431
    QString selectedFilter = QString::fromStdString(hPath->GetASCII("FileExportFilter"));
432
    if (!lastExportFilterUsed.isEmpty())
433
        selectedFilter = lastExportFilterUsed;
434

435
    // Create a default filename for the export
436
    // * If this is the first export this session default, generate a new default.
437
    // * If this is a repeated export during the same session:
438
    //     * If the user accepted the default filename last time, regenerate a new
439
    //       default, potentially updating the object label.
440
    //     * If not, default to their previously-set export filename.
441
    QString defaultFilename = lastExportFullPath;
442

443
    bool filenameWasGenerated = false;
444
    // We want to generate a new default name in two cases:
445
    if (defaultFilename.isEmpty() || lastExportUsedGeneratedFilename) {
446
        // First, get the name and path of the current .FCStd file, if there is one:
447
        QString docFilename = QString::fromUtf8(
448
            App::GetApplication().getActiveDocument()->getFileName());
449

450
        // Find the default location for our exported file. Three possibilities:
451
        QString defaultExportPath;
452
        if (!lastExportFullPath.isEmpty()) {
453
            QFileInfo fi(lastExportFullPath);
454
            defaultExportPath = fi.path();
455
        }
456
        else if (!docFilename.isEmpty()) {
457
            QFileInfo fi(docFilename);
458
            defaultExportPath = fi.path();
459
        }
460
        else {
461
            defaultExportPath = Gui::FileDialog::getWorkingDirectory();
462
        }
463

464
        if (lastExportUsedGeneratedFilename /*<- static, true on first call*/ ) {
465
            defaultFilename = defaultExportPath + QLatin1Char('/') + createDefaultExportBasename();
466

467
            // Append the last extension used, if there is one.
468
            if (!lastExportFullPath.isEmpty()) {
469
                QFileInfo lastExportFile(lastExportFullPath);
470
                if (!lastExportFile.suffix().isEmpty())
471
                    defaultFilename += QLatin1String(".") + lastExportFile.suffix();
472
            }
473
            filenameWasGenerated = true;
474
        }
475
    }
476

477
    // Launch the file selection modal dialog
478
    QString fileName = FileDialog::getSaveFileName(getMainWindow(),
479
        QObject::tr("Export file"), defaultFilename, formatList, &selectedFilter);
480
    if (!fileName.isEmpty()) {
481
        hPath->SetASCII("FileExportFilter", selectedFilter.toLatin1().constData());
482
        lastExportFilterUsed = selectedFilter; // So we can select the same one next time
483
        SelectModule::Dict dict = SelectModule::exportHandler(fileName, selectedFilter);
484
        // export the files with the associated modules
485
        for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
486
            getGuiApplication()->exportTo(it.key().toUtf8(),
487
                getActiveGuiDocument()->getDocument()->getName(),
488
                it.value().toLatin1());
489
        }
490

491
        // Keep a record of if the user used our suggested generated filename. If they
492
        // did, next time we can recreate it, which will update the object label if
493
        // there is one.
494
        QFileInfo defaultExportFI(defaultFilename);
495
        QFileInfo thisExportFI(fileName);
496
        if (filenameWasGenerated &&
497
            thisExportFI.completeBaseName() == defaultExportFI.completeBaseName())
498
            lastExportUsedGeneratedFilename = true;
499
        else
500
            lastExportUsedGeneratedFilename = false;
501
        lastExportFullPath = fileName;
502
    }
503
}
504

505
bool StdCmdExport::isActive()
506
{
507
    return (getActiveGuiDocument() ? true : false);
508
}
509

510
//===========================================================================
511
// Std_MergeProjects
512
//===========================================================================
513

514
DEF_STD_CMD_A(StdCmdMergeProjects)
515

516
StdCmdMergeProjects::StdCmdMergeProjects()
517
  : Command("Std_MergeProjects")
518
{
519
    sAppModule    = "File";
520
    sGroup        = "File";
521
    sMenuText     = QT_TR_NOOP("Merge document...");
522
    sToolTipText  = QT_TR_NOOP("Merge document");
523
    sWhatsThis    = "Std_MergeProjects";
524
    sStatusTip    = QT_TR_NOOP("Merge document");
525
    sPixmap       = "Std_MergeProjects";
526
}
527

528
void StdCmdMergeProjects::activated(int iMsg)
529
{
530
    Q_UNUSED(iMsg);
531

532
    QString exe = qApp->applicationName();
533
    QString project = FileDialog::getOpenFileName(Gui::getMainWindow(),
534
        QString::fromUtf8(QT_TR_NOOP("Merge document")), FileDialog::getWorkingDirectory(),
535
        QString::fromUtf8(QT_TR_NOOP("%1 document (*.FCStd)")).arg(exe));
536
    if (!project.isEmpty()) {
537
        FileDialog::setWorkingDirectory(project);
538
        App::Document* doc = App::GetApplication().getActiveDocument();
539
        QFileInfo info(QString::fromUtf8(doc->FileName.getValue()));
540
        QFileInfo proj(project);
541
        if (proj == info) {
542
            QMessageBox::critical(Gui::getMainWindow(),
543
                QString::fromUtf8(QT_TR_NOOP("Merge document")),
544
                QString::fromUtf8(QT_TR_NOOP("Cannot merge document with itself.")));
545
            return;
546
        }
547

548
        doc->openTransaction("Merge document");
549
        Base::FileInfo fi((const char*)project.toUtf8());
550
        Base::ifstream str(fi, std::ios::in | std::ios::binary);
551
        MergeDocuments md(doc);
552
        md.importObjects(str);
553
        str.close();
554
        doc->commitTransaction();
555
    }
556
}
557

558
bool StdCmdMergeProjects::isActive()
559
{
560
    return this->hasActiveDocument();
561
}
562

563
//===========================================================================
564
// Std_DependencyGraph
565
//===========================================================================
566

567
DEF_STD_CMD_A(StdCmdDependencyGraph)
568

569
StdCmdDependencyGraph::StdCmdDependencyGraph()
570
  : Command("Std_DependencyGraph")
571
{
572
    // setting the
573
    sGroup        = "Tools";
574
    sMenuText     = QT_TR_NOOP("Dependency graph...");
575
    sToolTipText  = QT_TR_NOOP("Show the dependency graph of the objects in the active document");
576
    sStatusTip    = QT_TR_NOOP("Show the dependency graph of the objects in the active document");
577
    sWhatsThis    = "Std_DependencyGraph";
578
    eType         = 0;
579
    sPixmap       = "Std_DependencyGraph";
580
}
581

582
void StdCmdDependencyGraph::activated(int iMsg)
583
{
584
    Q_UNUSED(iMsg);
585
    App::Document* doc = App::GetApplication().getActiveDocument();
586
    auto view = new Gui::GraphvizView(*doc);
587
    view->setWindowTitle(qApp->translate("Std_DependencyGraph","Dependency graph"));
588
    getMainWindow()->addWindow(view);
589
}
590

591
bool StdCmdDependencyGraph::isActive()
592
{
593
    return (getActiveGuiDocument() ? true : false);
594
}
595

596
//===========================================================================
597
// Std_ExportDependencyGraph
598
//===========================================================================
599

600
DEF_STD_CMD_A(StdCmdExportDependencyGraph)
601

602
StdCmdExportDependencyGraph::StdCmdExportDependencyGraph()
603
  : Command("Std_ExportDependencyGraph")
604
{
605
    sGroup        = "Tools";
606
    sMenuText     = QT_TR_NOOP("Export dependency graph...");
607
    sToolTipText  = QT_TR_NOOP("Export the dependency graph to a file");
608
    sStatusTip    = QT_TR_NOOP("Export the dependency graph to a file");
609
    sWhatsThis    = "Std_ExportDependencyGraph";
610
    eType         = 0;
611
  //sPixmap       = "Std_ExportDependencyGraph";
612
}
613

614
void StdCmdExportDependencyGraph::activated(int iMsg)
615
{
616
    Q_UNUSED(iMsg);
617
    App::Document* doc = App::GetApplication().getActiveDocument();
618
    QString format = QString::fromLatin1("%1 (*.gv)").arg(Gui::GraphvizView::tr("Graphviz format"));
619
    QString fn = Gui::FileDialog::getSaveFileName(Gui::getMainWindow(), Gui::GraphvizView::tr("Export graph"), QString(), format);
620
    if (!fn.isEmpty()) {
621
        QFile file(fn);
622
        if (file.open(QFile::WriteOnly)) {
623
            std::stringstream str;
624
            doc->exportGraphviz(str);
625
            QByteArray buffer = QByteArray::fromStdString(str.str());
626
            file.write(buffer);
627
            file.close();
628
        }
629
    }
630
}
631

632
bool StdCmdExportDependencyGraph::isActive()
633
{
634
    return (getActiveGuiDocument() ? true : false);
635
}
636

637
//===========================================================================
638
// Std_New
639
//===========================================================================
640

641
DEF_STD_CMD(StdCmdNew)
642

643
StdCmdNew::StdCmdNew()
644
  :Command("Std_New")
645
{
646
    sGroup        = "File";
647
    sMenuText     = QT_TR_NOOP("&New");
648
    sToolTipText  = QT_TR_NOOP("Create a new empty document");
649
    sWhatsThis    = "Std_New";
650
    sStatusTip    = QT_TR_NOOP("Create a new empty document");
651
    sPixmap       = "document-new";
652
    sAccel        = keySequenceToAccel(QKeySequence::New);
653
}
654

655
void StdCmdNew::activated(int iMsg)
656
{
657
    Q_UNUSED(iMsg);
658
    QString cmd;
659
    cmd = QString::fromLatin1("App.newDocument()");
660
    runCommand(Command::Doc,cmd.toUtf8());
661
    doCommand(Command::Gui,"Gui.activeDocument().activeView().viewDefaultOrientation()");
662

663
    ParameterGrp::handle hViewGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
664
    if (hViewGrp->GetBool("ShowAxisCross"))
665
        doCommand(Command::Gui,"Gui.ActiveDocument.ActiveView.setAxisCross(True)");
666
}
667

668
//===========================================================================
669
// Std_Save
670
//===========================================================================
671
DEF_STD_CMD_A(StdCmdSave)
672

673
StdCmdSave::StdCmdSave()
674
  :Command("Std_Save")
675
{
676
  sGroup        = "File";
677
  sMenuText     = QT_TR_NOOP("&Save");
678
  sToolTipText  = QT_TR_NOOP("Save the active document");
679
  sWhatsThis    = "Std_Save";
680
  sStatusTip    = QT_TR_NOOP("Save the active document");
681
  sPixmap       = "document-save";
682
  sAccel        = keySequenceToAccel(QKeySequence::Save);
683
  eType         = 0;
684
}
685

686
void StdCmdSave::activated(int iMsg)
687
{
688
    Q_UNUSED(iMsg);
689
    doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"Save\")");
690
}
691

692
bool StdCmdSave::isActive()
693
{
694
    return getGuiApplication()->sendHasMsgToActiveView("Save");
695
}
696

697
//===========================================================================
698
// Std_SaveAs
699
//===========================================================================
700
DEF_STD_CMD_A(StdCmdSaveAs)
701

702
StdCmdSaveAs::StdCmdSaveAs()
703
  :Command("Std_SaveAs")
704
{
705
  sGroup        = "File";
706
  sMenuText     = QT_TR_NOOP("Save &As...");
707
  sToolTipText  = QT_TR_NOOP("Save the active document under a new file name");
708
  sWhatsThis    = "Std_SaveAs";
709
  sStatusTip    = QT_TR_NOOP("Save the active document under a new file name");
710
  sPixmap       = "document-save-as";
711
  sAccel        = keySequenceToAccel(QKeySequence::SaveAs);
712
  eType         = 0;
713
}
714

715
void StdCmdSaveAs::activated(int iMsg)
716
{
717
    Q_UNUSED(iMsg);
718
    doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"SaveAs\")");
719
}
720

721
bool StdCmdSaveAs::isActive()
722
{
723
    return getGuiApplication()->sendHasMsgToActiveView("SaveAs");
724
}
725

726
//===========================================================================
727
// Std_SaveCopy
728
//===========================================================================
729
DEF_STD_CMD_A(StdCmdSaveCopy)
730

731
StdCmdSaveCopy::StdCmdSaveCopy()
732
  :Command("Std_SaveCopy")
733
{
734
  sGroup        = "File";
735
  sMenuText     = QT_TR_NOOP("Save a &Copy...");
736
  sToolTipText  = QT_TR_NOOP("Save a copy of the active document under a new file name");
737
  sWhatsThis    = "Std_SaveCopy";
738
  sStatusTip    = QT_TR_NOOP("Save a copy of the active document under a new file name");
739
  sPixmap       = "Std_SaveCopy";
740
}
741

742
void StdCmdSaveCopy::activated(int iMsg)
743
{
744
    Q_UNUSED(iMsg);
745
    doCommand(Command::Gui,"Gui.SendMsgToActiveView(\"SaveCopy\")");
746
}
747

748
bool StdCmdSaveCopy::isActive()
749
{
750
  return ( getActiveGuiDocument() ? true : false );
751
}
752

753
//===========================================================================
754
// Std_SaveAll
755
//===========================================================================
756
DEF_STD_CMD_A(StdCmdSaveAll)
757

758
StdCmdSaveAll::StdCmdSaveAll()
759
  :Command("Std_SaveAll")
760
{
761
  sGroup        = "File";
762
  sMenuText     = QT_TR_NOOP("Save All");
763
  sToolTipText  = QT_TR_NOOP("Save all opened document");
764
  sWhatsThis    = "Std_SaveAll";
765
  sStatusTip    = QT_TR_NOOP("Save all opened document");
766
  sPixmap       = "Std_SaveAll";
767
}
768

769
void StdCmdSaveAll::activated(int iMsg)
770
{
771
    Q_UNUSED(iMsg);
772
    Gui::Document::saveAll();
773
}
774

775
bool StdCmdSaveAll::isActive()
776
{
777
  return ( getActiveGuiDocument() ? true : false );
778
}
779

780

781
//===========================================================================
782
// Std_Revert
783
//===========================================================================
784
DEF_STD_CMD_A(StdCmdRevert)
785

786
StdCmdRevert::StdCmdRevert()
787
  :Command("Std_Revert")
788
{
789
    sGroup        = "File";
790
    sMenuText     = QT_TR_NOOP("Revert");
791
    sToolTipText  = QT_TR_NOOP("Reverts to the saved version of this file");
792
    sWhatsThis    = "Std_Revert";
793
    sStatusTip    = QT_TR_NOOP("Reverts to the saved version of this file");
794
    sPixmap       = "Std_Revert";
795
    eType         = NoTransaction;
796
}
797

798
void StdCmdRevert::activated(int iMsg)
799
{
800
    Q_UNUSED(iMsg);
801
    QMessageBox msgBox(Gui::getMainWindow());
802
    msgBox.setIcon(QMessageBox::Question);
803
    msgBox.setWindowTitle(qApp->translate("Std_Revert","Revert document"));
804
    msgBox.setText(qApp->translate("Std_Revert","This will discard all the changes since last file save."));
805
    msgBox.setInformativeText(qApp->translate("Std_Revert","Do you want to continue?"));
806
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
807
    msgBox.setDefaultButton(QMessageBox::No);
808
    int ret = msgBox.exec();
809
    if (ret == QMessageBox::Yes)
810
        doCommand(Command::App,"App.ActiveDocument.restore()");
811
}
812

813
bool StdCmdRevert::isActive()
814
{
815
  return ( getActiveGuiDocument() ? true : false );
816
}
817

818
//===========================================================================
819
// Std_ProjectInfo
820
//===========================================================================
821

822
DEF_STD_CMD_A(StdCmdProjectInfo)
823

824
StdCmdProjectInfo::StdCmdProjectInfo()
825
  :Command("Std_ProjectInfo")
826
{
827
  // setting the
828
  sGroup        = "File";
829
  sMenuText     = QT_TR_NOOP("Document i&nformation...");
830
  sToolTipText  = QT_TR_NOOP("Show details of the currently active document");
831
  sWhatsThis    = "Std_ProjectInfo";
832
  sStatusTip    = QT_TR_NOOP("Show details of the currently active document");
833
  sPixmap       = "document-properties";
834
}
835

836
void StdCmdProjectInfo::activated(int iMsg)
837
{
838
    Q_UNUSED(iMsg);
839
    Gui::Dialog::DlgProjectInformationImp dlg(getActiveGuiDocument()->getDocument(), getMainWindow());
840
    dlg.exec();
841
}
842

843
bool StdCmdProjectInfo::isActive()
844
{
845
  return ( getActiveGuiDocument() ? true : false );
846
}
847

848
//===========================================================================
849
// Std_ProjectUtil
850
//===========================================================================
851

852
DEF_STD_CMD_A(StdCmdProjectUtil)
853

854
StdCmdProjectUtil::StdCmdProjectUtil()
855
  :Command("Std_ProjectUtil")
856
{
857
    // setting the
858
    sGroup        = "Tools";
859
    sWhatsThis    = "Std_ProjectUtil";
860
    sMenuText     = QT_TR_NOOP("Document utility...");
861
    sToolTipText  = QT_TR_NOOP("Utility to extract or create document files");
862
    sStatusTip    = QT_TR_NOOP("Utility to extract or create document files");
863
    sPixmap       = "Std_ProjectUtil";
864
}
865

866
void StdCmdProjectUtil::activated(int iMsg)
867
{
868
    Q_UNUSED(iMsg);
869
    Gui::Dialog::DlgProjectUtility dlg(getMainWindow());
870
    dlg.exec();
871
}
872

873
bool StdCmdProjectUtil::isActive()
874
{
875
    return true;
876
}
877

878
//===========================================================================
879
// Std_Print
880
//===========================================================================
881
DEF_STD_CMD_A(StdCmdPrint)
882

883
StdCmdPrint::StdCmdPrint()
884
  :Command("Std_Print")
885
{
886
    sGroup        = "File";
887
    sMenuText     = QT_TR_NOOP("&Print...");
888
    sToolTipText  = QT_TR_NOOP("Print the document");
889
    sWhatsThis    = "Std_Print";
890
    sStatusTip    = QT_TR_NOOP("Print the document");
891
    sPixmap       = "document-print";
892
    sAccel        = keySequenceToAccel(QKeySequence::Print);
893
    eType         = 0;
894
}
895

896
void StdCmdPrint::activated(int iMsg)
897
{
898
    Q_UNUSED(iMsg);
899
    if (getMainWindow()->activeWindow()) {
900
        getMainWindow()->showMessage(QObject::tr("Printing..."));
901
        getMainWindow()->activeWindow()->print();
902
    }
903
}
904

905
bool StdCmdPrint::isActive()
906
{
907
    return getGuiApplication()->sendHasMsgToActiveView("Print");
908
}
909

910
//===========================================================================
911
// Std_PrintPreview
912
//===========================================================================
913
DEF_STD_CMD_A(StdCmdPrintPreview)
914

915
StdCmdPrintPreview::StdCmdPrintPreview()
916
  :Command("Std_PrintPreview")
917
{
918
    sGroup        = "File";
919
    sMenuText     = QT_TR_NOOP("&Print preview...");
920
    sToolTipText  = QT_TR_NOOP("Print the document");
921
    sWhatsThis    = "Std_PrintPreview";
922
    sStatusTip    = QT_TR_NOOP("Print preview");
923
    sPixmap       = "document-print-preview";
924
    eType         = 0;
925
}
926

927
void StdCmdPrintPreview::activated(int iMsg)
928
{
929
    Q_UNUSED(iMsg);
930
    if (getMainWindow()->activeWindow()) {
931
        getMainWindow()->activeWindow()->printPreview();
932
    }
933
}
934

935
bool StdCmdPrintPreview::isActive()
936
{
937
    return getGuiApplication()->sendHasMsgToActiveView("PrintPreview");
938
}
939

940
//===========================================================================
941
// Std_PrintPdf
942
//===========================================================================
943
DEF_STD_CMD_A(StdCmdPrintPdf)
944

945
StdCmdPrintPdf::StdCmdPrintPdf()
946
  :Command("Std_PrintPdf")
947
{
948
    sGroup        = "File";
949
    sMenuText     = QT_TR_NOOP("&Export PDF...");
950
    sToolTipText  = QT_TR_NOOP("Export the document as PDF");
951
    sWhatsThis    = "Std_PrintPdf";
952
    sStatusTip    = QT_TR_NOOP("Export the document as PDF");
953
    sPixmap       = "Std_PrintPdf";
954
    eType         = 0;
955
}
956

957
void StdCmdPrintPdf::activated(int iMsg)
958
{
959
    Q_UNUSED(iMsg);
960
    if (getMainWindow()->activeWindow()) {
961
        getMainWindow()->showMessage(QObject::tr("Exporting PDF..."));
962
        getMainWindow()->activeWindow()->printPdf();
963
    }
964
}
965

966
bool StdCmdPrintPdf::isActive()
967
{
968
    return getGuiApplication()->sendHasMsgToActiveView("PrintPdf");
969
}
970

971
//===========================================================================
972
// Std_Quit
973
//===========================================================================
974

975
DEF_STD_CMD(StdCmdQuit)
976

977
StdCmdQuit::StdCmdQuit()
978
  :Command("Std_Quit")
979
{
980
  sGroup        = "File";
981
  sMenuText     = QT_TR_NOOP("E&xit");
982
  sToolTipText  = QT_TR_NOOP("Quits the application");
983
  sWhatsThis    = "Std_Quit";
984
  sStatusTip    = QT_TR_NOOP("Quits the application");
985
  sPixmap       = "application-exit";
986
  sAccel        = keySequenceToAccel(QKeySequence::Quit);
987
  eType         = NoTransaction;
988
}
989

990
void StdCmdQuit::activated(int iMsg)
991
{
992
    Q_UNUSED(iMsg);
993
    // close the main window and exit the event loop
994
    getMainWindow()->close();
995
}
996

997
//===========================================================================
998
// Std_Undo
999
//===========================================================================
1000

1001
DEF_STD_CMD_AC(StdCmdUndo)
1002

1003
StdCmdUndo::StdCmdUndo()
1004
  :Command("Std_Undo")
1005
{
1006
  sGroup        = "Edit";
1007
  sMenuText     = QT_TR_NOOP("&Undo");
1008
  sToolTipText  = QT_TR_NOOP("Undo exactly one action");
1009
  sWhatsThis    = "Std_Undo";
1010
  sStatusTip    = QT_TR_NOOP("Undo exactly one action");
1011
  sPixmap       = "edit-undo";
1012
  sAccel        = keySequenceToAccel(QKeySequence::Undo);
1013
  eType         = ForEdit|NoTransaction;
1014
}
1015

1016
void StdCmdUndo::activated(int iMsg)
1017
{
1018
    Q_UNUSED(iMsg);
1019
//  Application::Instance->slotUndo();
1020
    getGuiApplication()->sendMsgToActiveView("Undo");
1021
}
1022

1023
bool StdCmdUndo::isActive()
1024
{
1025
  return getGuiApplication()->sendHasMsgToActiveView("Undo");
1026
}
1027

1028
Action * StdCmdUndo::createAction()
1029
{
1030
    Action *pcAction;
1031

1032
    pcAction = new UndoAction(this,getMainWindow());
1033
    pcAction->setShortcut(QString::fromLatin1(getAccel()));
1034
    applyCommandData(this->className(), pcAction);
1035
    if (getPixmap())
1036
        pcAction->setIcon(Gui::BitmapFactory().iconFromTheme(getPixmap()));
1037

1038
    return pcAction;
1039
}
1040

1041
//===========================================================================
1042
// Std_Redo
1043
//===========================================================================
1044

1045
DEF_STD_CMD_AC(StdCmdRedo)
1046

1047
StdCmdRedo::StdCmdRedo()
1048
  :Command("Std_Redo")
1049
{
1050
  sGroup        = "Edit";
1051
  sMenuText     = QT_TR_NOOP("&Redo");
1052
  sToolTipText  = QT_TR_NOOP("Redoes a previously undone action");
1053
  sWhatsThis    = "Std_Redo";
1054
  sStatusTip    = QT_TR_NOOP("Redoes a previously undone action");
1055
  sPixmap       = "edit-redo";
1056
  sAccel        = keySequenceToAccel(QKeySequence::Redo);
1057
  eType         = ForEdit|NoTransaction;
1058
}
1059

1060
void StdCmdRedo::activated(int iMsg)
1061
{
1062
    Q_UNUSED(iMsg);
1063
//  Application::Instance->slotRedo();
1064
    getGuiApplication()->sendMsgToActiveView("Redo");
1065
}
1066

1067
bool StdCmdRedo::isActive()
1068
{
1069
  return getGuiApplication()->sendHasMsgToActiveView("Redo");
1070
}
1071

1072
Action * StdCmdRedo::createAction()
1073
{
1074
    Action *pcAction;
1075

1076
    pcAction = new RedoAction(this,getMainWindow());
1077
    pcAction->setShortcut(QString::fromLatin1(getAccel()));
1078
    applyCommandData(this->className(), pcAction);
1079
    if (getPixmap())
1080
        pcAction->setIcon(Gui::BitmapFactory().iconFromTheme(getPixmap()));
1081

1082
    return pcAction;
1083
}
1084

1085
//===========================================================================
1086
// Std_Cut
1087
//===========================================================================
1088
DEF_STD_CMD_A(StdCmdCut)
1089

1090
StdCmdCut::StdCmdCut()
1091
  : Command("Std_Cut")
1092
{
1093
    sGroup        = "Edit";
1094
    sMenuText     = QT_TR_NOOP("&Cut");
1095
    sToolTipText  = QT_TR_NOOP("Cut out");
1096
    sWhatsThis    = "Std_Cut";
1097
    sStatusTip    = QT_TR_NOOP("Cut out");
1098
    sPixmap       = "edit-cut";
1099
    sAccel        = keySequenceToAccel(QKeySequence::Cut);
1100
}
1101

1102
void StdCmdCut::activated(int iMsg)
1103
{
1104
    Q_UNUSED(iMsg);
1105
    getGuiApplication()->sendMsgToActiveView("Cut");
1106
}
1107

1108
bool StdCmdCut::isActive()
1109
{
1110
    return getGuiApplication()->sendHasMsgToActiveView("Cut");
1111
}
1112

1113
//===========================================================================
1114
// Std_Copy
1115
//===========================================================================
1116
DEF_STD_CMD_A(StdCmdCopy)
1117

1118
StdCmdCopy::StdCmdCopy()
1119
  : Command("Std_Copy")
1120
{
1121
    sGroup        = "Edit";
1122
    sMenuText     = QT_TR_NOOP("C&opy");
1123
    sToolTipText  = QT_TR_NOOP("Copy operation");
1124
    sWhatsThis    = "Std_Copy";
1125
    sStatusTip    = QT_TR_NOOP("Copy operation");
1126
    sPixmap       = "edit-copy";
1127
    sAccel        = keySequenceToAccel(QKeySequence::Copy);
1128
}
1129

1130
void StdCmdCopy::activated(int iMsg)
1131
{
1132
    Q_UNUSED(iMsg);
1133
    bool done = getGuiApplication()->sendMsgToFocusView("Copy");
1134
    if (!done) {
1135
        QMimeData * mimeData = getMainWindow()->createMimeDataFromSelection();
1136
        QClipboard* cb = QApplication::clipboard();
1137
        cb->setMimeData(mimeData);
1138
    }
1139
}
1140

1141
bool StdCmdCopy::isActive()
1142
{
1143
    if (getGuiApplication()->sendHasMsgToFocusView("Copy"))
1144
        return true;
1145
    return Selection().hasSelection();
1146
}
1147

1148
//===========================================================================
1149
// Std_Paste
1150
//===========================================================================
1151
DEF_STD_CMD_A(StdCmdPaste)
1152

1153
StdCmdPaste::StdCmdPaste()
1154
  : Command("Std_Paste")
1155
{
1156
    sGroup        = "Edit";
1157
    sMenuText     = QT_TR_NOOP("&Paste");
1158
    sToolTipText  = QT_TR_NOOP("Paste operation");
1159
    sWhatsThis    = "Std_Paste";
1160
    sStatusTip    = QT_TR_NOOP("Paste operation");
1161
    sPixmap       = "edit-paste";
1162
    sAccel        = keySequenceToAccel(QKeySequence::Paste);
1163
}
1164

1165
void StdCmdPaste::activated(int iMsg)
1166
{
1167
    Q_UNUSED(iMsg);
1168
    bool done = getGuiApplication()->sendMsgToFocusView("Paste");
1169
    if (!done) {
1170
        QClipboard* cb = QApplication::clipboard();
1171
        const QMimeData* mimeData = cb->mimeData();
1172
        if (mimeData) {
1173
            WaitCursor wc;
1174
            getMainWindow()->insertFromMimeData(mimeData);
1175
        }
1176
    }
1177
}
1178

1179
bool StdCmdPaste::isActive()
1180
{
1181
    if (getGuiApplication()->sendHasMsgToFocusView("Paste"))
1182
        return true;
1183
    QClipboard* cb = QApplication::clipboard();
1184
    const QMimeData* mime = cb->mimeData();
1185
    if (!mime)
1186
        return false;
1187
    return getMainWindow()->canInsertFromMimeData(mime);
1188
}
1189

1190
DEF_STD_CMD_A(StdCmdDuplicateSelection)
1191

1192
StdCmdDuplicateSelection::StdCmdDuplicateSelection()
1193
  :Command("Std_DuplicateSelection")
1194
{
1195
    sAppModule    = "Edit";
1196
    sGroup        = "Edit";
1197
    sMenuText     = QT_TR_NOOP("Duplicate selection");
1198
    sToolTipText  = QT_TR_NOOP("Put duplicates of the selected objects to the active document");
1199
    sWhatsThis    = "Std_DuplicateSelection";
1200
    sStatusTip    = QT_TR_NOOP("Put duplicates of the selected objects to the active document");
1201
    sPixmap       = "Std_DuplicateSelection";
1202
}
1203

1204
void StdCmdDuplicateSelection::activated(int iMsg)
1205
{
1206
    Q_UNUSED(iMsg);
1207
    std::vector<App::DocumentObject*> sel;
1208
    std::set<App::DocumentObject*> objSet;
1209
    for(auto &s : Selection().getCompleteSelection()) {
1210
        if(s.pObject && s.pObject->isAttachedToDocument() && objSet.insert(s.pObject).second)
1211
            sel.push_back(s.pObject);
1212
    }
1213
    if(sel.empty())
1214
        return;
1215

1216
    bool hasXLink = false;
1217
    Base::FileInfo fi(App::Application::getTempFileName());
1218
    {
1219
        auto all = App::Document::getDependencyList(sel);
1220
        if (all.size() > sel.size()) {
1221
            DlgObjectSelection dlg(sel,getMainWindow());
1222
            if(dlg.exec()!=QDialog::Accepted)
1223
                return;
1224
            sel = dlg.getSelections();
1225
            if(sel.empty())
1226
                return;
1227
        }
1228
        std::vector<App::Document*> unsaved;
1229
        hasXLink = App::PropertyXLink::hasXLink(sel,&unsaved);
1230
        if(!unsaved.empty()) {
1231
            QMessageBox::critical(getMainWindow(), QObject::tr("Unsaved document"),
1232
                QObject::tr("The exported object contains external link. Please save the document"
1233
                   "at least once before exporting."));
1234
            return;
1235
        }
1236

1237
        // save stuff to file
1238
        Base::ofstream str(fi, std::ios::out | std::ios::binary);
1239
        App::Document* doc = sel.front()->getDocument();
1240
        MergeDocuments mimeView(doc);
1241
        doc->exportObjects(sel, str);
1242
        str.close();
1243
    }
1244
    App::Document* doc = App::GetApplication().getActiveDocument();
1245
    if (doc) {
1246
        bool proceed = true;
1247
        if(hasXLink && !doc->isSaved()) {
1248
            auto ret = QMessageBox::question(getMainWindow(),
1249
                qApp->translate("Std_DuplicateSelection","Object dependencies"),
1250
                qApp->translate("Std_DuplicateSelection",
1251
                "To link to external objects, the document must be saved at least once.\n"
1252
                "Do you want to save the document now?"),
1253
                QMessageBox::Yes,QMessageBox::No);
1254
            if(ret == QMessageBox::Yes)
1255
                proceed = Application::Instance->getDocument(doc)->saveAs();
1256
        }
1257
        if(proceed) {
1258
            doc->openTransaction("Duplicate");
1259
            // restore objects from file and add to active document
1260
            Base::ifstream str(fi, std::ios::in | std::ios::binary);
1261
            MergeDocuments mimeView(doc);
1262
            mimeView.importObjects(str);
1263
            str.close();
1264
            doc->commitTransaction();
1265
        }
1266
    }
1267
    fi.deleteFile();
1268
}
1269

1270
bool StdCmdDuplicateSelection::isActive()
1271
{
1272
    return Gui::Selection().hasSelection();
1273
}
1274

1275
//===========================================================================
1276
// Std_SelectAll
1277
//===========================================================================
1278

1279
DEF_STD_CMD_A(StdCmdSelectAll)
1280

1281
StdCmdSelectAll::StdCmdSelectAll()
1282
  : Command("Std_SelectAll")
1283
{
1284
    sGroup        = "Edit";
1285
    sMenuText     = QT_TR_NOOP("Select &All");
1286
    sToolTipText  = QT_TR_NOOP("Select all");
1287
    sWhatsThis    = "Std_SelectAll";
1288
    sStatusTip    = QT_TR_NOOP("Select all");
1289
    sPixmap       = "edit-select-all";
1290
    //sAccel        = "Ctrl+A"; // supersedes shortcuts for text edits
1291
}
1292

1293
void StdCmdSelectAll::activated(int iMsg)
1294
{
1295
    Q_UNUSED(iMsg);
1296
    SelectionSingleton& rSel = Selection();
1297
    App::Document* doc = App::GetApplication().getActiveDocument();
1298
    std::vector<App::DocumentObject*> objs = doc->getObjectsOfType(App::DocumentObject::getClassTypeId());
1299
    rSel.setSelection(doc->getName(), objs);
1300
}
1301

1302
bool StdCmdSelectAll::isActive()
1303
{
1304
    return App::GetApplication().getActiveDocument() != nullptr;
1305
}
1306

1307
//===========================================================================
1308
// Std_Delete
1309
//===========================================================================
1310
DEF_STD_CMD_A(StdCmdDelete)
1311

1312
StdCmdDelete::StdCmdDelete()
1313
  :Command("Std_Delete")
1314
{
1315
  sGroup        = "Edit";
1316
  sMenuText     = QT_TR_NOOP("&Delete");
1317
  sToolTipText  = QT_TR_NOOP("Deletes the selected objects");
1318
  sWhatsThis    = "Std_Delete";
1319
  sStatusTip    = QT_TR_NOOP("Deletes the selected objects");
1320
  sPixmap       = "edit-delete";
1321
  sAccel        = keySequenceToAccel(QKeySequence::Delete);
1322
  eType         = ForEdit;
1323
}
1324

1325
void StdCmdDelete::activated(int iMsg)
1326
{
1327
    Q_UNUSED(iMsg);
1328

1329
    std::set<App::Document*> docs;
1330
    try {
1331
        openCommand(QT_TRANSLATE_NOOP("Command", "Delete"));
1332
        if (getGuiApplication()->sendHasMsgToFocusView(getName())) {
1333
            commitCommand();
1334
            return;
1335
        }
1336

1337
        App::TransactionLocker tlock;
1338

1339
        Gui::getMainWindow()->setUpdatesEnabled(false);
1340
        auto editDoc = Application::Instance->editDocument();
1341
        ViewProviderDocumentObject *vpedit = nullptr;
1342
        if(editDoc)
1343
            vpedit = dynamic_cast<ViewProviderDocumentObject*>(editDoc->getInEdit());
1344
        if(vpedit && !vpedit->acceptDeletionsInEdit()) {
1345
            for(auto &sel : Selection().getSelectionEx(editDoc->getDocument()->getName())) {
1346
                if(sel.getObject() == vpedit->getObject()) {
1347
                    if (!sel.getSubNames().empty()) {
1348
                        vpedit->onDelete(sel.getSubNames());
1349
                        docs.insert(editDoc->getDocument());
1350
                    }
1351
                    break;
1352
                }
1353
            }
1354
        } else {
1355
            std::set<QString> affectedLabels;
1356
            bool more = false;
1357
            auto sels = Selection().getSelectionEx();
1358
            bool autoDeletion = true;
1359
            for(auto &sel : sels) {
1360
                auto obj = sel.getObject();
1361
                for(auto parent : obj->getInList()) {
1362
                    if(!Selection().isSelected(parent)) {
1363
                        ViewProvider* vp = Application::Instance->getViewProvider(parent);
1364
                        if (vp && !vp->canDelete(obj)) {
1365
                            autoDeletion = false;
1366
                            QString label;
1367
                            if(parent->getDocument() != obj->getDocument())
1368
                                label = QLatin1String(parent->getFullName().c_str());
1369
                            else
1370
                                label = QLatin1String(parent->getNameInDocument());
1371
                            if(parent->Label.getStrValue() != parent->getNameInDocument())
1372
                                label += QString::fromLatin1(" (%1)").arg(
1373
                                        QString::fromUtf8(parent->Label.getValue()));
1374
                            affectedLabels.insert(label);
1375
                            if(affectedLabels.size()>=10) {
1376
                                more = true;
1377
                                break;
1378
                            }
1379
                        }
1380
                    }
1381
                }
1382
                if(more)
1383
                    break;
1384
            }
1385

1386
            if (!autoDeletion) {
1387
                QString bodyMessage;
1388
                QTextStream bodyMessageStream(&bodyMessage);
1389
                bodyMessageStream << qApp->translate("Std_Delete",
1390
                                                     "The following referencing objects might break.\n\n"
1391
                                                     "Are you sure you want to continue?\n");
1392
                for (const auto &currentLabel : affectedLabels)
1393
                    bodyMessageStream << '\n' << currentLabel;
1394
                if(more)
1395
                    bodyMessageStream << "\n...";
1396

1397
                auto ret = QMessageBox::warning(Gui::getMainWindow(),
1398
                    qApp->translate("Std_Delete", "Object dependencies"), bodyMessage,
1399
                    QMessageBox::Yes, QMessageBox::No);
1400
                if (ret == QMessageBox::Yes)
1401
                    autoDeletion = true;
1402
            }
1403
            if (autoDeletion) {
1404
                for(auto &sel : sels) {
1405
                    auto obj = sel.getObject();
1406
                    Gui::ViewProvider* vp = Application::Instance->getViewProvider(obj);
1407
                    if (vp) {
1408
                        // ask the ViewProvider if it wants to do some clean up
1409
                        if (vp->onDelete(sel.getSubNames())) {
1410
                            docs.insert(obj->getDocument());
1411
                            FCMD_OBJ_DOC_CMD(obj,"removeObject('" << obj->getNameInDocument() << "')");
1412
                        }
1413
                    }
1414
                }
1415
            }
1416
        }
1417
        if(!docs.empty()) {
1418
            const auto &outList = App::PropertyXLink::getDocumentOutList();
1419
            for(auto it=docs.begin();it!=docs.end();++it) {
1420
                auto itd = outList.find(*it);
1421
                if(itd!=outList.end()) {
1422
                    for(auto doc : itd->second) {
1423
                        if(doc != *it)
1424
                            docs.erase(doc);
1425
                    }
1426
                }
1427
            }
1428
            for(auto doc : docs) {
1429
                FCMD_DOC_CMD(doc,"recompute()");
1430
            }
1431
        }
1432
    } catch (const Base::Exception& e) {
1433
        QMessageBox::critical(getMainWindow(), QObject::tr("Delete failed"),
1434
                QString::fromLatin1(e.what()));
1435
        e.ReportException();
1436
    } catch (...) {
1437
        QMessageBox::critical(getMainWindow(), QObject::tr("Delete failed"),
1438
                QString::fromLatin1("Unknown error"));
1439
    }
1440
    commitCommand();
1441
    Gui::getMainWindow()->setUpdatesEnabled(true);
1442
    Gui::getMainWindow()->update();
1443
}
1444

1445
bool StdCmdDelete::isActive()
1446
{
1447
    return !Selection().getCompleteSelection().empty();
1448
}
1449

1450
//===========================================================================
1451
// Std_Refresh
1452
//===========================================================================
1453
DEF_STD_CMD_A(StdCmdRefresh)
1454

1455
StdCmdRefresh::StdCmdRefresh()
1456
  : Command("Std_Refresh")
1457
{
1458
    sGroup        = "Edit";
1459
    sMenuText     = QT_TR_NOOP("&Refresh");
1460
    sToolTipText  = QT_TR_NOOP("Recomputes the current active document");
1461
    sWhatsThis    = "Std_Refresh";
1462
    sStatusTip    = QT_TR_NOOP("Recomputes the current active document");
1463
    sPixmap       = "view-refresh";
1464
    sAccel        = keySequenceToAccel(QKeySequence::Refresh);
1465
    eType         = AlterDoc | Alter3DView | AlterSelection | ForEdit;
1466
    bCanLog        = false;
1467

1468
    // Make it optional to create a transaction for a recompute.
1469
    // The new default behaviour is quite cumbersome in some cases because when
1470
    // undoing the last transaction the manual recompute will clear the redo stack.
1471
    ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
1472
            "User parameter:BaseApp/Preferences/Document");
1473
    bool create = hGrp->GetBool("TransactionOnRecompute", false);
1474
    if (!create)
1475
        eType = eType | NoTransaction;
1476
}
1477

1478
void StdCmdRefresh::activated(int iMsg)
1479
{
1480
    Q_UNUSED(iMsg);
1481
    if (getActiveGuiDocument()) {
1482
        App::AutoTransaction trans((eType & NoTransaction) ? nullptr : "Recompute");
1483
        try {
1484
            doCommand(Doc,"App.activeDocument().recompute(None,True,True)");
1485
        }
1486
        catch (Base::Exception& /*e*/) {
1487
            auto ret = QMessageBox::warning(getMainWindow(), QObject::tr("Dependency error"),
1488
                qApp->translate("Std_Refresh", "The document contains dependency cycles.\n"
1489
                            "Please check the Report View for more details.\n\n"
1490
                            "Do you still want to proceed?"),
1491
                    QMessageBox::Yes, QMessageBox::No);
1492
            if(ret == QMessageBox::No)
1493
                return;
1494
            doCommand(Doc,"App.activeDocument().recompute(None,True)");
1495
        }
1496
    }
1497
}
1498

1499
bool StdCmdRefresh::isActive()
1500
{
1501
    return this->getDocument() && this->getDocument()->mustExecute();
1502
}
1503

1504
//===========================================================================
1505
// Std_Transform
1506
//===========================================================================
1507
DEF_STD_CMD_A(StdCmdTransform)
1508

1509
StdCmdTransform::StdCmdTransform()
1510
  : Command("Std_Transform")
1511
{
1512
    sGroup        = "Edit";
1513
    sMenuText     = QT_TR_NOOP("Transform...");
1514
    sToolTipText  = QT_TR_NOOP("Transform the geometry of selected objects");
1515
    sStatusTip    = QT_TR_NOOP("Transform the geometry of selected objects");
1516
    sWhatsThis    = "Std_Transform";
1517
}
1518

1519
void StdCmdTransform::activated(int iMsg)
1520
{
1521
    Q_UNUSED(iMsg);
1522
    Gui::Control().showDialog(new Gui::Dialog::TaskTransform());
1523
}
1524

1525
bool StdCmdTransform::isActive()
1526
{
1527
    return (Gui::Control().activeDialog() == nullptr);
1528
}
1529

1530
//===========================================================================
1531
// Std_Placement
1532
//===========================================================================
1533
DEF_STD_CMD_A(StdCmdPlacement)
1534

1535
StdCmdPlacement::StdCmdPlacement()
1536
  : Command("Std_Placement")
1537
{
1538
    sGroup        = "Edit";
1539
    sMenuText     = QT_TR_NOOP("Placement...");
1540
    sToolTipText  = QT_TR_NOOP("Place the selected objects");
1541
    sStatusTip    = QT_TR_NOOP("Place the selected objects");
1542
    sWhatsThis    = "Std_Placement";
1543
    sPixmap       = "Std_Placement";
1544
}
1545

1546
void StdCmdPlacement::activated(int iMsg)
1547
{
1548
    Q_UNUSED(iMsg);
1549
    std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId());
1550
    auto plm = new Gui::Dialog::TaskPlacement();
1551
    if (!sel.empty()) {
1552
        App::Property* prop = sel.front()->getPropertyByName("Placement");
1553
        if (prop && prop->is<App::PropertyPlacement>()) {
1554
            plm->setPlacement(static_cast<App::PropertyPlacement*>(prop)->getValue());
1555

1556
            std::vector<Gui::SelectionObject> selection;
1557
            selection.reserve(sel.size());
1558
            std::transform(sel.cbegin(), sel.cend(), std::back_inserter(selection), [](App::DocumentObject* obj) {
1559
                return Gui::SelectionObject(obj);
1560
            });
1561

1562
            plm->setPropertyName(QLatin1String("Placement"));
1563
            plm->setSelection(selection);
1564
            plm->bindObject();
1565
            plm->clearSelection();
1566
        }
1567
    }
1568
    Gui::Control().showDialog(plm);
1569
}
1570

1571
bool StdCmdPlacement::isActive()
1572
{
1573
    return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) >= 1;
1574
}
1575

1576
//===========================================================================
1577
// Std_TransformManip
1578
//===========================================================================
1579
DEF_STD_CMD_A(StdCmdTransformManip)
1580

1581
StdCmdTransformManip::StdCmdTransformManip()
1582
  : Command("Std_TransformManip")
1583
{
1584
    sGroup        = "Edit";
1585
    sMenuText     = QT_TR_NOOP("Transform");
1586
    sToolTipText  = QT_TR_NOOP("Transform the selected object in the 3d view");
1587
    sStatusTip    = QT_TR_NOOP("Transform the selected object in the 3d view");
1588
    sWhatsThis    = "Std_TransformManip";
1589
    sPixmap       = "Std_TransformManip";
1590
}
1591

1592
void StdCmdTransformManip::activated(int iMsg)
1593
{
1594
    Q_UNUSED(iMsg);
1595
    if (getActiveGuiDocument()->getInEdit())
1596
        getActiveGuiDocument()->resetEdit();
1597
    std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId());
1598
    Gui::ViewProvider* vp = Application::Instance->getViewProvider(sel.front());
1599
    // FIXME: Need a way to force 'Transform' edit mode
1600
    // #0000477: Proper interface for edit modes of view provider
1601
    if (vp)
1602
        getActiveGuiDocument()->setEdit(vp, Gui::ViewProvider::Transform);
1603
}
1604

1605
bool StdCmdTransformManip::isActive()
1606
{
1607
    return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 1;
1608
}
1609

1610
//===========================================================================
1611
// Std_Alignment
1612
//===========================================================================
1613
DEF_STD_CMD_A(StdCmdAlignment)
1614

1615
StdCmdAlignment::StdCmdAlignment()
1616
  : Command("Std_Alignment")
1617
{
1618
    sGroup        = "Edit";
1619
    sMenuText     = QT_TR_NOOP("Alignment...");
1620
    sToolTipText  = QT_TR_NOOP("Align the selected objects");
1621
    sStatusTip    = QT_TR_NOOP("Align the selected objects");
1622
    sWhatsThis    = "Std_Alignment";
1623
    sPixmap       = "Std_Alignment";
1624
}
1625

1626
void StdCmdAlignment::activated(int iMsg)
1627
{
1628
    Q_UNUSED(iMsg);
1629
    std::vector<App::DocumentObject*> sel = Gui::Selection().getObjectsOfType
1630
        (App::GeoFeature::getClassTypeId());
1631
    ManualAlignment* align = ManualAlignment::instance();
1632
    QObject::connect(align, &ManualAlignment::emitCanceled, align, &QObject::deleteLater);
1633
    QObject::connect(align, &ManualAlignment::emitFinished, align, &QObject::deleteLater);
1634

1635
    // Get the fixed and moving meshes
1636
    FixedGroup fixedGroup;
1637
    std::map<int, MovableGroup> groupMap;
1638
    fixedGroup.addView(sel[0]);
1639
    groupMap[0].addView(sel[1]);
1640

1641
    // add the fixed group
1642
    align->setFixedGroup(fixedGroup);
1643

1644
    // create the model of movable groups
1645
    MovableGroupModel model;
1646
    model.addGroups(groupMap);
1647
    align->setModel(model);
1648
    Base::Type style = Base::Type::fromName("Gui::CADNavigationStyle");
1649
    Base::Vector3d upDir(0,1,0), viewDir(0,0,-1);
1650
    Gui::Document* doc = Application::Instance->activeDocument();
1651
    if (doc) {
1652
        auto mdi = qobject_cast<View3DInventor*>(doc->getActiveView());
1653
        if (mdi) {
1654
            View3DInventorViewer* viewer = mdi->getViewer();
1655
            SoCamera* camera = viewer->getSoRenderManager()->getCamera();
1656
            if (camera) {
1657
                SbVec3f up(0,1,0), dir(0,0,-1);
1658
                camera->orientation.getValue().multVec(dir, dir);
1659
                viewDir.Set(dir[0],dir[1],dir[2]);
1660
                camera->orientation.getValue().multVec(up, up);
1661
                upDir.Set(up[0],up[1],up[2]);
1662
            }
1663
            style = viewer->navigationStyle()->getTypeId();
1664
        }
1665
    }
1666

1667
    align->setMinPoints(1);
1668
    align->startAlignment(style);
1669
    align->setViewingDirections(viewDir,upDir, viewDir,upDir);
1670
    Gui::Selection().clearSelection();
1671
}
1672

1673
bool StdCmdAlignment::isActive()
1674
{
1675
    if (ManualAlignment::hasInstance())
1676
        return false;
1677
    return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 2;
1678
}
1679

1680
//===========================================================================
1681
// Std_Edit
1682
//===========================================================================
1683
DEF_STD_CMD_A(StdCmdEdit)
1684

1685
StdCmdEdit::StdCmdEdit()
1686
  : Command("Std_Edit")
1687
{
1688
    sGroup        = "Edit";
1689
    sMenuText     = QT_TR_NOOP("Toggle &Edit mode");
1690
    sToolTipText  = QT_TR_NOOP("Toggles the selected object's edit mode");
1691
    sWhatsThis    = "Std_Edit";
1692
    sStatusTip    = QT_TR_NOOP("Activates or Deactivates the selected object's edit mode");
1693
    sAccel        = "";
1694
    sPixmap       = "edit-edit";
1695
    eType         = ForEdit;
1696
}
1697

1698
void StdCmdEdit::activated(int iMsg)
1699
{
1700
    Q_UNUSED(iMsg);
1701
    Gui::MDIView* view = Gui::getMainWindow()->activeWindow();
1702
    if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
1703
        Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
1704
        if (viewer->isEditingViewProvider()) {
1705
            doCommand(Command::Gui,"Gui.activeDocument().resetEdit()");
1706
        } else {
1707
            if (!Selection().getCompleteSelection().empty()) {
1708
                SelectionSingleton::SelObj obj = Selection().getCompleteSelection()[0];
1709
                doCommand(Command::Gui,"Gui.activeDocument().setEdit(\"%s\",0)",obj.FeatName);
1710
            }
1711
        }
1712
    }
1713
}
1714

1715
bool StdCmdEdit::isActive()
1716
{
1717
    return (!Selection().getCompleteSelection().empty()) || (Gui::Control().activeDialog() != nullptr);
1718
}
1719

1720
//===========================================================================
1721
// Std_Properties
1722
//===========================================================================
1723
DEF_STD_CMD_A(StdCmdProperties)
1724

1725
StdCmdProperties::StdCmdProperties()
1726
    : Command("Std_Properties")
1727
{
1728
    sGroup = "Edit";
1729
    sMenuText = QT_TR_NOOP("Properties");
1730
    sToolTipText = QT_TR_NOOP("Show the property view, which displays the properties of the selected object.");
1731
    sWhatsThis = "Std_Properties";
1732
    sStatusTip = sToolTipText;
1733
    sAccel = "Alt+Return";
1734
    sPixmap = "document-properties";
1735
    eType = Alter3DView;
1736
}
1737

1738
void StdCmdProperties::activated(int iMsg)
1739
{
1740
    Q_UNUSED(iMsg);
1741
    QWidget* propertyView = Gui::DockWindowManager::instance()->getDockWindow("Property view");
1742
    if (propertyView) {
1743
        QWidget* parent = propertyView->parentWidget();
1744
        if (parent && !parent->isVisible()) {
1745
            parent->show();
1746
        }
1747
    }
1748
}
1749

1750
bool StdCmdProperties::isActive()
1751
{
1752
    return !Selection().getCompleteSelection().empty();
1753
}
1754

1755
//======================================================================
1756
// StdCmdExpression
1757
//===========================================================================
1758
class StdCmdExpression : public Gui::Command
1759
{
1760
public:
1761
    StdCmdExpression() : Command("Std_Expressions")
1762
    {
1763
        sGroup        = "Edit";
1764
        sMenuText     = QT_TR_NOOP("Expression actions");
1765
        sToolTipText  = QT_TR_NOOP("Actions that apply to expressions");
1766
        sWhatsThis    = "Std_Expressions";
1767
        sStatusTip    = QT_TR_NOOP("Actions that apply to expressions");
1768
        eType         = ForEdit;
1769
    }
1770

1771
    const char* className() const override {return "StdCmdExpression";}
1772
protected:
1773

1774
    void activated(int iMsg) override {
1775
        std::map<App::Document*, std::set<App::DocumentObject*> > objs;
1776
        switch(iMsg) {
1777
        case 0:
1778
            for(auto &sel : Selection().getCompleteSelection())
1779
                objs[sel.pObject->getDocument()].insert(sel.pObject);
1780
            break;
1781
        case 1:
1782
            if(App::GetApplication().getActiveDocument()) {
1783
                auto doc = App::GetApplication().getActiveDocument();
1784
                auto array = doc->getObjects();
1785
                auto &set = objs[doc];
1786
                set.insert(array.begin(),array.end());
1787
            }
1788
            break;
1789
        case 2:
1790
            for(auto doc : App::GetApplication().getDocuments()) {
1791
                auto &set = objs[doc];
1792
                auto array = doc->getObjects();
1793
                set.insert(array.begin(),array.end());
1794
            }
1795
            break;
1796
        case 3:
1797
            pasteExpressions();
1798
            break;
1799
        }
1800
        copyExpressions(objs);
1801
    }
1802

1803
    Gui::Action * createAction() override {
1804
        auto pcAction = new ActionGroup(this, getMainWindow());
1805
        pcAction->setDropDownMenu(true);
1806
        applyCommandData(this->className(), pcAction);
1807

1808
        pcActionCopySel = pcAction->addAction(QObject::tr("Copy selected"));
1809
        pcActionCopyActive = pcAction->addAction(QObject::tr("Copy active document"));
1810
        pcActionCopyAll = pcAction->addAction(QObject::tr("Copy all documents"));
1811
        pcActionPaste = pcAction->addAction(QObject::tr("Paste"));
1812

1813
        return pcAction;
1814
    }
1815

1816
    void copyExpressions(const std::map<App::Document*, std::set<App::DocumentObject*> > &objs) {
1817
        std::ostringstream ss;
1818
        std::vector<App::Property*> props;
1819
        for(auto &v : objs) {
1820
            for(auto obj : v.second) {
1821
                props.clear();
1822
                obj->getPropertyList(props);
1823
                for(auto prop : props) {
1824
                    auto p = dynamic_cast<App::PropertyExpressionContainer*>(prop);
1825
                    if(!p) continue;
1826
                    for(auto &v : p->getExpressions()) {
1827
                        ss << "##@@ " << v.first.toString() << ' '
1828
                           << obj->getFullName() << '.' << p->getName()
1829
                           << " (" << obj->Label.getValue() << ')' << std::endl;
1830
                        ss << "##@@";
1831
                        if(!v.second->comment.empty()) {
1832
                            if(v.second->comment[0] == '&'
1833
                                    || v.second->comment.find('\n') != std::string::npos
1834
                                    || v.second->comment.find('\r') != std::string::npos)
1835
                            {
1836
                                std::string comment = v.second->comment;
1837
                                boost::replace_all(comment,"&","&amp;");
1838
                                boost::replace_all(comment,"\n","&#10;");
1839
                                boost::replace_all(comment,"\r","&#13;");
1840
                                ss << '&' << comment;
1841
                            }else
1842
                                ss << v.second->comment;
1843
                        }
1844
                        ss << std::endl << v.second->toString(true) << std::endl << std::endl;
1845
                    }
1846
                }
1847
            }
1848
        }
1849
        QApplication::clipboard()->setText(QString::fromUtf8(ss.str().c_str()));
1850
    }
1851

1852
    void pasteExpressions() {
1853
        std::map<App::Document*, std::map<App::PropertyExpressionContainer*,
1854
            std::map<App::ObjectIdentifier, App::ExpressionPtr> > > exprs;
1855

1856
        bool failed = false;
1857
        std::string txt = QApplication::clipboard()->text().toUtf8().constData();
1858
        const char *tstart = txt.c_str();
1859
        const char *tend = tstart + txt.size();
1860

1861
        static boost::regex rule("^##@@ ([^ ]+) (\\w+)#(\\w+)\\.(\\w+) [^\n]+\n##@@([^\n]*)\n");
1862
        boost::cmatch m;
1863
        if(!boost::regex_search(tstart,m,rule)) {
1864
            FC_WARN("No expression header found");
1865
            return;
1866
        }
1867
        boost::cmatch m2;
1868
        bool found = true;
1869
        for(;found;m=m2) {
1870
            found = boost::regex_search(m[0].second,tend,m2,rule);
1871

1872
            auto pathName = m.str(1);
1873
            auto docName = m.str(2);
1874
            auto objName = m.str(3);
1875
            auto propName = m.str(4);
1876
            auto comment = m.str(5);
1877

1878
            App::Document *doc = App::GetApplication().getDocument(docName.c_str());
1879
            if(!doc) {
1880
                FC_WARN("Cannot find document '" << docName << "'");
1881
                continue;
1882
            }
1883

1884
            auto obj = doc->getObject(objName.c_str());
1885
            if(!obj) {
1886
                FC_WARN("Cannot find object '" << docName << '#' << objName << "'");
1887
                continue;
1888
            }
1889

1890
            auto prop = dynamic_cast<App::PropertyExpressionContainer*>(
1891
                    obj->getPropertyByName(propName.c_str()));
1892
            if(!prop) {
1893
                FC_WARN("Invalid property '" << docName << '#' << objName << '.' << propName << "'");
1894
                continue;
1895
            }
1896

1897
            size_t len = (found?m2[0].first:tend) - m[0].second;
1898
            try {
1899
                App::ExpressionPtr expr(App::Expression::parse(obj,std::string(m[0].second,len)));
1900
                if(expr && !comment.empty()) {
1901
                    if(comment[0] == '&') {
1902
                        expr->comment = comment.c_str()+1;
1903
                        boost::replace_all(expr->comment,"&amp;","&");
1904
                        boost::replace_all(expr->comment,"&#10;","\n");
1905
                        boost::replace_all(expr->comment,"&#13;","\r");
1906
                    } else
1907
                        expr->comment = comment;
1908
                }
1909
                exprs[doc][prop][App::ObjectIdentifier::parse(obj,pathName)] = std::move(expr);
1910
            } catch(Base::Exception &e) {
1911
                FC_ERR(e.what() << std::endl << m[0].str());
1912
                failed = true;
1913
            }
1914
        }
1915
        if(failed) {
1916
            QMessageBox::critical(getMainWindow(), QObject::tr("Expression error"),
1917
                QObject::tr("Failed to parse some of the expressions.\n"
1918
                            "Please check the Report View for more details."));
1919
            return;
1920
        }
1921

1922
        openCommand(QT_TRANSLATE_NOOP("Command", "Paste expressions"));
1923
        try {
1924
            for(auto &v : exprs) {
1925
                for(auto &v2 : v.second) {
1926
                    auto &expressions = v2.second;
1927
                    auto old = v2.first->getExpressions();
1928
                    for(auto it=expressions.begin(),itNext=it;it!=expressions.end();it=itNext) {
1929
                        ++itNext;
1930
                        auto iter = old.find(it->first);
1931
                        if(iter != old.end() && it->second->isSame(*iter->second))
1932
                            expressions.erase(it);
1933
                    }
1934
                    if(!expressions.empty())
1935
                        v2.first->setExpressions(std::move(expressions));
1936
                }
1937
            }
1938
            commitCommand();
1939
        } catch (const Base::Exception& e) {
1940
            abortCommand();
1941
            QMessageBox::critical(getMainWindow(), QObject::tr("Failed to paste expressions"),
1942
                QString::fromLatin1(e.what()));
1943
            e.ReportException();
1944
        }
1945
    }
1946

1947
    bool isActive() override {
1948
        if(!App::GetApplication().getActiveDocument()) {
1949
            pcActionCopyAll->setEnabled(false);
1950
            pcActionCopySel->setEnabled(false);
1951
            pcActionCopyActive->setEnabled(false);
1952
            pcActionPaste->setEnabled(false);
1953
            return true;
1954
        }
1955
        pcActionCopyActive->setEnabled(true);
1956
        pcActionCopyAll->setEnabled(true);
1957
        pcActionCopySel->setEnabled(Selection().hasSelection());
1958

1959
        pcActionPaste->setEnabled(
1960
                QApplication::clipboard()->text().startsWith(QLatin1String("##@@ ")));
1961
        return true;
1962
    }
1963

1964
    QAction *pcActionCopyAll{nullptr};
1965
    QAction *pcActionCopySel{nullptr};
1966
    QAction *pcActionCopyActive{nullptr};
1967
    QAction *pcActionPaste{nullptr};
1968
};
1969

1970
namespace Gui {
1971

1972
void CreateDocCommands()
1973
{
1974
    CommandManager &rcCmdMgr = Application::Instance->commandManager();
1975

1976
    rcCmdMgr.addCommand(new StdCmdNew());
1977
    rcCmdMgr.addCommand(new StdCmdOpen());
1978
    rcCmdMgr.addCommand(new StdCmdImport());
1979
    rcCmdMgr.addCommand(new StdCmdExport());
1980
    rcCmdMgr.addCommand(new StdCmdMergeProjects());
1981
    rcCmdMgr.addCommand(new StdCmdDependencyGraph());
1982
    rcCmdMgr.addCommand(new StdCmdExportDependencyGraph());
1983

1984
    rcCmdMgr.addCommand(new StdCmdSave());
1985
    rcCmdMgr.addCommand(new StdCmdSaveAs());
1986
    rcCmdMgr.addCommand(new StdCmdSaveCopy());
1987
    rcCmdMgr.addCommand(new StdCmdSaveAll());
1988
    rcCmdMgr.addCommand(new StdCmdRevert());
1989
    rcCmdMgr.addCommand(new StdCmdProjectInfo());
1990
    rcCmdMgr.addCommand(new StdCmdProjectUtil());
1991
    rcCmdMgr.addCommand(new StdCmdUndo());
1992
    rcCmdMgr.addCommand(new StdCmdRedo());
1993
    rcCmdMgr.addCommand(new StdCmdPrint());
1994
    rcCmdMgr.addCommand(new StdCmdPrintPreview());
1995
    rcCmdMgr.addCommand(new StdCmdPrintPdf());
1996
    rcCmdMgr.addCommand(new StdCmdQuit());
1997
    rcCmdMgr.addCommand(new StdCmdCut());
1998
    rcCmdMgr.addCommand(new StdCmdCopy());
1999
    rcCmdMgr.addCommand(new StdCmdPaste());
2000
    rcCmdMgr.addCommand(new StdCmdDuplicateSelection());
2001
    rcCmdMgr.addCommand(new StdCmdSelectAll());
2002
    rcCmdMgr.addCommand(new StdCmdDelete());
2003
    rcCmdMgr.addCommand(new StdCmdRefresh());
2004
    rcCmdMgr.addCommand(new StdCmdTransform());
2005
    rcCmdMgr.addCommand(new StdCmdPlacement());
2006
    rcCmdMgr.addCommand(new StdCmdTransformManip());
2007
    rcCmdMgr.addCommand(new StdCmdAlignment());
2008
    rcCmdMgr.addCommand(new StdCmdEdit());
2009
    rcCmdMgr.addCommand(new StdCmdProperties());
2010
    rcCmdMgr.addCommand(new StdCmdExpression());
2011
}
2012

2013
} // namespace Gui
2014

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.