FreeCAD

Форк
0
/
CommandLink.cpp 
912 строк · 32.1 Кб
1
/****************************************************************************
2
 *   Copyright (c) 2017 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
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
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
# include <sstream>
27
# include <QMessageBox>
28
#endif
29

30
#include <App/Application.h>
31
#include <App/ElementNamingUtils.h>
32
#include <App/Document.h>
33
#include <App/DocumentObject.h>
34
#include <App/Link.h>
35
#include <Base/Exception.h>
36
#include <Base/Tools.h>
37

38
#include "Action.h"
39
#include "Application.h"
40
#include "Command.h"
41
#include "Document.h"
42
#include "MainWindow.h"
43
#include "Selection.h"
44
#include "Tree.h"
45
#include "ViewProviderDocumentObject.h"
46
#include "WaitCursor.h"
47

48

49
FC_LOG_LEVEL_INIT("CommandLink", true, true)
50

51
using namespace Gui;
52

53
static void setLinkLabel(App::DocumentObject *obj, const char *doc, const char *name) {
54
    std::string label = obj->Label.getValue();
55
    label = Base::Tools::escapeEncodeString(label);
56
    Command::doCommand(Command::Doc,"App.getDocument('%s').getObject('%s').Label='%s'",doc,name,label.c_str());
57
}
58

59
////////////////////////////////////////////////////////////////////////////////////////////
60

61
class StdCmdLinkMakeGroup : public Gui::Command
62
{
63
public:
64
    StdCmdLinkMakeGroup();
65
    const char* className() const override
66
    { return "StdCmdLinkMakeGroup"; }
67

68
protected:
69
    void activated(int iMsg) override;
70
    bool isActive() override;
71
    Action * createAction() override;
72
    void languageChange() override;
73
};
74

75
StdCmdLinkMakeGroup::StdCmdLinkMakeGroup()
76
  : Command("Std_LinkMakeGroup")
77
{
78
    sGroup        = "Link";
79
    sMenuText     = QT_TR_NOOP("Make link group");
80
    sToolTipText  = QT_TR_NOOP("Create a group of links");
81
    sWhatsThis    = "Std_LinkMakeGroup";
82
    sStatusTip    = sToolTipText;
83
    eType         = AlterDoc;
84
    sPixmap       = "LinkGroup";
85
}
86

87
bool StdCmdLinkMakeGroup::isActive() {
88
    return !!App::GetApplication().getActiveDocument();
89
}
90

91
Action * StdCmdLinkMakeGroup::createAction()
92
{
93
    auto pcAction = new ActionGroup(this, getMainWindow());
94
    pcAction->setDropDownMenu(true);
95
    applyCommandData(this->className(), pcAction);
96

97
    // add the action items
98
    QAction* action = nullptr;
99
    action = pcAction->addAction(QObject::tr("Simple group"));
100
    action->setWhatsThis(QString::fromLatin1(getWhatsThis()));
101
    action = pcAction->addAction(QObject::tr("Group with links"));
102
    action->setWhatsThis(QString::fromLatin1(getWhatsThis()));
103
    action = pcAction->addAction(QObject::tr("Group with transform links"));
104
    action->setWhatsThis(QString::fromLatin1(getWhatsThis()));
105
    return pcAction;
106
}
107

108
void StdCmdLinkMakeGroup::languageChange()
109
{
110
    Command::languageChange();
111

112
    if (!_pcAction)
113
        return;
114
    auto pcAction = qobject_cast<ActionGroup*>(_pcAction);
115
    QList<QAction*> acts = pcAction->actions();
116
    acts[0]->setText(QObject::tr("Simple group"));
117
    acts[1]->setText(QObject::tr("Group with links"));
118
    acts[2]->setText(QObject::tr("Group with transform links"));
119
}
120

121

122
void StdCmdLinkMakeGroup::activated(int option) {
123

124
    std::vector<App::DocumentObject*> objs;
125
    std::set<App::DocumentObject*> objset;
126

127
    auto doc = App::GetApplication().getActiveDocument();
128
    if(!doc) {
129
        FC_ERR("no active document");
130
        return;
131
    }
132

133
    for(auto &sel : Selection().getCompleteSelection()) {
134
        if(sel.pObject && sel.pObject->isAttachedToDocument() &&
135
           objset.insert(sel.pObject).second)
136
            objs.push_back(sel.pObject);
137
    }
138

139
    Selection().selStackPush();
140
    Selection().clearCompleteSelection();
141

142
    Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make link group"));
143
    try {
144
        std::string groupName = doc->getUniqueObjectName("LinkGroup");
145
        Command::doCommand(Command::Doc,
146
            "App.getDocument('%s').addObject('App::LinkGroup','%s')",doc->getName(),groupName.c_str());
147
        if(objs.empty()) {
148
            Selection().addSelection(doc->getName(),groupName.c_str());
149
            Selection().selStackPush();
150
        }else{
151
            Command::doCommand(Command::Doc,"__objs__ = []");
152
            for(auto obj : objs) {
153
                std::string name;
154
                if(option!=0 || doc!=obj->getDocument()) {
155
                    name = doc->getUniqueObjectName("Link");
156
                    Command::doCommand(Command::Doc,
157
                        "App.getDocument('%s').addObject('App::Link','%s').setLink("
158
                            "App.getDocument('%s').getObject('%s'))",
159
                        doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
160
                    setLinkLabel(obj,doc->getName(),name.c_str());
161
                    if(option==2)
162
                        Command::doCommand(Command::Doc,
163
                            "App.getDocument('%s').getObject('%s').LinkTransform = True",
164
                            doc->getName(),name.c_str());
165
                    else if(obj->getPropertyByName("Placement"))
166
                        Command::doCommand(Command::Doc,
167
                            "App.getDocument('%s').getObject('%s').Placement = "
168
                                "App.getDocument('%s').getObject('%s').Placement",
169
                            doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
170
                }else
171
                    name = obj->getNameInDocument();
172
                Command::doCommand(Command::Doc,"__objs__.append(App.getDocument('%s').getObject('%s'))",
173
                        doc->getName(),name.c_str());
174
                Command::doCommand(Command::Doc,
175
                        "App.getDocument('%s').getObject('%s').ViewObject.Visibility=False",
176
                        doc->getName(),name.c_str());
177
            }
178
            Command::doCommand(Command::Doc,"App.getDocument('%s').getObject('%s').setLink(__objs__)",
179
                    doc->getName(),groupName.c_str());
180
            Command::doCommand(Command::Doc,"del __objs__");
181

182
            for(size_t i=0;i<objs.size();++i) {
183
                auto name = std::to_string(i)+".";
184
                Selection().addSelection(doc->getName(),groupName.c_str(),name.c_str());
185
            }
186
            Selection().selStackPush();
187
        }
188
        if(option!=0) {
189
            Command::doCommand(Command::Doc,
190
                    "App.getDocument('%s').getObject('%s').LinkMode = 'Auto Delete'",
191
                    doc->getName(),groupName.c_str());
192
        }
193
        Command::commitCommand();
194
    } catch (const Base::Exception& e) {
195
        QMessageBox::critical(getMainWindow(), QObject::tr("Create link group failed"),
196
            QString::fromLatin1(e.what()));
197
        Command::abortCommand();
198
        e.ReportException();
199
    }
200
} 
201

202
////////////////////////////////////////////////////////////////////////////////////////////
203

204
DEF_STD_CMD_A(StdCmdLinkMake)
205

206
StdCmdLinkMake::StdCmdLinkMake()
207
  : Command("Std_LinkMake")
208
{
209
    sGroup        = "Link";
210
    sMenuText     = QT_TR_NOOP("Make link");
211
    sToolTipText  = QT_TR_NOOP("A Link is an object that references or links to another object in the same document, "
212
                               "or in another document. Unlike Clones, Links reference the original Shape directly, "
213
                               "making them more memory-efficient, which helps with the creation of complex assemblies.");
214
    sWhatsThis    = "Std_LinkMake";
215
    sStatusTip    = sToolTipText;
216
    eType         = AlterDoc;
217
    sPixmap       = "Link";
218
}
219

220
bool StdCmdLinkMake::isActive() {
221
    return App::GetApplication().getActiveDocument();
222
}
223

224
void StdCmdLinkMake::activated(int) {
225
    auto doc = App::GetApplication().getActiveDocument();
226
    if(!doc) {
227
        FC_ERR("no active document");
228
        return;
229
    }
230

231
    std::set<App::DocumentObject*> objs;
232
    for(auto &sel : Selection().getCompleteSelection()) {
233
        if(sel.pObject && sel.pObject->isAttachedToDocument())
234
           objs.insert(sel.pObject);
235
    }
236

237
    Selection().selStackPush();
238
    Selection().clearCompleteSelection();
239

240
    Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make link"));
241
    try {
242
        if(objs.empty()) {
243
            std::string name = doc->getUniqueObjectName("Link");
244
            Command::doCommand(Command::Doc, "App.getDocument('%s').addObject('App::Link','%s')",
245
                doc->getName(),name.c_str());
246
            Selection().addSelection(doc->getName(),name.c_str());
247
        }else{
248
            for(auto obj : objs) {
249
                std::string name = doc->getUniqueObjectName("Link");
250
                Command::doCommand(Command::Doc,
251
                    "App.getDocument('%s').addObject('App::Link','%s').setLink(App.getDocument('%s').%s)",
252
                    doc->getName(),name.c_str(),obj->getDocument()->getName(),obj->getNameInDocument());
253
                setLinkLabel(obj,doc->getName(),name.c_str());
254
                Selection().addSelection(doc->getName(),name.c_str());
255
            }
256
        }
257
        Selection().selStackPush();
258
        Command::commitCommand();
259
    } catch (const Base::Exception& e) {
260
        Command::abortCommand();
261
        QMessageBox::critical(getMainWindow(), QObject::tr("Create link failed"),
262
            QString::fromLatin1(e.what()));
263
        e.ReportException();
264
    }
265
}
266

267
////////////////////////////////////////////////////////////////////////////////////////////
268

269
DEF_STD_CMD_A(StdCmdLinkMakeRelative)
270

271
StdCmdLinkMakeRelative::StdCmdLinkMakeRelative()
272
  : Command("Std_LinkMakeRelative")
273
{
274
    sGroup        = "Link";
275
    sMenuText     = QT_TR_NOOP("Make sub-link");
276
    sToolTipText  = QT_TR_NOOP("Create a sub-object or sub-element link");
277
    sWhatsThis    = "Std_LinkMakeRelative";
278
    sStatusTip    = sToolTipText;
279
    eType         = AlterDoc;
280
    sPixmap       = "LinkSub";
281
}
282

283
bool StdCmdLinkMakeRelative::isActive() {
284
    return Selection().hasSubSelection(nullptr,true);
285
}
286

287
void StdCmdLinkMakeRelative::activated(int) {
288
    auto doc = App::GetApplication().getActiveDocument();
289
    if(!doc) {
290
        FC_ERR("no active document");
291
        return;
292
    }
293
    Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make sub-link"));
294
    try {
295
        std::map<std::pair<App::DocumentObject*,std::string>,
296
                 std::pair<App::DocumentObject*, std::vector<std::string> > > linkInfo;
297
        for(auto &sel : Selection().getCompleteSelection(ResolveMode::NoResolve)) {
298
            if(!sel.pObject || !sel.pObject->isAttachedToDocument())
299
                continue;
300
            auto key = std::make_pair(sel.pObject,
301
                    Data::noElementName(sel.SubName));
302
            auto element = Data::findElementName(sel.SubName);
303
            auto &info = linkInfo[key];
304
            info.first = sel.pResolvedObject;
305
            if(element && element[0])
306
                info.second.emplace_back(element);
307
        }
308

309
        Selection().selStackPush();
310
        Selection().clearCompleteSelection();
311

312
        for(auto &v : linkInfo) {
313
            auto &key = v.first;
314
            auto &info = v.second;
315

316
            std::string name = doc->getUniqueObjectName("Link");
317

318
            std::ostringstream ss;
319
            ss << '[';
320
            for(auto &s : info.second)
321
                ss << "'" << s << "',";
322
            ss << ']';
323
            FCMD_DOC_CMD(doc,"addObject('App::Link','" << name << "').setLink("
324
                    << getObjectCmd(key.first) << ",'" << key.second
325
                    << "'," << ss.str() << ")");
326
            auto link = doc->getObject(name.c_str());
327
            FCMD_OBJ_CMD(link,"LinkTransform = True");
328
            setLinkLabel(info.first,doc->getName(),name.c_str());
329

330
            Selection().addSelection(doc->getName(),name.c_str());
331
        }
332
        Selection().selStackPush();
333
        Command::commitCommand();
334
    } catch (const Base::Exception& e) {
335
        Command::abortCommand();
336
        QMessageBox::critical(getMainWindow(), QObject::tr("Failed to create relative link"),
337
            QString::fromLatin1(e.what()));
338
        e.ReportException();
339
    }
340
    return;
341
}
342

343
/////////////////////////////////////////////////////////////////////////////////////
344

345
struct Info {
346
    bool inited = false;
347
    App::DocumentObjectT topParent;
348
    std::string subname;
349
    App::DocumentObjectT parent;
350
    App::DocumentObjectT obj;
351
};
352

353
static void linkConvert(bool unlink) {
354
    // We are trying to replace an object with a link (App::Link), or replace a
355
    // link back to its linked object (i.e. unlink). This is a very complex
356
    // operation. It works by reassign the link property of the parent of the
357
    // selected object(s) to a newly created link to the original object.
358
    // Everything should remain the same. This complexity is now largely handled
359
    // by ViewProviderDocumentObject::replaceObject(), which in turn relies on
360
    // PropertyLinkBase::CopyOnLinkReplace().
361

362
    std::map<std::pair<App::DocumentObject*,App::DocumentObject*>, Info> infos;
363
    for(const auto& sel : TreeWidget::getSelection()) {
364
        auto obj = sel.vp->getObject();
365
        auto parent = sel.parentVp;
366
        if(!parent) {
367
            FC_WARN("skip '" << obj->getFullName() << "' with no parent");
368
            continue;
369
        }
370
        auto parentObj = parent->getObject();
371
        auto &info = infos[std::make_pair(parentObj,obj)];
372
        if(info.inited)
373
            continue;
374
        info.inited = true;
375
        if(unlink) {
376
            auto linked = obj->getLinkedObject(false);
377
            if(!linked || !linked->isAttachedToDocument() || linked == obj) {
378
                FC_WARN("skip non link");
379
                continue;
380
            }
381
        }
382
        info.topParent = sel.topParent;
383
        info.parent = parentObj;
384
        info.obj = obj;
385
    }
386

387
    if(infos.empty())
388
        return;
389

390
    Selection().selStackPush();
391
    Selection().clearCompleteSelection();
392

393
    // now, do actual operation
394
    const char *transactionName = unlink?"Unlink":"Replace with link";
395
    Command::openCommand(transactionName);
396
    try {
397
        std::unordered_map<App::DocumentObject*,App::DocumentObjectT> recomputeSet;
398
        for(auto &v : infos) {
399
            auto &info = v.second;
400
            auto parent = info.parent.getObject();
401
            auto parentVp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
402
                    Application::Instance->getViewProvider(parent));
403
            auto obj = info.obj.getObject();
404
            if(!parent || !obj || !parentVp)
405
                continue;
406
            if(!recomputeSet.count(parent))
407
                recomputeSet.emplace(parent,parent);
408
            auto doc = parent->getDocument();
409
            App::DocumentObject *replaceObj;
410
            if(unlink) {
411
                replaceObj = obj->getLinkedObject(false);
412
                if(!replaceObj || !replaceObj->isAttachedToDocument() || replaceObj == obj)
413
                    continue;
414
            }else{
415
                auto name = doc->getUniqueObjectName("Link");
416
                auto link = static_cast<App::Link*>(doc->addObject("App::Link",name.c_str()));
417
                if(!link)
418
                    FC_THROWM(Base::RuntimeError,"Failed to create link");
419
                link->setLink(-1,obj);
420
                link->Label.setValue(obj->Label.getValue());
421
                auto pla = Base::freecad_dynamic_cast<App::PropertyPlacement>(
422
                        obj->getPropertyByName("Placement"));
423
                if(pla)
424
                    link->Placement.setValue(pla->getValue());
425
                else
426
                    link->LinkTransform.setValue(true);
427
                replaceObj = link;
428
            }
429

430
            // adjust subname for the new object
431
            auto pos = info.subname.rfind('.');
432
            if(pos==std::string::npos && pos)
433
                info.subname.clear();
434
            else {
435
                pos = info.subname.rfind('.',pos-1);
436
                if(pos==std::string::npos)
437
                    info.subname.clear();
438
                else {
439
                    info.subname.resize(pos+1);
440
                    info.subname += replaceObj->getNameInDocument();
441
                    info.subname += ".";
442
                }
443
            }
444

445
            // do the replacement operation
446
            if(parentVp->replaceObject(obj,replaceObj)<=0)
447
                FC_THROWM(Base::RuntimeError,
448
                        "Failed to change link for " << parent->getFullName());
449
        }
450

451
        std::vector<App::DocumentObject *> recomputes;
452
        for(auto &v : recomputeSet) {
453
            auto obj = v.second.getObject();
454
            if(obj)
455
                recomputes.push_back(obj);
456
        }
457
        if(!recomputes.empty())
458
            recomputes.front()->getDocument()->recompute(recomputes);
459

460
        Command::commitCommand();
461

462
    } catch (const Base::Exception& e) {
463
        Command::abortCommand();
464
        auto title = unlink?QObject::tr("Unlink failed"):QObject::tr("Replace link failed");
465
        QMessageBox::critical(getMainWindow(), title, QString::fromLatin1(e.what()));
466
        e.ReportException();
467
        return;
468
    }
469
}
470

471
static bool linkConvertible(bool unlink) {
472
    int count = 0;
473
    for(auto &sel : TreeWidget::getSelection()) {
474
        auto parent = sel.parentVp;
475
        if(!parent)
476
            return false;
477
        auto obj = sel.vp->getObject();
478
        if(unlink) {
479
            auto linked = obj->getLinkedObject(false);
480
            if(!linked || linked == obj)
481
                return false;
482
        }
483
        ++count;
484
    }
485
    return count!=0;
486
}
487

488
////////////////////////////////////////////////////////////////////////////////////////////
489

490
DEF_STD_CMD_A(StdCmdLinkReplace)
491

492
StdCmdLinkReplace::StdCmdLinkReplace()
493
  : Command("Std_LinkReplace")
494
{
495
    sGroup        = "Link";
496
    sMenuText     = QT_TR_NOOP("Replace with link");
497
    sToolTipText  = QT_TR_NOOP("Replace the selected object(s) with link");
498
    sWhatsThis    = "Std_LinkReplace";
499
    sStatusTip    = sToolTipText;
500
    eType         = AlterDoc;
501
    sPixmap       = "LinkReplace";
502
}
503

504
bool StdCmdLinkReplace::isActive() {
505
    return linkConvertible(false);
506
}
507

508
void StdCmdLinkReplace::activated(int) {
509
    linkConvert(false);
510
}
511

512
////////////////////////////////////////////////////////////////////////////////////////////
513

514
DEF_STD_CMD_A(StdCmdLinkUnlink)
515

516
StdCmdLinkUnlink::StdCmdLinkUnlink()
517
  : Command("Std_LinkUnlink")
518
{
519
    sGroup        = "Link";
520
    sMenuText     = QT_TR_NOOP("Unlink");
521
    sToolTipText  = QT_TR_NOOP("Strip on level of link");
522
    sWhatsThis    = "Std_LinkUnlink";
523
    sStatusTip    = sToolTipText;
524
    eType         = AlterDoc;
525
    sPixmap       = "Unlink";
526
}
527

528
bool StdCmdLinkUnlink::isActive() {
529
    return linkConvertible(true);
530
}
531

532
void StdCmdLinkUnlink::activated(int) {
533
    linkConvert(true);
534
}
535

536
////////////////////////////////////////////////////////////////////////////////////////////
537

538
DEF_STD_CMD_A(StdCmdLinkImport)
539

540
StdCmdLinkImport::StdCmdLinkImport()
541
  : Command("Std_LinkImport")
542
{
543
    sGroup        = "Link";
544
    sMenuText     = QT_TR_NOOP("Import links");
545
    sToolTipText  = QT_TR_NOOP("Import selected external link(s)");
546
    sWhatsThis    = "Std_LinkImport";
547
    sStatusTip    = sToolTipText;
548
    eType         = AlterDoc;
549
    sPixmap       = "LinkImport";
550
}
551

552
static std::map<App::Document*, std::vector<App::DocumentObject*> > getLinkImportSelections()
553
{
554
    std::map<App::Document*, std::vector<App::DocumentObject*> > objMap;
555
    for(auto &sel : Selection().getCompleteSelection(ResolveMode::NoResolve)) {
556
        auto obj = sel.pObject->resolve(sel.SubName);
557
        if(!obj || !obj->isAttachedToDocument())
558
            continue;
559
        for(auto o : obj->getOutList()) {
560
            if(o && o->isAttachedToDocument() && o->getDocument()!=obj->getDocument()) {
561
                objMap[obj->getDocument()].push_back(obj);
562
                break;
563
            }
564
        }
565
    }
566
    return objMap;
567
}
568

569
bool StdCmdLinkImport::isActive() {
570
    auto links = getLinkImportSelections();
571
    if(links.empty())
572
        return false;
573
    for(auto &v : links) {
574
        if(v.first->testStatus(App::Document::PartialDoc))
575
            return false;
576
    }
577
    return true;
578
}
579

580
void StdCmdLinkImport::activated(int) {
581
    Command::openCommand(QT_TRANSLATE_NOOP("Command", "Import links"));
582
    try {
583
        WaitCursor wc;
584
        wc.setIgnoreEvents(WaitCursor::NoEvents);
585
        for(auto &v : getLinkImportSelections()) {
586
            auto doc = v.first;
587
            // TODO: Is it possible to do this using interpreter?
588
            for(auto obj : doc->importLinks(v.second))
589
                obj->Visibility.setValue(false);
590
        }
591
        Command::commitCommand();
592
    }catch (const Base::Exception& e) {
593
        Command::abortCommand();
594
        QMessageBox::critical(getMainWindow(), QObject::tr("Failed to import links"),
595
            QString::fromLatin1(e.what()));
596
        e.ReportException();
597
    }
598
}
599

600
////////////////////////////////////////////////////////////////////////////////////////////
601

602
DEF_STD_CMD_A(StdCmdLinkImportAll)
603

604
StdCmdLinkImportAll::StdCmdLinkImportAll()
605
  : Command("Std_LinkImportAll")
606
{
607
    sGroup        = "Link";
608
    sMenuText     = QT_TR_NOOP("Import all links");
609
    sToolTipText  = QT_TR_NOOP("Import all links of the active document");
610
    sWhatsThis    = "Std_LinkImportAll";
611
    sStatusTip    = sToolTipText;
612
    eType         = AlterDoc;
613
    sPixmap       = "LinkImportAll";
614
}
615

616
bool StdCmdLinkImportAll::isActive() {
617
    auto doc = App::GetApplication().getActiveDocument();
618
    return doc && !doc->testStatus(App::Document::PartialDoc) && App::PropertyXLink::hasXLink(doc);
619
}
620

621
void StdCmdLinkImportAll::activated(int) {
622
    Command::openCommand(QT_TRANSLATE_NOOP("Command", "Import all links"));
623
    try {
624
        WaitCursor wc;
625
        wc.setIgnoreEvents(WaitCursor::NoEvents);
626
        auto doc = App::GetApplication().getActiveDocument();
627
        if(doc) {
628
            for(auto obj : doc->importLinks())
629
                obj->Visibility.setValue(false);
630
        }
631
        Command::commitCommand();
632
    } catch (const Base::Exception& e) {
633
        QMessageBox::critical(getMainWindow(), QObject::tr("Failed to import all links"),
634
            QString::fromLatin1(e.what()));
635
        Command::abortCommand();
636
        e.ReportException();
637
    }
638
}
639

640

641
////////////////////////////////////////////////////////////////////////////////////////////
642

643
DEF_STD_CMD_A(StdCmdLinkSelectLinked)
644

645
StdCmdLinkSelectLinked::StdCmdLinkSelectLinked()
646
  : Command("Std_LinkSelectLinked")
647
{
648
    sGroup        = "Link";
649
    sMenuText     = QT_TR_NOOP("Go to linked object");
650
    sToolTipText  = QT_TR_NOOP("Select the linked object and switch to its owner document");
651
    sWhatsThis    = "Std_LinkSelectLinked";
652
    sStatusTip    = sToolTipText;
653
    eType         = AlterSelection;
654
    sPixmap       = "LinkSelect";
655
    sAccel        = "S, G";
656
}
657

658
static App::DocumentObject *getSelectedLink(bool finalLink, std::string *subname=nullptr) {
659
    const auto &sels = Selection().getSelection("*", ResolveMode::NoResolve, true);
660
    if(sels.empty())
661
        return nullptr;
662
    auto sobj = sels[0].pObject->getSubObject(sels[0].SubName);
663
    if(!sobj)
664
        return nullptr;
665
    auto vp = Base::freecad_dynamic_cast<ViewProviderDocumentObject>(
666
            Application::Instance->getViewProvider(sobj));
667
    if(!vp)
668
        return nullptr;
669

670
    auto linkedVp = vp->getLinkedViewProvider(subname,finalLink);
671
    if(!linkedVp || linkedVp==vp) {
672
        if(sobj->getDocument()==sels[0].pObject->getDocument())
673
            return nullptr;
674
        for(const char *dot=strchr(sels[0].SubName,'.');dot;dot=strchr(dot+1,'.')) {
675
            std::string sub(sels[0].SubName,dot+1-sels[0].SubName);
676
            auto obj = sels[0].pObject->getSubObject(sub.c_str());
677
            if(!obj)
678
                break;
679
            obj = obj->getLinkedObject(true);
680
            if(obj->getDocument()!=sels[0].pObject->getDocument()) {
681
                if(finalLink)
682
                    return sobj==obj?nullptr:sobj;
683
                if(subname)
684
                    *subname = std::string(dot+1);
685
                return obj;
686
            }
687
        }
688
        return finalLink?nullptr:sobj;
689
    }
690

691
    if(finalLink && linkedVp == vp->getLinkedViewProvider())
692
        return nullptr;
693

694
    auto linked = linkedVp->getObject();
695
    if(!linked || !linked->isAttachedToDocument())
696
        return nullptr;
697

698
    if(subname && sels[0].pObject!=sobj && sels[0].SubName) {
699
        bool found = false;
700
        int pre_len=0;
701
        std::size_t post_len=0;
702
        std::string prefix;
703
        std::string prefix2;
704
        // An object can be claimed by multiple objects. Let's try select one
705
        // that causes minimum jump in tree view, and prefer upper over lower
706
        // hierarchy (because of less depth/complexity of tree expansion)
707
        for(auto &v : linked->getParents()) {
708
            if(v.first != sels[0].pObject)
709
                continue;
710

711
            const char *sub = v.second.c_str();
712
            const char *dot = sub;
713
            for(const char *s=sels[0].SubName; *s && *sub==*s; ++s,++sub) {
714
                if(*sub == '.')
715
                    dot = sub;
716
            }
717
            found = true;
718
            if(dot-v.second.c_str() > pre_len
719
                    || (dot-v.second.c_str()==pre_len
720
                        && v.second.size()<post_len))
721
            {
722
                pre_len = dot-v.second.c_str();
723
                prefix = std::string(sels[0].SubName,pre_len) + (v.second.c_str()+pre_len);
724
                post_len = v.second.size();
725
            }else if(!pre_len) {
726
                if(prefix2.empty() || prefix2.size() > v.second.size())
727
                    prefix2 = v.second;
728
            }
729
        }
730

731
        if(found) {
732
            linked = sels[0].pObject;
733
            *subname = !prefix.empty()?prefix:prefix2 + *subname;
734
        }
735
    }
736

737
    return linked;
738
}
739

740
bool StdCmdLinkSelectLinked::isActive() {
741
    return getSelectedLink(false) != nullptr;
742
}
743

744
void StdCmdLinkSelectLinked::activated(int)
745
{
746
    std::string subname;
747
    auto linked = getSelectedLink(false,&subname);
748
    if(!linked){
749
        FC_WARN("invalid selection");
750
        return;
751
    }
752
    Selection().selStackPush();
753
    Selection().clearCompleteSelection();
754
    if(!subname.empty()) {
755
        Selection().addSelection(linked->getDocument()->getName(),linked->getNameInDocument(),subname.c_str());
756
        auto doc = Application::Instance->getDocument(linked->getDocument());
757
        if(doc) {
758
            auto vp = dynamic_cast<ViewProviderDocumentObject*>(Application::Instance->getViewProvider(linked));
759
            doc->setActiveView(vp);
760
        }
761
    } else {
762
        const auto trees = getMainWindow()->findChildren<TreeWidget*>();
763
        for(auto tree : trees)
764
            tree->selectLinkedObject(linked);
765
    }
766
    Selection().selStackPush();
767
}
768

769
////////////////////////////////////////////////////////////////////////////////////////////
770

771
DEF_STD_CMD_A(StdCmdLinkSelectLinkedFinal)
772

773
StdCmdLinkSelectLinkedFinal::StdCmdLinkSelectLinkedFinal()
774
  : Command("Std_LinkSelectLinkedFinal")
775
{
776
    sGroup        = "Link";
777
    sMenuText     = QT_TR_NOOP("Go to the deepest linked object");
778
    sToolTipText  = QT_TR_NOOP("Select the deepest linked object and switch to its owner document");
779
    sWhatsThis    = "Std_LinkSelectLinkedFinal";
780
    sStatusTip    = sToolTipText;
781
    eType         = AlterSelection;
782
    sPixmap       = "LinkSelectFinal";
783
    sAccel        = "S, D";
784
}
785

786
bool StdCmdLinkSelectLinkedFinal::isActive() {
787
    return getSelectedLink(true) != nullptr;
788
}
789

790
void StdCmdLinkSelectLinkedFinal::activated(int) {
791
    auto linked = getSelectedLink(true);
792
    if(!linked){
793
        FC_WARN("invalid selection");
794
        return;
795
    }
796
    Selection().selStackPush();
797
    Selection().clearCompleteSelection();
798
    const auto trees = getMainWindow()->findChildren<TreeWidget*>();
799
    for(auto tree : trees)
800
        tree->selectLinkedObject(linked);
801
    Selection().selStackPush();
802
}
803

804
////////////////////////////////////////////////////////////////////////////////////////////
805

806
DEF_STD_CMD_A(StdCmdLinkSelectAllLinks)
807

808
StdCmdLinkSelectAllLinks::StdCmdLinkSelectAllLinks()
809
  : Command("Std_LinkSelectAllLinks")
810
{
811
    sGroup        = "Link";
812
    sMenuText     = QT_TR_NOOP("Select all links");
813
    sToolTipText  = QT_TR_NOOP("Select all links to the current selected object");
814
    sWhatsThis    = "Std_LinkSelectAllLinks";
815
    sStatusTip    = sToolTipText;
816
    eType         = AlterSelection;
817
    sPixmap       = "LinkSelectAll";
818
}
819

820
bool StdCmdLinkSelectAllLinks::isActive() {
821
    const auto &sels = Selection().getSelection("*", ResolveMode::OldStyleElement, true);
822
    if(sels.empty())
823
        return false;
824
    return App::GetApplication().hasLinksTo(sels[0].pObject);
825
}
826

827
void StdCmdLinkSelectAllLinks::activated(int)
828
{
829
    auto sels = Selection().getSelection("*", ResolveMode::OldStyleElement, true);
830
    if(sels.empty())
831
        return;
832
    Selection().selStackPush();
833
    Selection().clearCompleteSelection();
834
    const auto trees = getMainWindow()->findChildren<TreeWidget*>();
835
    for(auto tree : trees)
836
        tree->selectAllLinks(sels[0].pObject);
837
    Selection().selStackPush();
838
}
839

840

841
//======================================================================
842
// Std_LinkSelectActions
843
//===========================================================================
844

845
class StdCmdLinkSelectActions : public GroupCommand
846
{
847
public:
848
    StdCmdLinkSelectActions()
849
        : GroupCommand("Std_LinkSelectActions")
850
    {
851
        sGroup        = "View";
852
        sMenuText     = QT_TR_NOOP("Link navigation");
853
        sToolTipText  = QT_TR_NOOP("Link navigation actions");
854
        sWhatsThis    = "Std_LinkSelectActions";
855
        sStatusTip    = QT_TR_NOOP("Link navigation actions");
856
        eType         = AlterSelection;
857
        bCanLog       = false;
858

859
        addCommand(new StdCmdLinkSelectLinked());
860
        addCommand(new StdCmdLinkSelectLinkedFinal());
861
        addCommand(new StdCmdLinkSelectAllLinks());
862
    }
863

864
    const char* className() const override {return "StdCmdLinkSelectActions";}
865
};
866

867
//======================================================================
868
// Std_LinkActions
869
//===========================================================================
870

871
class StdCmdLinkActions : public GroupCommand
872
{
873
public:
874
    StdCmdLinkActions()
875
        : GroupCommand("Std_LinkActions")
876
    {
877
        sGroup        = "View";
878
        sMenuText     = QT_TR_NOOP("Link actions");
879
        sToolTipText  = QT_TR_NOOP("Actions that apply to link objects");
880
        sWhatsThis    = "Std_LinkMakeRelative";
881
        sStatusTip    = QT_TR_NOOP("Actions that apply to link objects");
882
        eType         = AlterDoc;
883
        bCanLog       = false;
884

885
        addCommand(new StdCmdLinkMake());
886
        addCommand(new StdCmdLinkMakeRelative());
887
        addCommand(new StdCmdLinkReplace());
888
        addCommand(new StdCmdLinkUnlink());
889
        addCommand(new StdCmdLinkImport());
890
        addCommand(new StdCmdLinkImportAll());
891
    }
892

893
    const char* className() const override {return "StdCmdLinkActions";}
894
};
895

896
//===========================================================================
897
// Instantiation
898
//===========================================================================
899

900

901
namespace Gui {
902

903
void CreateLinkCommands()
904
{
905
    CommandManager &rcCmdMgr = Application::Instance->commandManager();
906
    rcCmdMgr.addCommand(new StdCmdLinkActions());
907
    rcCmdMgr.addCommand(new StdCmdLinkMakeGroup());
908
    rcCmdMgr.addCommand(new StdCmdLinkSelectActions());
909

910
}
911

912
} // namespace Gui
913

914

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

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

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

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