FreeCAD

Форк
0
/
WorkbenchManipulatorPython.cpp 
357 строк · 12.0 Кб
1
// SPDX-License-Identifier: LGPL-2.1-or-later
2

3
/***************************************************************************
4
 *   Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net>     *
5
 *                                                                         *
6
 *   This file is part of FreeCAD.                                         *
7
 *                                                                         *
8
 *   FreeCAD is free software: you can redistribute it and/or modify it    *
9
 *   under the terms of the GNU Lesser General Public License as           *
10
 *   published by the Free Software Foundation, either version 2.1 of the  *
11
 *   License, or (at your option) any later version.                       *
12
 *                                                                         *
13
 *   FreeCAD is distributed in the hope that it will be useful, but        *
14
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
16
 *   Lesser General Public License for more details.                       *
17
 *                                                                         *
18
 *   You should have received a copy of the GNU Lesser General Public      *
19
 *   License along with FreeCAD. If not, see                               *
20
 *   <https://www.gnu.org/licenses/>.                                      *
21
 *                                                                         *
22
 **************************************************************************/
23

24

25
#include "PreCompiled.h"
26
#include "WorkbenchManipulatorPython.h"
27
#include "MenuManager.h"
28
#include "ToolBarManager.h"
29
#include <Base/Interpreter.h>
30

31
using namespace Gui;
32

33
void WorkbenchManipulatorPython::installManipulator(const Py::Object& obj)
34
{
35
    auto manip = std::make_shared<WorkbenchManipulatorPython>(obj);
36
    WorkbenchManipulator::installManipulator(manip);
37
}
38

39
void WorkbenchManipulatorPython::removeManipulator(const Py::Object& obj)
40
{
41
    auto manip = getManipulators();
42
    for (const auto& it : manip) {
43
        auto ptr = std::dynamic_pointer_cast<WorkbenchManipulatorPython>(it);
44
        if (ptr && ptr->object == obj) {
45
            WorkbenchManipulator::removeManipulator(ptr);
46
            break;
47
        }
48
    }
49
}
50

51
WorkbenchManipulatorPython::WorkbenchManipulatorPython(const Py::Object& obj)
52
    : object(obj)
53
{
54
}
55

56
WorkbenchManipulatorPython::~WorkbenchManipulatorPython()
57
{
58
    Base::PyGILStateLocker lock;
59
    object = Py::None();
60
}
61

62
/*!
63
 * \brief WorkbenchManipulatorPython::modifyMenuBar
64
 * \param menuBar
65
 * The Python manipulator can be implemented as
66
 * \code
67
 * class Manipulator:
68
 *   def modifyMenuBar(self):
69
 *     return [{"remove" : "Std_Quit"},
70
 *             {"append" : "Std_About", "menuItem" : "Std_DlgMacroRecord"},
71
 *             {"insert" : "Std_About", "menuItem" : "Std_DlgParameter"}
72
 *             {"insert" : "Std_Windows", "menuItem" : "Std_DlgParameter", "after" : ""}]
73
 *
74
 * manip = Manipulator()
75
 * Gui.addWorkbenchManipulator(manip)
76
 * \endcode
77
 * This manipulator removes the Std_Quit command, appends the Std_About command
78
 * to the Macro menu, inserts it to the Tools menu before the Std_DlgParameter
79
 * and adds the Std_Windows after the Std_DlgParameter command.
80
 */
81
void WorkbenchManipulatorPython::modifyMenuBar(MenuItem* menuBar)
82
{
83
    Base::PyGILStateLocker lock;
84
    try {
85
        tryModifyMenuBar(menuBar);
86
    }
87
    catch (Py::Exception&) {
88
        Base::PyException exc; // extract the Python error text
89
        exc.ReportException();
90
    }
91
}
92

93
void WorkbenchManipulatorPython::tryModifyMenuBar(MenuItem* menuBar)
94
{
95
    if (object.hasAttr(std::string("modifyMenuBar"))) {
96
        Py::Callable method(object.getAttr(std::string("modifyMenuBar")));
97
        Py::Tuple args;
98
        Py::Object result = method.apply(args);
99
        if (result.isDict()) {
100
            tryModifyMenuBar(Py::Dict(result), menuBar);
101
        }
102
        else if (result.isSequence()) {
103
            Py::Sequence list(result);
104
            for (const auto& it : list) {
105
                if (it.isDict()) {
106
                    tryModifyMenuBar(Py::Dict(it), menuBar);
107
                }
108
            }
109
        }
110
    }
111
}
112

113
// NOLINTNEXTLINE
114
void WorkbenchManipulatorPython::tryModifyMenuBar(const Py::Dict& dict, MenuItem* menuBar)
115
{
116
    std::string insert("insert");
117
    std::string append("append");
118
    std::string remove("remove");
119

120
    // insert a new command
121
    if (dict.hasKey(insert)) {
122
        std::string command = static_cast<std::string>(Py::String(dict.getItem(insert)));
123
        std::string itemName = static_cast<std::string>(Py::String(dict.getItem("menuItem")));
124
        bool after = dict.hasKey(std::string("after"));
125

126
        if (auto par = menuBar->findParentOf(itemName)) {
127
            if (MenuItem* item = par->findItem(itemName)) {
128
                if (after) {
129
                    item = par->afterItem(item);
130
                }
131

132
                if (item) {
133
                    auto add = new MenuItem();  // NOLINT
134
                    add->setCommand(command);
135
                    par->insertItem(item, add);
136
                }
137
            }
138
        }
139
    }
140
    // append a command
141
    else if (dict.hasKey(append)) {
142
        std::string command = static_cast<std::string>(Py::String(dict.getItem(append)));
143
        std::string itemName = static_cast<std::string>(Py::String(dict.getItem("menuItem")));
144

145
        if (auto par = menuBar->findParentOf(itemName)) {
146
            auto add = new MenuItem();  // NOLINT
147
            add->setCommand(command);
148
            par->appendItem(add);
149
        }
150
    }
151
    // remove a command
152
    else if (dict.hasKey(remove)) {
153
        std::string command = static_cast<std::string>(Py::String(dict.getItem(remove)));
154
        if (auto par = menuBar->findParentOf(command)) {
155
            if (MenuItem* item = par->findItem(command)) {
156
                par->removeItem(item);
157
                delete item;  // NOLINT
158
            }
159
        }
160

161
    }
162
}
163

164
/*!
165
 * \brief WorkbenchManipulatorPython::modifyContextMenu
166
 * \param menuBar
167
 * The Python manipulator can be implemented as
168
 * \code
169
 * class Manipulator:
170
 *   def modifyContextMenu(self, recipient):
171
 *     if recipient == "View":
172
 *       return [{"remove" : "Standard views"},
173
 *               {"insert" : "Std_Windows", "menuItem" : "View_Measure_Toggle_All"}]
174
 *
175
 * manip = Manipulator()
176
 * Gui.addWorkbenchManipulator(manip)
177
 * \endcode
178
 * This manipulator removes the "Standard views sub-menu and
179
 * adds the Std_Windows before the View_Measure_Toggle_All command.
180
 */
181
void WorkbenchManipulatorPython::modifyContextMenu(const char* recipient, MenuItem* menuBar)
182
{
183
    Base::PyGILStateLocker lock;
184
    try {
185
        tryModifyContextMenu(recipient, menuBar);
186
    }
187
    catch (Py::Exception&) {
188
        Base::PyException exc; // extract the Python error text
189
        exc.ReportException();
190
    }
191
}
192

193
void WorkbenchManipulatorPython::tryModifyContextMenu(const char* recipient, MenuItem* menuBar)
194
{
195
    if (object.hasAttr(std::string("modifyContextMenu"))) {
196
        Py::Callable method(object.getAttr(std::string("modifyContextMenu")));
197
        Py::Tuple args(1);
198
        args.setItem(0, Py::String(recipient));
199
        Py::Object result = method.apply(args);
200
        if (result.isDict()) {
201
            tryModifyContextMenu(Py::Dict(result), menuBar);
202
        }
203
        else if (result.isSequence()) {
204
            Py::Sequence list(result);
205
            for (const auto& it : list) {
206
                if (it.isDict()) {
207
                    tryModifyContextMenu(Py::Dict(it), menuBar);
208
                }
209
            }
210
        }
211
    }
212
}
213

214
void WorkbenchManipulatorPython::tryModifyContextMenu(const Py::Dict& dict, MenuItem* menuBar)
215
{
216
    tryModifyMenuBar(dict, menuBar);
217
}
218

219
void WorkbenchManipulatorPython::modifyToolBars(ToolBarItem* toolBar)
220
{
221
    Base::PyGILStateLocker lock;
222
    try {
223
        tryModifyToolBar(toolBar);
224
    }
225
    catch (Py::Exception&) {
226
        Base::PyException exc; // extract the Python error text
227
        exc.ReportException();
228
    }
229
}
230

231
/*!
232
 * \brief WorkbenchManipulatorPython::tryModifyToolBar
233
 * \param toolBar
234
 * The Python manipulator can be implemented as
235
 * \code
236
 * class Manipulator:
237
 *   def modifyToolBars(self):
238
       return [{"remove" : "Macro"},
239
               {"append" : "Std_Quit", "toolBar" : "File"},
240
 *             {"insert" : "Std_Cut", "toolItem" : "Std_New"}]
241
 *
242
 * manip = Manipulator()
243
 * Gui.addWorkbenchManipulator(manip)
244
 * \endcode
245
 * This manipulator removes the Macro toolbar, adds the
246
 * Std_Quit to the File toolbar and adds Std_Cut the
247
 * command to the toolbar where Std_New is part of.
248
 */
249
void WorkbenchManipulatorPython::tryModifyToolBar(ToolBarItem* toolBar)
250
{
251
    if (object.hasAttr(std::string("modifyToolBars"))) {
252
        Py::Callable method(object.getAttr(std::string("modifyToolBars")));
253
        Py::Tuple args;
254
        Py::Object result = method.apply(args);
255
        if (result.isDict()) {
256
            tryModifyToolBar(Py::Dict(result), toolBar);
257
        }
258
        else if (result.isSequence()) {
259
            Py::Sequence list(result);
260
            for (const auto& it : list) {
261
                if (it.isDict()) {
262
                    tryModifyToolBar(Py::Dict(it), toolBar);
263
                }
264
            }
265
        }
266
    }
267
}
268

269
// NOLINTNEXTLINE
270
void WorkbenchManipulatorPython::tryModifyToolBar(const Py::Dict& dict, ToolBarItem* toolBar)
271
{
272
    std::string insert("insert");
273
    std::string append("append");
274
    std::string remove("remove");
275

276
    // insert a new command
277
    if (dict.hasKey(insert)) {
278

279
        std::string command = static_cast<std::string>(Py::String(dict.getItem(insert)));
280
        std::string itemName = static_cast<std::string>(Py::String(dict.getItem("toolItem")));
281

282
        for (auto it : toolBar->getItems()) {
283
            if (ToolBarItem* item = it->findItem(itemName)) {
284
                auto add = new ToolBarItem();  // NOLINT
285
                add->setCommand(command);
286
                it->insertItem(item, add);
287
                break;
288
            }
289
        }
290
    }
291
    // append a command
292
    else if (dict.hasKey(append)) {
293
        std::string command = static_cast<std::string>(Py::String(dict.getItem(append)));
294
        std::string itemName = static_cast<std::string>(Py::String(dict.getItem("toolBar")));
295

296
        if (ToolBarItem* item = toolBar->findItem(itemName)) {
297
            auto add = new ToolBarItem();  // NOLINT
298
            add->setCommand(command);
299
            item->appendItem(add);
300
        }
301
    }
302
    // remove a command or toolbar
303
    else if (dict.hasKey(remove)) {
304
        std::string command = static_cast<std::string>(Py::String(dict.getItem(remove)));
305

306
        if (ToolBarItem* item = toolBar->findItem(command)) {
307
            toolBar->removeItem(item);
308
            delete item;  // NOLINT
309
        }
310
        else {
311
            for (auto it : toolBar->getItems()) {
312
                if (ToolBarItem* item = it->findItem(command)) {
313
                    it->removeItem(item);
314
                    delete item;  // NOLINT
315
                    break;
316
                }
317
            }
318
        }
319
    }
320
}
321

322
void WorkbenchManipulatorPython::modifyDockWindows(DockWindowItems* dockWindow)
323
{
324
    Base::PyGILStateLocker lock;
325
    try {
326
        tryModifyDockWindows(dockWindow);
327
    }
328
    catch (Py::Exception&) {
329
        Base::PyException exc; // extract the Python error text
330
        exc.ReportException();
331
    }
332
}
333

334
void WorkbenchManipulatorPython::tryModifyDockWindows(DockWindowItems* dockWindow)
335
{
336
    if (object.hasAttr(std::string("modifyDockWindows"))) {
337
        Py::Callable method(object.getAttr(std::string("modifyDockWindows")));
338
        Py::Tuple args;
339
        Py::Object result = method.apply(args);
340
        if (result.isDict()) {
341
            tryModifyDockWindows(Py::Dict(result), dockWindow);
342
        }
343
        else if (result.isSequence()) {
344
            Py::Sequence list(result);
345
            for (const auto& it : list) {
346
                if (it.isDict()) {
347
                    tryModifyDockWindows(Py::Dict(it), dockWindow);
348
                }
349
            }
350
        }
351
    }
352
}
353

354
void WorkbenchManipulatorPython::tryModifyDockWindows([[maybe_unused]]const Py::Dict& dict,
355
                                                      [[maybe_unused]]DockWindowItems* dockWindow)
356
{
357
}
358

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

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

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

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