24
#include "PreCompiled.h"
26
# include <QActionGroup>
27
# include <QApplication>
31
# include <QCloseEvent>
32
# include <QContextMenuEvent>
33
# include <QDesktopServices>
34
# include <QDockWidget>
35
# include <QFontMetrics>
36
# include <QKeySequence>
38
# include <QMdiSubWindow>
41
# include <QMessageBox>
44
# include <QRegularExpression>
45
# include <QRegularExpressionMatch>
48
# include <QSignalMapper>
56
# include <QPushButton>
60
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
61
#include <QtPlatformHeaders/QWindowsWindowFunctions>
63
#include <qpa/qplatformwindow_p.h>
67
#include <boost/algorithm/string/predicate.hpp>
69
#include <App/Application.h>
70
#include <App/Document.h>
71
#include <App/DocumentObject.h>
72
#include <App/DocumentObjectGroup.h>
73
#include <Base/ConsoleObserver.h>
74
#include <Base/Parameter.h>
75
#include <Base/Exception.h>
76
#include <Base/FileInfo.h>
77
#include <Base/Interpreter.h>
78
#include <Base/Stream.h>
79
#include <Base/Tools.h>
80
#include <Base/UnitsApi.h>
81
#include <DAGView/DAGView.h>
82
#include <TaskView/TaskView.h>
84
#include "MainWindow.h"
87
#include "BitmapFactory.h"
90
#include "DockWindowManager.h"
91
#include "DownloadManager.h"
92
#include "FileDialog.h"
93
#include "MenuManager.h"
94
#include "NotificationArea.h"
95
#include "OverlayManager.h"
96
#include "ProgressBar.h"
97
#include "PropertyView.h"
98
#include "PythonConsole.h"
99
#include "ReportView.h"
100
#include "SelectionView.h"
101
#include "Splashscreen.h"
102
#include "ToolBarManager.h"
103
#include "ToolBoxManager.h"
105
#include "WaitCursor.h"
106
#include "WorkbenchManager.h"
107
#include "Workbench.h"
109
#include "MergeDocuments.h"
110
#include "ViewProviderExtern.h"
112
#include "SpaceballEvent.h"
113
#include "View3DInventor.h"
114
#include "View3DInventorViewer.h"
115
#include "DlgObjectSelection.h"
117
#include <App/Color.h>
119
FC_LOG_LEVEL_INIT("MainWindow",false,true,true)
121
#if defined(Q_OS_WIN32)
126
using namespace Gui::DockWnd;
130
MainWindow* MainWindow::instance = nullptr;
142
class CustomMessageEvent : public QEvent
145
CustomMessageEvent(int t, const QString& s, int timeout=0)
146
: QEvent(QEvent::User), _type(t), msg(s), _timeout(timeout)
148
~CustomMessageEvent() override = default;
151
const QString& message() const
166
class DimensionWidget : public QPushButton, WindowParameter
171
explicit DimensionWidget(QWidget* parent): QPushButton(parent), WindowParameter("Units")
174
setText(qApp->translate("Gui::MainWindow", "Dimension"));
175
setMinimumWidth(120);
178
auto* menu = new QMenu(this);
179
auto* actionGrp = new QActionGroup(menu);
180
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes);
181
for (int i = 0; i < num; i++) {
182
QAction* action = menu->addAction(QStringLiteral("UnitSchema%1").arg(i));
183
actionGrp->addAction(action);
184
action->setCheckable(true);
187
QObject::connect(actionGrp, &QActionGroup::triggered, this, [this](QAction* action) {
188
int userSchema = action->data().toInt();
189
setUserSchema(userSchema);
191
const auto views = getMainWindow()->findChildren<PropertyView*>();
192
for(auto view : views) {
193
bool show = view->showAll();
194
view->setShowAll(!show);
195
view->setShowAll(show);
201
getWindowParameter()->Attach(this);
204
~DimensionWidget() override
206
getWindowParameter()->Detach(this);
209
void OnChange(Base::Subject<const char*> &rCaller, const char * sReason) override
212
if (strcmp(sReason, "UserSchema") == 0) {
217
void changeEvent(QEvent *event) override
219
if (event->type() == QEvent::LanguageChange) {
223
QPushButton::changeEvent(event);
227
void setUserSchema(int userSchema)
229
App::Document* doc = App::GetApplication().getActiveDocument();
230
if ( doc != nullptr ) {
231
if (doc->UnitSystem.getValue() != userSchema )
232
doc->UnitSystem.setValue(userSchema);
234
getWindowParameter()->SetInt("UserSchema", userSchema);
237
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(userSchema));
239
Gui::Application::Instance->onUpdate();
245
ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath
246
("User parameter:BaseApp/Preferences/Units");
247
bool ignore = hGrpu->GetBool("IgnoreProjectSchema", false);
248
App::Document* doc = App::GetApplication().getActiveDocument();
249
int userSchema = getWindowParameter()->GetInt("UserSchema", 0);
250
if ( doc != nullptr && ! ignore) {
251
userSchema = doc->UnitSystem.getValue();
253
auto actions = menu()->actions();
254
if(Q_UNLIKELY(userSchema < 0 || userSchema >= actions.size())) {
257
actions[userSchema]->setChecked(true);
260
void retranslateUi() {
261
auto actions = menu()->actions();
262
int maxSchema = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes);
263
assert(actions.size() <= maxSchema);
264
for(int i = 0; i < maxSchema ; i++)
266
actions[i]->setText(Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i)));
275
DimensionWidget* sizeLabel;
277
QLabel* rightSideLabel;
280
QTimer* activityTimer;
281
QTimer saveStateTimer;
282
QTimer restoreStateTimer;
284
QPointer<MDIView> activeView;
285
QSignalMapper* windowMapper;
286
SplashScreen* splashscreen;
287
StatusBarObserver* status;
290
Assistant* assistant;
291
int currentStatusType = 100;
292
int actionUpdateDelay = 0;
293
QMap<QString, QPointer<UrlHandler> > urlHandler;
294
std::string hiddenDockWindows;
295
boost::signals2::scoped_connection connParam;
296
ParameterGrp::handle hGrp;
297
bool _restoring = false;
299
void restoreWindowState(const QByteArray &);
302
class MDITabbar : public QTabBar
305
explicit MDITabbar( QWidget * parent = nullptr ) : QTabBar(parent)
307
menu = new QMenu(this);
309
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
312
~MDITabbar() override
318
void contextMenuEvent ( QContextMenuEvent * e ) override
321
CommandManager& cMgr = Application::Instance->commandManager();
322
if (tabRect(currentIndex()).contains(e->pos()))
323
cMgr.getCommandByName("Std_CloseActiveWindow")->addTo(menu);
324
cMgr.getCommandByName("Std_CloseAllWindows")->addTo(menu);
325
menu->addSeparator();
326
cMgr.getCommandByName("Std_CascadeWindows")->addTo(menu);
327
cMgr.getCommandByName("Std_TileWindows")->addTo(menu);
328
menu->addSeparator();
329
cMgr.getCommandByName("Std_Windows")->addTo(menu);
330
menu->popup(e->globalPos());
337
#if defined(Q_OS_WIN32)
338
class MainWindowTabBar : public QTabBar
341
MainWindowTabBar(QWidget *parent) : QTabBar(parent)
346
bool event(QEvent *e)
349
if (e->type() != QEvent::ToolTip)
350
return QTabBar::event(e);
351
QSize size = this->size();
352
QSize hint = sizeHint();
353
if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
357
if (size.width() < hint.width())
358
return QTabBar::event(e);
362
void tabInserted (int index)
365
QList<QDockWidget*> dw = getMainWindow()->findChildren<QDockWidget*>();
366
for (QList<QDockWidget*>::iterator it = dw.begin(); it != dw.end(); ++it) {
368
if (this->tabText(index) == (*it)->windowTitle()) {
369
QWidget* dock = (*it)->widget();
371
QIcon icon = dock->windowIcon();
373
setTabIcon(index, icon);
386
MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags f)
387
: QMainWindow( parent, f )
390
d->splashscreen = nullptr;
391
d->activeView = nullptr;
392
d->whatsthis = false;
393
d->assistant = new Assistant();
395
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
400
new QOpenGLWidget(this);
406
d->connParam = App::GetApplication().GetUserParameter().signalParamChanged.connect(
407
[this](ParameterGrp *Param, ParameterGrp::ParamType, const char *Name, const char *) {
408
if (Param != d->hGrp || !Name)
410
if (boost::equals(Name, "StatusBar")) {
411
if(auto sb = getMainWindow()->statusBar())
412
sb->setVisible(d->hGrp->GetBool("StatusBar", sb->isVisible()));
414
else if (boost::equals(Name, "MainWindowState")) {
415
OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadPause);
416
d->restoreStateTimer.start(100);
420
d->hGrp = App::GetApplication().GetParameterGroupByPath(
421
"User parameter:BaseApp/Preferences/MainWindow");
422
d->saveStateTimer.setSingleShot(true);
423
connect(&d->saveStateTimer, &QTimer::timeout, [this](){this->saveWindowSettings();});
425
d->restoreStateTimer.setSingleShot(true);
426
connect(&d->restoreStateTimer, &QTimer::timeout, [this](){
427
d->restoreWindowState(QByteArray::fromBase64(d->hGrp->GetASCII("MainWindowState").c_str()));
428
ToolBarManager::getInstance()->restoreState();
429
OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadResume);
434
setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
437
d->mdiArea = new QMdiArea();
439
d->mdiArea->setTabsMovable(true);
440
d->mdiArea->setTabPosition(QTabWidget::South);
441
d->mdiArea->setViewMode(QMdiArea::TabbedView);
442
auto tab = d->mdiArea->findChild<QTabBar*>();
444
tab->setTabsClosable(true);
446
tab->setExpanding(false);
447
tab->setObjectName(QString::fromLatin1("mdiAreaTabBar"));
449
d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
450
d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
451
d->mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, false);
452
d->mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder);
453
d->mdiArea->setBackground(QBrush(QColor(160,160,160)));
454
setCentralWidget(d->mdiArea);
456
statusBar()->setObjectName(QString::fromLatin1("statusBar"));
457
connect(statusBar(), &QStatusBar::messageChanged, this, &MainWindow::statusMessageChanged);
460
d->status = new StatusBarObserver();
461
d->actionLabel = new QLabel(statusBar());
462
d->actionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
465
d->sizeLabel = new DimensionWidget(statusBar());
467
statusBar()->addWidget(d->actionLabel, 1);
468
QProgressBar* progressBar = Gui::SequencerBar::instance()->getProgressBar(statusBar());
469
statusBar()->addPermanentWidget(progressBar, 0);
470
statusBar()->addPermanentWidget(d->sizeLabel, 0);
472
d->rightSideLabel = new QLabel(statusBar());
473
d->rightSideLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
474
statusBar()->addPermanentWidget(d->rightSideLabel);
476
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/NotificationArea");
478
auto notificationAreaEnabled = hGrp->GetBool("NotificationAreaEnabled", true);
480
if(notificationAreaEnabled) {
481
NotificationArea* notificationArea = new NotificationArea(statusBar());
482
notificationArea->setObjectName(QString::fromLatin1("notificationArea"));
483
notificationArea->setStyleSheet(QStringLiteral("text-align:left;"));
484
statusBar()->addPermanentWidget(notificationArea);
488
d->actionTimer = new QTimer( this );
489
d->actionTimer->setObjectName(QString::fromLatin1("actionTimer"));
490
connect(d->actionTimer, &QTimer::timeout, d->actionLabel, &QLabel::clear);
493
d->statusTimer = new QTimer( this );
494
d->statusTimer->setObjectName(QString::fromLatin1("statusTimer"));
495
connect(d->statusTimer, &QTimer::timeout, this, &MainWindow::clearStatus);
498
d->activityTimer = new QTimer(this);
499
d->activityTimer->setObjectName(QString::fromLatin1("activityTimer"));
500
connect(d->activityTimer, &QTimer::timeout, this, &MainWindow::_updateActions);
501
d->activityTimer->setSingleShot(false);
502
d->activityTimer->start(150);
505
QClipboard *clipbd = QApplication::clipboard();
506
connect(clipbd, &QClipboard::dataChanged, this, &MainWindow::updateEditorActions);
508
d->windowMapper = new QSignalMapper(this);
511
#if QT_VERSION < QT_VERSION_CHECK(5,15,0)
512
connect(d->windowMapper, qOverload<QWidget*>(&QSignalMapper::mapped),
513
this, &MainWindow::onSetActiveSubWindow);
514
#elif QT_VERSION < QT_VERSION_CHECK(6,0,0)
515
connect(d->windowMapper, &QSignalMapper::mappedWidget,
516
this, &MainWindow::onSetActiveSubWindow);
518
connect(d->windowMapper, &QSignalMapper::mappedObject,
519
this, [=](QObject* object) {
520
onSetActiveSubWindow(qobject_cast<QWidget*>(object));
523
connect(d->mdiArea, &QMdiArea::subWindowActivated,
524
this, &MainWindow::onWindowActivated);
529
setAcceptDrops(true);
531
statusBar()->showMessage(tr("Ready"), 2001);
534
MainWindow::~MainWindow()
541
MainWindow* MainWindow::getInstance()
550
static inline void _updateDockWidget(const char *name,
553
Qt::DockWidgetArea pos,
556
auto pDockMgr = DockWindowManager::instance();
557
auto widget = pDockMgr->findRegisteredDockWindow(name);
560
pDockMgr->removeDockWindow(widget);
561
pDockMgr->unregisterDockWindow(name);
562
widget->deleteLater();
567
widget = callback(widget);
570
DockWindowManager::instance()->registerDockWindow(name, widget);
572
auto dock = pDockMgr->addDockWindow(
573
widget->objectName().toUtf8().constData(), widget, pos);
575
if(!dock->toggleViewAction()->isChecked())
576
dock->toggleViewAction()->activate(QAction::Trigger);
577
OverlayManager::instance()->refresh(dock);
582
void MainWindow::initDockWindows(bool show)
584
updateTreeView(show);
585
updatePropertyView(show);
586
updateComboView(show);
587
updateTaskView(show);
591
void MainWindow::setupDockWindows()
595
setupPythonConsole();
596
setupSelectionView();
599
initDockWindows(false);
601
std::vector<QTabWidget::TabPosition> tabPos = {QTabWidget::North,
605
long value = d->hGrp->GetInt("LeftDockWidgetAreaTabPos", long(tabPos.front()));
606
if (value >= 0 && value < long(tabPos.size())) {
607
setTabPosition(Qt::LeftDockWidgetArea, tabPos[value]);
611
bool MainWindow::setupTaskView()
614
if (d->hiddenDockWindows.find("Std_TaskView") == std::string::npos) {
616
auto group = App::GetApplication().GetUserParameter()
618
->GetGroup("Preferences")
619
->GetGroup("DockWindows")
620
->GetGroup("TaskView");
622
auto taskView = new Gui::TaskView::TaskView(this);
623
bool restore = group->GetBool("RestoreWidth", taskView->shouldRestoreWidth());
624
taskView->setRestoreWidth(restore);
625
taskView->setObjectName(QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Tasks")));
626
taskView->setMinimumWidth(210);
628
DockWindowManager* pDockMgr = DockWindowManager::instance();
629
pDockMgr->registerDockWindow("Std_TaskView", taskView);
636
bool MainWindow::setupSelectionView()
639
if (d->hiddenDockWindows.find("Std_SelectionView") == std::string::npos) {
640
auto pcSelectionView = new SelectionView(nullptr, this);
641
pcSelectionView->setObjectName
642
(QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Selection view")));
643
pcSelectionView->setMinimumWidth(210);
645
DockWindowManager* pDockMgr = DockWindowManager::instance();
646
pDockMgr->registerDockWindow("Std_SelectionView", pcSelectionView);
653
bool MainWindow::setupReportView()
656
if (d->hiddenDockWindows.find("Std_ReportView") == std::string::npos) {
657
auto pcReport = new ReportOutput(this);
658
pcReport->setWindowIcon(BitmapFactory().pixmap("MacroEditor"));
659
pcReport->setObjectName
660
(QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Report view")));
662
DockWindowManager* pDockMgr = DockWindowManager::instance();
663
pDockMgr->registerDockWindow("Std_ReportView", pcReport);
665
auto rvObserver = new ReportOutputObserver(pcReport);
666
qApp->installEventFilter(rvObserver);
673
bool MainWindow::setupPythonConsole()
676
if (d->hiddenDockWindows.find("Std_PythonView") == std::string::npos) {
677
auto pcPython = new PythonConsole(this);
678
pcPython->setWindowIcon(Gui::BitmapFactory().iconFromTheme("applications-python"));
679
pcPython->setObjectName
680
(QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Python console")));
682
DockWindowManager* pDockMgr = DockWindowManager::instance();
683
pDockMgr->registerDockWindow("Std_PythonView", pcPython);
690
bool MainWindow::updateTreeView(bool show)
692
if (d->hiddenDockWindows.find("Std_TreeView") == std::string::npos) {
693
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
694
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("TreeView");
695
bool enabled = group->GetBool("Enabled", false);
696
_updateDockWidget("Std_TreeView", enabled, show, Qt::RightDockWidgetArea,
697
[](QWidget *widget) {
702
auto tree = new TreeDockWidget(0,getMainWindow());
703
tree->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Tree view")));
704
tree->setMinimumWidth(210);
715
bool MainWindow::updatePropertyView(bool show)
718
if (d->hiddenDockWindows.find("Std_PropertyView") == std::string::npos) {
719
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
720
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("PropertyView");
721
bool enabled = group->GetBool("Enabled", false);
722
_updateDockWidget("Std_PropertyView", enabled, show, Qt::RightDockWidgetArea,
723
[](QWidget *widget) {
728
auto pcPropView = new PropertyDockView(0, getMainWindow());
729
pcPropView->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Property view")));
730
pcPropView->setMinimumWidth(210);
741
bool MainWindow::updateTaskView(bool show)
744
if (d->hiddenDockWindows.find("Std_TaskWatcher") == std::string::npos) {
746
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
747
GetGroup("BaseApp/Preferences/DockWindows/TaskWatcher");
748
bool enabled = group->GetBool("Enabled", false);
749
group->SetBool("Enabled", enabled);
750
_updateDockWidget("Std_TaskWatcher", enabled, show, Qt::RightDockWidgetArea,
751
[](QWidget *widget) {
756
widget = new TaskView::TaskView(getMainWindow());
757
widget->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Task List")));
767
bool MainWindow::updateComboView(bool show)
770
if (d->hiddenDockWindows.find("Std_ComboView") == std::string::npos) {
771
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
772
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("ComboView");
773
bool enable = group->GetBool("Enabled", true);
774
_updateDockWidget("Std_ComboView", enable, show, Qt::LeftDockWidgetArea,
775
[](QWidget *widget) {
776
auto pcComboView = qobject_cast<ComboView*>(widget);
781
pcComboView = new ComboView(nullptr, getMainWindow());
782
pcComboView->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget", "Model")));
783
pcComboView->setMinimumWidth(150);
784
widget = pcComboView;
794
bool MainWindow::updateDAGView(bool show)
797
if (d->hiddenDockWindows.find("Std_DAGView") == std::string::npos) {
798
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
799
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("DAGView");
800
bool enabled = group->GetBool("Enabled", false);
801
_updateDockWidget("Std_DAGView", enabled, show, Qt::RightDockWidgetArea,
802
[](QWidget *widget) {
807
auto dagDockWindow = new DAG::DockWindow(nullptr, getMainWindow());
808
dagDockWindow->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","DAG View")));
809
widget = dagDockWindow;
819
QMenu* MainWindow::createPopupMenu ()
821
QMenu *menu = new QMenu(this);
822
populateDockWindowMenu(menu);
823
menu->addSeparator();
824
populateToolBarMenu(menu);
825
menu->addSeparator();
826
Workbench* wb = WorkbenchManager::instance()->active();
829
wb->createMainWindowPopupMenu(&item);
830
if (item.hasItems()) {
831
menu->addSeparator();
832
QList<MenuItem*> items = item.getItems();
833
for (const auto & item : items) {
834
if (item->command() == "Separator") {
835
menu->addSeparator();
838
Command* cmd = Application::Instance->commandManager().getCommandByName(item->command().c_str());
839
if (cmd) cmd->addTo(menu);
848
void MainWindow::tile()
850
d->mdiArea->tileSubWindows();
853
void MainWindow::cascade()
855
d->mdiArea->cascadeSubWindows();
858
void MainWindow::closeActiveWindow ()
860
d->mdiArea->closeActiveSubWindow();
863
int MainWindow::confirmSave(const char *docName, QWidget *parent, bool addCheckbox) {
864
QMessageBox box(parent?parent:this);
865
box.setIcon(QMessageBox::Question);
866
box.setWindowFlags(box.windowFlags() | Qt::WindowStaysOnTopHint);
867
box.setWindowTitle(QObject::tr("Unsaved document"));
869
box.setText(QObject::tr("Do you want to save your changes to document '%1' before closing?")
870
.arg(QString::fromUtf8(docName)));
872
box.setText(QObject::tr("Do you want to save your changes to document before closing?"));
874
box.setInformativeText(QObject::tr("If you don't save, your changes will be lost."));
875
box.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save);
876
box.setDefaultButton(QMessageBox::Save);
877
box.setEscapeButton(QMessageBox::Cancel);
879
QCheckBox checkBox(QObject::tr("Apply answer to all"));
880
ParameterGrp::handle hGrp;
882
hGrp = App::GetApplication().GetUserParameter().
883
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General");
884
checkBox.setChecked(hGrp->GetBool("ConfirmAll",false));
885
checkBox.blockSignals(true);
886
box.addButton(&checkBox, QMessageBox::ResetRole);
890
QAbstractButton* saveBtn = box.button(QMessageBox::Save);
891
if (saveBtn->shortcut().isEmpty()) {
892
QString text = saveBtn->text();
893
text.prepend(QLatin1Char('&'));
894
saveBtn->setShortcut(QKeySequence::mnemonic(text));
897
QAbstractButton* discardBtn = box.button(QMessageBox::Discard);
898
if (discardBtn->shortcut().isEmpty()) {
899
QString text = discardBtn->text();
900
text.prepend(QLatin1Char('&'));
901
discardBtn->setShortcut(QKeySequence::mnemonic(text));
904
int res = ConfirmSaveResult::Cancel;
908
case QMessageBox::Save:
909
res = checkBox.isChecked()?ConfirmSaveResult::SaveAll:ConfirmSaveResult::Save;
911
case QMessageBox::Discard:
912
res = checkBox.isChecked()?ConfirmSaveResult::DiscardAll:ConfirmSaveResult::Discard;
915
if(addCheckbox && res)
916
hGrp->SetBool("ConfirmAll",checkBox.isChecked());
920
bool MainWindow::closeAllDocuments (bool close)
922
auto docs = App::GetApplication().getDocuments();
924
docs = App::Document::getDependentDocuments(docs, true);
926
catch(Base::Exception &e) {
930
bool checkModify = true;
931
bool saveAll = false;
934
for (auto doc : docs) {
935
auto gdoc = Application::Instance->getDocument(doc);
938
if (!gdoc->canClose(false))
940
if (!gdoc->isModified()
941
|| doc->testStatus(App::Document::PartialDoc)
942
|| doc->testStatus(App::Document::TempDoc))
945
if (!save && checkModify) {
946
int res = confirmSave(doc->Label.getStrValue().c_str(), this, docs.size()>1);
949
case ConfirmSaveResult::Cancel:
951
case ConfirmSaveResult::SaveAll:
954
case ConfirmSaveResult::Save:
957
case ConfirmSaveResult::DiscardAll:
962
if (save && !gdoc->save())
966
if (failedSaves > 0) {
967
int ret = QMessageBox::question(
969
QObject::tr("%1 Document(s) not saved").arg(QString::number(failedSaves)),
970
QObject::tr("Some documents could not be saved. Do you want to cancel closing?"),
971
QMessageBox::Discard | QMessageBox::Cancel,
972
QMessageBox::Discard);
973
if (ret == QMessageBox::Cancel)
978
App::GetApplication().closeAllDocuments();
983
void MainWindow::activateNextWindow ()
985
auto tab = d->mdiArea->findChild<QTabBar*>();
986
if (tab && tab->count() > 0) {
987
int index = (tab->currentIndex() + 1) % tab->count();
988
tab->setCurrentIndex(index);
992
void MainWindow::activatePreviousWindow ()
994
auto tab = d->mdiArea->findChild<QTabBar*>();
995
if (tab && tab->count() > 0) {
996
int index = (tab->currentIndex() + tab->count() - 1) % tab->count();
997
tab->setCurrentIndex(index);
1001
void MainWindow::activateWorkbench(const QString& name)
1003
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
1004
bool saveWB = hGrp->GetBool("SaveWBbyTab", false);
1005
QMdiSubWindow* subWin = d->mdiArea->activeSubWindow();
1006
if (subWin && saveWB) {
1007
QString currWb = subWin->property("ownWB").toString();
1008
if (currWb.isEmpty() || currWb != name) {
1009
subWin->setProperty("ownWB", name);
1013
Q_EMIT workbenchActivated(name);
1014
updateActions(true);
1017
void MainWindow::whatsThis()
1019
QWhatsThis::enterWhatsThisMode();
1022
void MainWindow::showDocumentation(const QString& help)
1024
Base::PyGILStateLocker lock;
1026
PyObject* module = PyImport_ImportModule("Help");
1029
Gui::Command::addModule(Gui::Command::Gui,"Help");
1030
Gui::Command::doCommand(Gui::Command::Gui,"Help.show(\"%s\")", help.toStdString().c_str());
1033
catch (const Base::Exception& e) {
1034
e.ReportException();
1038
bool MainWindow::event(QEvent *e)
1040
if (e->type() == QEvent::EnterWhatsThisMode) {
1045
d->whatstext.clear();
1046
if (!d->whatsthis) {
1047
d-> whatsthis = true;
1048
qApp->installEventFilter(this);
1051
else if (e->type() == QEvent::LeaveWhatsThisMode) {
1056
else if (e->type() == QEvent::WhatsThisClicked) {
1057
auto wt = static_cast<QWhatsThisClickedEvent*>(e);
1058
showDocumentation(wt->href());
1060
else if (e->type() == QEvent::ApplicationWindowIconChange) {
1062
this->setWindowIcon(QApplication::windowIcon());
1063
Command* about = Application::Instance->commandManager().getCommandByName("Std_About");
1065
Action* action = about->getAction();
1066
if (action) action->setIcon(QApplication::windowIcon());
1069
else if (e->type() == Spaceball::ButtonEvent::ButtonEventType) {
1070
auto buttonEvent = dynamic_cast<Spaceball::ButtonEvent *>(e);
1073
buttonEvent->setHandled(true);
1075
if (buttonEvent->buttonStatus() != Spaceball::BUTTON_PRESSED)
1077
ParameterGrp::handle group = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
1078
GetGroup("Spaceball")->GetGroup("Buttons");
1079
QByteArray groupName(QVariant(buttonEvent->buttonNumber()).toByteArray());
1080
if (group->HasGroup(groupName.data())) {
1081
ParameterGrp::handle commandGroup = group->GetGroup(groupName.data());
1082
std::string commandName(commandGroup->GetASCII("Command"));
1083
if (commandName.empty())
1086
Application::Instance->commandManager().runCommandByName(commandName.c_str());
1091
else if (e->type() == Spaceball::MotionEvent::MotionEventType) {
1092
auto motionEvent = dynamic_cast<Spaceball::MotionEvent *>(e);
1095
motionEvent->setHandled(true);
1096
Gui::Document *doc = Application::Instance->activeDocument();
1099
auto temp = dynamic_cast<View3DInventor *>(doc->getActiveView());
1102
View3DInventorViewer *view = temp->getViewer();
1104
Spaceball::MotionEvent anotherEvent(*motionEvent);
1105
qApp->sendEvent(view, &anotherEvent);
1108
}else if(e->type() == QEvent::StatusTip) {
1110
if(std::abs(d->currentStatusType) <= MainWindow::Wrn)
1113
return QMainWindow::event(e);
1116
bool MainWindow::eventFilter(QObject* o, QEvent* e)
1119
if (e->type() == QEvent::WindowStateChange) {
1122
auto view = qobject_cast<MDIView*>(o);
1124
Qt::WindowStates oldstate = static_cast<QWindowStateChangeEvent*>(e)->oldState();
1125
Qt::WindowStates newstate = view->windowState();
1126
if (oldstate != newstate)
1127
Q_EMIT windowStateChanged(view);
1135
if (e->type() == QEvent::WhatsThis) {
1136
if (!o->isWidgetType())
1139
auto w = static_cast<QWidget *>(o);
1140
d->whatstext = w->whatsThis();
1142
if (e->type() == QEvent::WhatsThisClicked) {
1144
if (o->isWidgetType() && qobject_cast<QWidget*>(o)->isWindow()) {
1146
QApplication::sendEvent(this, e);
1151
if (o->inherits("QMenu") && QWhatsThis::inWhatsThisMode()) {
1152
bool whatthis = false;
1153
if (e->type() == QEvent::KeyPress) {
1154
auto ke = static_cast<QKeyEvent*>(e);
1155
if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_F1)
1158
else if (e->type() == QEvent::MouseButtonRelease)
1160
else if (e->type() == QEvent::EnterWhatsThisMode)
1163
QAction* cur = static_cast<QMenu*>(o)->activeAction();
1166
QString s = cur->whatsThis();
1168
s = static_cast<QMenu*>(o)->whatsThis();
1173
if (o->inherits("QWhatsThat") && e->type() == QEvent::Show) {
1176
if (!d->whatstext.isEmpty()) {
1177
QWhatsThisClickedEvent e(d->whatstext);
1178
QApplication::sendEvent(this, &e);
1180
static_cast<QWidget *>(o)->setAttribute(Qt::WA_OutsideWSRange);
1184
if (o->inherits("QWhatsThat") && e->type() == QEvent::Hide) {
1187
d->whatsthis = false;
1188
d->whatstext.clear();
1189
qApp->removeEventFilter(this);
1194
return QMainWindow::eventFilter(o, e);
1197
void MainWindow::addWindow(MDIView* view)
1200
bool isempty = d->mdiArea->subWindowList().isEmpty();
1201
auto child = qobject_cast<QMdiSubWindow*>(view->parentWidget());
1203
child = new QMdiSubWindow(d->mdiArea->viewport());
1204
child->setAttribute(Qt::WA_DeleteOnClose);
1205
child->setWidget(view);
1206
child->setWindowIcon(view->windowIcon());
1207
QMenu* menu = child->systemMenu();
1210
QList<QAction*> acts = menu->actions();
1211
for (auto & act : acts) {
1212
if (act->shortcut() == QKeySequence(QKeySequence::Close)) {
1213
act->setShortcuts(QList<QKeySequence>());
1218
QAction* action = menu->addAction(tr("Close All"));
1219
connect(action, &QAction::triggered, d->mdiArea, &QMdiArea::closeAllSubWindows);
1220
d->mdiArea->addSubWindow(child);
1223
connect(view, &MDIView::message, this, &MainWindow::showMessage);
1224
connect(this, &MainWindow::windowStateChanged, view, &MDIView::windowStateChanged);
1227
view->installEventFilter(this);
1231
view->showMaximized();
1242
void MainWindow::removeWindow(Gui::MDIView* view, bool close)
1245
disconnect(view, &MDIView::message, this, &MainWindow::showMessage);
1246
disconnect(this, &MainWindow::windowStateChanged, view, &MDIView::windowStateChanged);
1248
view->removeEventFilter(this);
1251
QWidget* foc = this->focusWidget();
1253
QWidget* par = foc->parentWidget();
1259
par = par->parentWidget();
1263
QWidget* parent = view->parentWidget();
1274
auto subwindow = qobject_cast<QMdiSubWindow*>(parent);
1275
if(subwindow && d->mdiArea->subWindowList().contains(subwindow)) {
1276
subwindow->setParent(nullptr);
1278
assert(!d->mdiArea->subWindowList().contains(subwindow));
1283
parent->deleteLater();
1287
void MainWindow::tabChanged(MDIView* view)
1293
void MainWindow::tabCloseRequested(int index)
1295
auto tab = d->mdiArea->findChild<QTabBar*>();
1296
if (index < 0 || index >= tab->count())
1299
const QList<QMdiSubWindow *> subWindows = d->mdiArea->subWindowList();
1300
Q_ASSERT(index < subWindows.size());
1302
QMdiSubWindow *subWindow = d->mdiArea->subWindowList().at(index);
1303
Q_ASSERT(subWindow);
1308
void MainWindow::onSetActiveSubWindow(QWidget *window)
1312
d->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
1316
void MainWindow::setActiveWindow(MDIView* view)
1318
if (!view || d->activeView == view)
1320
onSetActiveSubWindow(view->parentWidget());
1321
d->activeView = view;
1322
Application::Instance->viewActivated(view);
1325
void MainWindow::onWindowActivated(QMdiSubWindow* mdi)
1328
setWindowTitle(QString());
1329
setWindowModified(false);
1333
auto view = dynamic_cast<MDIView*>(mdi->widget());
1338
d->activeView = view;
1339
Application::Instance->viewActivated(view);
1342
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
1343
bool saveWB = hGrp->GetBool("SaveWBbyTab", false);
1345
QString currWb = mdi->property("ownWB").toString();
1346
if (! currWb.isEmpty()) {
1347
this->activateWorkbench(currWb);
1350
mdi->setProperty("ownWB", QString::fromStdString(WorkbenchManager::instance()->active()->name()));
1367
updateActions(true);
1370
void MainWindow::onWindowsMenuAboutToShow()
1372
QList<QMdiSubWindow*> windows = d->mdiArea->subWindowList(QMdiArea::CreationOrder);
1373
QWidget* active = d->mdiArea->activeSubWindow();
1376
CommandManager& cMgr = Application::Instance->commandManager();
1377
Command* cmd = cMgr.getCommandByName("Std_WindowsMenu");
1378
QList<QAction*> actions = qobject_cast<ActionGroup*>(cmd->getAction())->actions();
1381
static bool firstShow = true;
1384
QAction* last = actions.isEmpty() ? 0 : actions.last();
1385
for (const auto & action : actions) {
1388
connect(action, &QAction::triggered, d->windowMapper, qOverload<>(&QSignalMapper::map));
1392
int numWindows = std::min<int>(actions.count()-1, windows.count());
1393
for (int index = 0; index < numWindows; index++) {
1394
QWidget* child = windows.at(index);
1395
QAction* action = actions.at(index);
1397
QString title = child->windowTitle();
1398
int lastIndex = title.lastIndexOf(QString::fromLatin1("[*]"));
1399
if (lastIndex > 0) {
1400
title = title.left(lastIndex);
1401
if (child->isWindowModified())
1402
title = QString::fromLatin1("%1*").arg(title);
1405
text = QString::fromLatin1("&%1 %2").arg(index+1).arg(title);
1407
text = QString::fromLatin1("%1 %2").arg(index+1).arg(title);
1408
action->setText(text);
1409
action->setVisible(true);
1410
action->setChecked(child == active);
1411
d->windowMapper->setMapping(action, child);
1415
for (int index = numWindows; index < actions.count(); index++)
1416
actions[index]->setVisible(false);
1419
actions.last()->setVisible(true);
1422
void MainWindow::onToolBarMenuAboutToShow()
1424
auto menu = static_cast<QMenu*>(sender());
1426
populateToolBarMenu(menu);
1428
menu->addSeparator();
1430
Application::Instance->commandManager().getCommandByName("Std_ToggleToolBarLock")->addTo(menu);
1433
void MainWindow::populateToolBarMenu(QMenu *menu)
1435
QList<QToolBar*> toolbars = this->findChildren<QToolBar*>();
1436
for (const auto & toolbar : toolbars) {
1437
if (auto parent = toolbar->parentWidget()) {
1439
|| parent == statusBar()
1440
|| parent->parentWidget() == statusBar()
1441
|| parent->parentWidget() == menuBar()) {
1442
QAction* action = toolbar->toggleViewAction();
1443
action->setToolTip(tr("Toggles this toolbar"));
1444
action->setStatusTip(tr("Toggles this toolbar"));
1445
action->setWhatsThis(tr("Toggles this toolbar"));
1446
menu->addAction(action);
1452
void MainWindow::onDockWindowMenuAboutToShow()
1454
auto menu = static_cast<QMenu*>(sender());
1456
populateDockWindowMenu(menu);
1459
void MainWindow::populateDockWindowMenu(QMenu *menu)
1461
QList<QDockWidget*> dock = this->findChildren<QDockWidget*>();
1462
for (auto & it : dock) {
1463
QAction* action = it->toggleViewAction();
1464
action->setToolTip(tr("Toggles this dockable window"));
1465
action->setStatusTip(tr("Toggles this dockable window"));
1466
action->setWhatsThis(tr("Toggles this dockable window"));
1467
menu->addAction(action);
1471
void MainWindow::setDockWindowMenu(QMenu* menu)
1473
connect(menu, &QMenu::aboutToShow, this, &MainWindow::onDockWindowMenuAboutToShow);
1476
void MainWindow::setToolBarMenu(QMenu* menu)
1478
connect(menu, &QMenu::aboutToShow, this, &MainWindow::onToolBarMenuAboutToShow);
1481
void MainWindow::setWindowsMenu(QMenu* menu)
1483
connect(menu, &QMenu::aboutToShow, this, &MainWindow::onWindowsMenuAboutToShow);
1486
QList<QWidget*> MainWindow::windows(QMdiArea::WindowOrder order) const
1488
QList<QWidget*> mdis;
1489
QList<QMdiSubWindow*> wnds = d->mdiArea->subWindowList(order);
1490
for (const auto & wnd : wnds) {
1491
mdis << wnd->widget();
1496
MDIView* MainWindow::activeWindow() const
1499
return d->activeView;
1502
void MainWindow::closeEvent (QCloseEvent * e)
1504
Application::Instance->tryClose(e);
1505
if (e->isAccepted()) {
1507
QList<QDialog*> dialogs = this->findChildren<QDialog*>();
1510
QVector< QPointer<QDialog> > dialogs_ptr;
1511
for (const auto & dialog : dialogs) {
1512
dialogs_ptr.append(dialog);
1514
for (auto & it : dialogs_ptr) {
1518
QList<MDIView*> mdis = this->findChildren<MDIView*>();
1520
for (auto & mdi : mdis) {
1525
if (Workbench* wb = WorkbenchManager::instance()->active())
1526
wb->removeTaskWatcher();
1528
Q_EMIT mainWindowClosed();
1529
d->activityTimer->stop();
1536
saveWindowSettings();
1538
delete d->assistant;
1539
d->assistant = nullptr;
1542
QVariant prop = this->property("x-documentobject-file");
1543
if (!prop.isNull()) {
1544
Base::FileInfo fi((const char*)prop.toByteArray());
1549
if (this->property("QuitOnClosed").isValid()) {
1550
QApplication::closeAllWindows();
1556
void MainWindow::showEvent(QShowEvent* e)
1558
std::clog << "Show main window" << std::endl;
1559
QMainWindow::showEvent(e);
1562
void MainWindow::hideEvent(QHideEvent* e)
1564
std::clog << "Hide main window" << std::endl;
1565
QMainWindow::hideEvent(e);
1568
void MainWindow::processMessages(const QList<QString> & msg)
1573
std::list<std::string> files;
1574
QString action = QString::fromStdString("OpenFile:");
1575
for (const auto & it : msg) {
1576
if (it.startsWith(action))
1577
files.emplace_back(it.mid(action.size()).toStdString());
1579
files = App::Application::processFiles(files);
1580
for (const auto & file : files) {
1581
QString filename = QString::fromUtf8(file.c_str(), file.size());
1582
FileDialog::setWorkingDirectory(filename);
1585
catch (const Base::SystemExitException&) {
1589
void MainWindow::delayedStartup()
1592
if (App::Application::Config()["RunMode"] == "Internal") {
1593
QTimer::singleShot(1000, this, []{
1598
"import QtUnitGui\n\n"
1599
"testCase = FreeCAD.ConfigGet(\"TestCase\")\n"
1600
"QtUnitGui.addTest(testCase)\n"
1601
"QtUnitGui.setTest(testCase)\n"
1602
"result = QtUnitGui.runTest()\n"
1603
"sys.stdout.flush()\n";
1604
if (App::Application::Config()["ExitTests"] == "yes") {
1605
command += "sys.exit(0 if result else 1)";
1607
Base::Interpreter().runString(command.c_str());
1609
catch (const Base::SystemExitException&) {
1612
catch (const Base::Exception& e) {
1613
e.ReportException();
1621
std::list<std::string> files = App::Application::getCmdLineFiles();
1622
files = App::Application::processFiles(files);
1623
for (const auto & file : files) {
1624
QString filename = QString::fromUtf8(file.c_str(), file.size());
1625
FileDialog::setWorkingDirectory(filename);
1628
catch (const Base::SystemExitException&) {
1632
const std::map<std::string,std::string>& cfg = App::Application::Config();
1633
auto it = cfg.find("StartHidden");
1634
if (it != cfg.end()) {
1635
QApplication::quit();
1640
Application::Instance->checkForDeprecatedSettings();
1643
ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Document");
1644
if (hGrp->GetBool("CreateNewDoc", false)) {
1645
if (App::GetApplication().getDocuments().empty()){
1646
Application::Instance->commandManager().runCommandByName("Std_New");
1650
if (hGrp->GetBool("RecoveryEnabled", true)) {
1651
Application::Instance->checkForPreviousCrashes();
1655
void MainWindow::appendRecentFile(const QString& filename)
1657
auto recent = this->findChild<RecentFilesAction *>
1658
(QString::fromLatin1("recentFiles"));
1660
recent->appendFile(filename);
1664
void MainWindow::appendRecentMacro(const QString& filename)
1666
auto recent = this->findChild<RecentMacrosAction *>
1667
(QString::fromLatin1("recentMacros"));
1669
recent->appendFile(filename);
1673
void MainWindow::updateActions(bool delay)
1679
if (!d->activityTimer->isActive()) {
1683
if (d->activityTimer->thread() != QThread::currentThread()) {
1684
QMetaObject::invokeMethod(d->activityTimer, "start", Qt::QueuedConnection,
1688
d->activityTimer->start(150);
1692
if (!d->actionUpdateDelay)
1693
d->actionUpdateDelay = 1;
1696
d->actionUpdateDelay = -1;
1700
void MainWindow::_updateActions()
1702
if (isVisible() && d->actionUpdateDelay <= 0) {
1703
FC_LOG("update actions");
1704
d->activityTimer->stop();
1705
Application::Instance->commandManager().testActive();
1708
d->actionUpdateDelay = 0;
1710
if (auto view = activeWindow()) {
1711
setWindowTitle(view->buildWindowTitle());
1712
if (auto document = view->getGuiDocument()) {
1713
setWindowModified(document->isModified());
1718
void MainWindow::updateEditorActions()
1720
Command* cmd = nullptr;
1721
CommandManager& mgr = Application::Instance->commandManager();
1723
cmd = mgr.getCommandByName("Std_Cut");
1724
if (cmd) cmd->testActive();
1726
cmd = mgr.getCommandByName("Std_Copy");
1727
if (cmd) cmd->testActive();
1729
cmd = mgr.getCommandByName("Std_Paste");
1730
if (cmd) cmd->testActive();
1732
cmd = mgr.getCommandByName("Std_Undo");
1733
if (cmd) cmd->testActive();
1735
cmd = mgr.getCommandByName("Std_Redo");
1736
if (cmd) cmd->testActive();
1739
void MainWindow::switchToTopLevelMode()
1741
QList<QDockWidget*> dw = this->findChildren<QDockWidget*>();
1742
for (auto & it : dw) {
1743
it->setParent(nullptr, Qt::Window);
1746
QList<QWidget*> mdi = getMainWindow()->windows();
1747
for (auto & it : mdi) {
1748
it->setParent(nullptr, Qt::Window);
1753
void MainWindow::switchToDockedMode()
1756
QWidgetList toplevel = QApplication::topLevelWidgets();
1757
for (const auto & it : toplevel) {
1758
auto view = qobject_cast<MDIView*>(it);
1760
view->setCurrentViewMode(MDIView::Child);
1764
void MainWindow::loadWindowSettings()
1766
QString vendor = QString::fromUtf8(App::Application::Config()["ExeVendor"].c_str());
1767
QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
1768
int major = (QT_VERSION >> 0x10) & 0xff;
1769
int minor = (QT_VERSION >> 0x08) & 0xff;
1770
QString qtver = QStringLiteral("Qt%1.%2").arg(major).arg(minor);
1771
QSettings config(vendor, application);
1773
QRect rect = QApplication::primaryScreen()->availableGeometry();
1774
int maxHeight = rect.height();
1775
int maxWidth = rect.width();
1777
config.beginGroup(qtver);
1778
QPoint pos = config.value(QStringLiteral("Position"), this->pos()).toPoint();
1779
maxWidth -= pos.x();
1780
maxHeight -= pos.y();
1781
QSize size = config.value(QStringLiteral("Size"), QSize(maxWidth, maxHeight)).toSize();
1782
bool max = config.value(QStringLiteral("Maximized"), false).toBool();
1783
bool showStatusBar = config.value(QStringLiteral("StatusBar"), true).toBool();
1784
QByteArray windowState = config.value(QStringLiteral("MainWindowState")).toByteArray();
1788
std::string geometry = d->hGrp->GetASCII("Geometry");
1789
std::istringstream iss(geometry);
1791
if (iss >> x >> y >> w >> h) {
1796
max = d->hGrp->GetBool("Maximized", max);
1797
showStatusBar = d->hGrp->GetBool("StatusBar", showStatusBar);
1798
std::string wstate = d->hGrp->GetASCII("MainWindowState");
1799
if (!wstate.empty()) {
1800
windowState = QByteArray::fromBase64(wstate.c_str());
1804
int x1{},x2{},y1{},y2{};
1806
rect.getCoords(&x1, &y1, &x2, &y2);
1807
pos.setX(qMin(qMax(pos.x(),x1-this->width()+30),x2-30));
1808
pos.setY(qMin(qMax(pos.y(),y1-10),y2-10));
1811
Base::StateLocker guard(d->_restoring);
1813
d->restoreWindowState(windowState);
1814
std::clog << "Main window restored" << std::endl;
1816
max ? showMaximized() : show();
1819
#if defined(Q_OS_WIN)
1820
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1821
if (QWindow* win = this->windowHandle()) {
1822
QWindowsWindowFunctions::setHasBorderInFullScreen(win, true);
1825
using namespace QNativeInterface::Private;
1826
if (auto *windowsWindow = dynamic_cast<QWindowsWindow*>(this->windowHandle())) {
1827
windowsWindow->setHasBorderInFullScreen(true);
1832
statusBar()->setVisible(showStatusBar);
1834
ToolBarManager::getInstance()->restoreState();
1835
std::clog << "Toolbars restored" << std::endl;
1837
OverlayManager::instance()->restore();
1840
bool MainWindow::isRestoringWindowState() const
1842
return d->_restoring;
1845
void MainWindowP::restoreWindowState(const QByteArray &windowState)
1847
if (windowState.isEmpty())
1850
Base::StateLocker guard(_restoring);
1853
if (Base::Console().IsMsgTypeEnabled("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn)) {
1854
Base::Console().SetEnabledMsgType("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn, false);
1855
getMainWindow()->restoreState(windowState);
1856
Base::Console().SetEnabledMsgType("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn, true);
1858
getMainWindow()->restoreState(windowState);
1860
Base::ConnectionBlocker block(connParam);
1862
hGrp->SetBool("WindowStateRestored", !hGrp->GetBool("WindowStateRestored", false));
1865
void MainWindow::saveWindowSettings(bool canDelay)
1867
if (isRestoringWindowState())
1871
d->saveStateTimer.start(100);
1875
QString vendor = QString::fromUtf8(App::Application::Config()["ExeVendor"].c_str());
1876
QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
1877
int major = (QT_VERSION >> 0x10) & 0xff;
1878
int minor = (QT_VERSION >> 0x08) & 0xff;
1879
QString qtver = QStringLiteral("Qt%1.%2").arg(major).arg(minor);
1880
QSettings config(vendor, application);
1883
config.beginGroup(qtver);
1884
config.setValue(QStringLiteral("Size"), this->size());
1885
config.setValue(QStringLiteral("Position"), this->pos());
1886
config.setValue(QStringLiteral("Maximized"), this->isMaximized());
1887
config.setValue(QStringLiteral("MainWindowState"), this->saveState());
1888
config.setValue(QStringLiteral("StatusBar"), this->statusBar()->isVisible());
1895
Base::ConnectionBlocker block(d->connParam);
1896
d->hGrp->SetBool("Maximized", this->isMaximized());
1897
d->hGrp->SetBool("StatusBar", this->statusBar()->isVisible());
1898
d->hGrp->SetASCII("MainWindowState", this->saveState().toBase64().constData());
1900
std::ostringstream ss;
1901
QRect rect(this->pos(), this->size());
1902
ss << rect.left() << " " << rect.top() << " " << rect.width() << " " << rect.height();
1903
d->hGrp->SetASCII("Geometry", ss.str().c_str());
1905
DockWindowManager::instance()->saveState();
1906
OverlayManager::instance()->save();
1907
ToolBarManager::getInstance()->saveState();
1910
void MainWindow::startSplasher()
1914
if (!(App::Application::Config()["Verbose"] == "Strict") &&
1915
(App::Application::Config()["RunMode"] == "Gui")) {
1916
ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
1917
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General");
1919
if (hGrp->GetBool("ShowSplasher", true)) {
1920
d->splashscreen = new SplashScreen(this->splashImage());
1922
if (!hGrp->GetBool("ShowSplasherMessages", false)) {
1923
d->splashscreen->setShowMessages(false);
1926
d->splashscreen->show();
1929
d->splashscreen = nullptr;
1934
void MainWindow::stopSplasher()
1936
if (d->splashscreen) {
1937
d->splashscreen->finish(this);
1938
delete d->splashscreen;
1939
d->splashscreen = nullptr;
1943
QPixmap MainWindow::aboutImage() const
1946
QPixmap about_image;
1947
QFileInfo fi(QString::fromLatin1("images:about_image.png"));
1948
if (fi.isFile() && fi.exists())
1949
about_image.load(fi.filePath(), "PNG");
1951
std::string about_path = App::Application::Config()["AboutImage"];
1952
if (!about_path.empty() && about_image.isNull()) {
1953
QString path = QString::fromUtf8(about_path.c_str());
1954
if (QDir(path).isRelative()) {
1955
QString home = QString::fromStdString(App::Application::getHomePath());
1956
path = QFileInfo(QDir(home), path).absoluteFilePath();
1958
about_image.load(path);
1961
if (about_image.isNull()) {
1962
about_image = Gui::BitmapFactory().pixmap(about_path.c_str());
1979
void MainWindow::renderDevBuildWarning(
1981
const QPoint startPosition,
1982
const QSize maxSize,
1986
QColor fader (Qt::white);
1987
constexpr float halfDensity (0.65F);
1988
fader.setAlphaF(halfDensity);
1989
QBrush fillBrush(fader, Qt::BrushStyle::SolidPattern);
1990
painter.setBrush(fillBrush);
1993
const auto devWarningLine1 = tr("WARNING: This is a development version.");
1994
const auto devWarningLine2 = tr("Please do not use it in a production environment.");
1995
QFontMetrics fontMetrics(painter.font());
1996
int padding = QtTools::horizontalAdvance(fontMetrics, QLatin1String("M"));
1997
int line1Width = QtTools::horizontalAdvance(fontMetrics, devWarningLine1);
1998
int line2Width = QtTools::horizontalAdvance(fontMetrics, devWarningLine2);
1999
int boxWidth = std::max(line1Width,line2Width) + 2 * padding;
2000
int lineHeight = fontMetrics.lineSpacing();
2001
if (boxWidth > maxSize.width()) {
2005
float reductionFactor = static_cast<float>(maxSize.width()) / static_cast<float>(boxWidth);
2006
int newFontSize = static_cast<int>(painter.font().pointSize() * reductionFactor);
2007
padding *= reductionFactor;
2008
QFont newFont = painter.font();
2009
newFont.setPointSize(newFontSize);
2010
painter.setFont(newFont);
2011
lineHeight = painter.fontMetrics().lineSpacing();
2012
boxWidth = maxSize.width();
2014
constexpr float lineExpansionFactor(2.3F);
2015
int boxHeight = static_cast<int>(lineHeight*lineExpansionFactor);
2018
painter.setPen(color);
2019
painter.drawRect(startPosition.x(), startPosition.y(), boxWidth, boxHeight);
2020
painter.drawText(startPosition.x()+padding, startPosition.y()+lineHeight, devWarningLine1);
2021
painter.drawText(startPosition.x()+padding, startPosition.y()+2*lineHeight, devWarningLine2);
2024
QPixmap MainWindow::splashImage() const
2027
QPixmap splash_image;
2028
QFileInfo fi(QString::fromLatin1("images:splash_image.png"));
2029
if (fi.isFile() && fi.exists())
2030
splash_image.load(fi.filePath(), "PNG");
2033
std::string splash_path = App::Application::Config()["SplashScreen"];
2034
if (splash_image.isNull()) {
2035
QString path = QString::fromUtf8(splash_path.c_str());
2036
if (QDir(path).isRelative()) {
2037
QString home = QString::fromStdString(App::Application::getHomePath());
2038
path = QFileInfo(QDir(home), path).absoluteFilePath();
2041
splash_image.load(path);
2045
float pixelRatio (1.0);
2046
if (splash_image.isNull()) {
2048
QStringList pixmaps = Gui::BitmapFactory().findIconFiles().filter(QString::fromStdString(splash_path));
2051
int splash_count = pixmaps.count()/2 - 1;
2054
if (splash_count > 0) {
2055
int random = rand() % splash_count;
2056
splash_path += std::to_string(random);
2058
if (qApp->devicePixelRatio() > 1.0) {
2060
splash_path += "_2x";
2061
splash_image = Gui::BitmapFactory().pixmap(splash_path.c_str());
2062
splash_image.setDevicePixelRatio(2.0);
2066
splash_image = Gui::BitmapFactory().pixmap(splash_path.c_str());
2071
std::map<std::string,std::string>::const_iterator tc = App::Application::Config().find("SplashInfoColor");
2072
std::map<std::string,std::string>::const_iterator wc = App::Application::Config().find("SplashWarningColor");
2073
if (tc != App::Application::Config().end() && wc != App::Application::Config().end()) {
2074
QString title = qApp->applicationName();
2075
QString major = QString::fromLatin1(App::Application::Config()["BuildVersionMajor"].c_str());
2076
QString minor = QString::fromLatin1(App::Application::Config()["BuildVersionMinor"].c_str());
2077
QString point = QString::fromLatin1(App::Application::Config()["BuildVersionPoint"].c_str());
2078
QString suffix = QString::fromLatin1(App::Application::Config()["BuildVersionSuffix"].c_str());
2079
QString version = QString::fromLatin1("%1.%2.%3%4").arg(major, minor, point, suffix);
2080
QString position, fontFamily;
2082
std::map<std::string,std::string>::const_iterator te = App::Application::Config().find("SplashInfoExeName");
2083
std::map<std::string,std::string>::const_iterator tv = App::Application::Config().find("SplashInfoVersion");
2084
std::map<std::string,std::string>::const_iterator tp = App::Application::Config().find("SplashInfoPosition");
2085
std::map<std::string,std::string>::const_iterator tf = App::Application::Config().find("SplashInfoFont");
2086
if (te != App::Application::Config().end())
2087
title = QString::fromUtf8(te->second.c_str());
2088
if (tv != App::Application::Config().end())
2089
version = QString::fromUtf8(tv->second.c_str());
2090
if (tp != App::Application::Config().end())
2091
position = QString::fromUtf8(tp->second.c_str());
2092
if (tf != App::Application::Config().end())
2093
fontFamily = QString::fromUtf8(tf->second.c_str());
2096
painter.begin(&splash_image);
2097
if (!fontFamily.isEmpty()) {
2098
QFont font = painter.font();
2099
if (font.fromString(fontFamily))
2100
painter.setFont(font);
2103
QFont fontExe = painter.font();
2104
fontExe.setPointSizeF(20.0);
2105
QFontMetrics metricExe(fontExe);
2106
int l = QtTools::horizontalAdvance(metricExe, title);
2107
if (title == QLatin1String("FreeCAD")) {
2110
int w = splash_image.width();
2111
int h = splash_image.height();
2113
QFont fontVer = painter.font();
2114
fontVer.setPointSizeF(11.0);
2115
QFontMetrics metricVer(fontVer);
2116
int v = QtTools::horizontalAdvance(metricVer, version);
2119
QRegularExpression rx(QLatin1String("(\\d+).(\\d+)"));
2120
auto match = rx.match(position);
2121
if (match.hasMatch()) {
2122
x = match.captured(1).toInt();
2123
y = match.captured(2).toInt();
2126
x = w - (l + v + 10);
2130
QColor color(QString::fromLatin1(tc->second.c_str()));
2131
if (color.isValid()) {
2132
painter.setPen(color);
2133
painter.setFont(fontExe);
2134
if (title != QLatin1String("FreeCAD")) {
2136
painter.drawText(x, y, title);
2138
painter.setFont(fontVer);
2139
painter.drawText(x + (l + 235), y - 7, version);
2140
QColor warningColor(QString::fromLatin1(wc->second.c_str()));
2141
if (suffix == QLatin1String("dev") && warningColor.isValid()) {
2142
fontVer.setPointSizeF(14.0);
2143
painter.setFont(fontVer);
2144
const int lineHeight = metricVer.lineSpacing();
2145
const int padding {45};
2146
QPoint startPosition(padding, y + lineHeight*2);
2147
QSize maxSize(w/pixelRatio - 2*padding, lineHeight * 3);
2148
MainWindow::renderDevBuildWarning(painter, startPosition, maxSize, warningColor);
2154
return splash_image;
2160
void MainWindow::dropEvent (QDropEvent* e)
2162
const QMimeData* data = e->mimeData();
2163
if (data->hasUrls()) {
2165
loadUrls(App::GetApplication().getActiveDocument(), data->urls());
2168
QMainWindow::dropEvent(e);
2172
void MainWindow::dragEnterEvent (QDragEnterEvent * e)
2175
const QMimeData* data = e->mimeData();
2176
if (data->hasUrls()) {
2184
static QLatin1String _MimeDocObj("application/x-documentobject");
2185
static QLatin1String _MimeDocObjX("application/x-documentobject-x");
2186
static QLatin1String _MimeDocObjFile("application/x-documentobject-file");
2187
static QLatin1String _MimeDocObjXFile("application/x-documentobject-x-file");
2189
QMimeData * MainWindow::createMimeDataFromSelection () const
2191
std::vector<App::DocumentObject*> sel;
2192
std::set<App::DocumentObject*> objSet;
2193
for(auto &s : Selection().getCompleteSelection()) {
2194
if(s.pObject && s.pObject->isAttachedToDocument() && objSet.insert(s.pObject).second)
2195
sel.push_back(s.pObject);
2200
auto all = App::Document::getDependencyList(sel);
2201
if (all.size() > sel.size()) {
2202
DlgObjectSelection dlg(sel,getMainWindow());
2203
if(dlg.exec()!=QDialog::Accepted)
2205
sel = dlg.getSelections();
2210
std::vector<App::Document*> unsaved;
2211
bool hasXLink = App::PropertyXLink::hasXLink(sel,&unsaved);
2212
if(!unsaved.empty()) {
2213
QMessageBox::critical(getMainWindow(), tr("Unsaved document"),
2214
tr("The exported object contains external link. Please save the document"
2215
"at least once before exporting."));
2219
unsigned int memsize=1000;
2220
for (const auto & it : sel)
2221
memsize += it->getMemSize();
2224
bool use_buffer=(memsize < 0xA00000);
2228
res.reserve(memsize);
2230
catch (const std::bad_alloc &) {
2238
mime = hasXLink?_MimeDocObjX:_MimeDocObj;
2239
Base::ByteArrayOStreambuf buf(res);
2240
std::ostream str(&buf);
2242
App::Document* doc = sel.front()->getDocument();
2243
MergeDocuments mimeView(doc);
2244
doc->exportObjects(sel, str);
2247
mime = hasXLink?_MimeDocObjXFile:_MimeDocObjFile;
2248
static Base::FileInfo fi(App::Application::getTempFileName());
2249
Base::ofstream str(fi, std::ios::out | std::ios::binary);
2251
App::Document* doc = sel.front()->getDocument();
2252
MergeDocuments mimeView(doc);
2253
doc->exportObjects(sel, str);
2255
res = fi.filePath().c_str();
2259
const_cast<MainWindow*>(this)->setProperty("x-documentobject-file", res);
2262
auto mimeData = new QMimeData();
2263
mimeData->setData(mime,res);
2267
bool MainWindow::canInsertFromMimeData (const QMimeData * source) const
2271
return source->hasUrls() ||
2272
source->hasFormat(_MimeDocObj) || source->hasFormat(_MimeDocObjX) ||
2273
source->hasFormat(_MimeDocObjFile) || source->hasFormat(_MimeDocObjXFile);
2276
void MainWindow::insertFromMimeData (const QMimeData * mimeData)
2280
bool fromDoc = false;
2281
bool hasXLink = false;
2283
if(mimeData->hasFormat(_MimeDocObj))
2284
format = _MimeDocObj;
2285
else if(mimeData->hasFormat(_MimeDocObjX)) {
2286
format = _MimeDocObjX;
2288
}else if(mimeData->hasFormat(_MimeDocObjFile)) {
2289
format = _MimeDocObjFile;
2291
}else if(mimeData->hasFormat(_MimeDocObjXFile)) {
2292
format = _MimeDocObjXFile;
2296
if (mimeData->hasUrls())
2297
loadUrls(App::GetApplication().getActiveDocument(), mimeData->urls());
2301
App::Document* doc = App::GetApplication().getActiveDocument();
2302
if(!doc) doc = App::GetApplication().newDocument();
2304
if(hasXLink && !doc->isSaved()) {
2305
int ret = QMessageBox::question(getMainWindow(), tr("Unsaved document"),
2306
tr("To link to external objects, the document must be saved at least once.\n"
2307
"Do you want to save the document now?"),
2308
QMessageBox::Yes,QMessageBox::No);
2309
if(ret != QMessageBox::Yes || !Application::Instance->getDocument(doc)->saveAs())
2313
QByteArray res = mimeData->data(format);
2315
doc->openTransaction("Paste");
2316
Base::ByteArrayIStreambuf buf(res);
2317
std::istream in(nullptr);
2319
MergeDocuments mimeView(doc);
2320
std::vector<App::DocumentObject*> newObj = mimeView.importObjects(in);
2321
std::vector<App::DocumentObjectGroup*> grp = Gui::Selection().getObjectsOfType<App::DocumentObjectGroup>();
2322
if (grp.size() == 1) {
2323
Gui::Document* gui = Application::Instance->getDocument(doc);
2325
gui->addRootObjectsToGroup(newObj, grp.front());
2327
doc->commitTransaction();
2330
QByteArray res = mimeData->data(format);
2332
doc->openTransaction("Paste");
2333
Base::FileInfo fi((const char*)res);
2334
Base::ifstream str(fi, std::ios::in | std::ios::binary);
2335
MergeDocuments mimeView(doc);
2336
std::vector<App::DocumentObject*> newObj = mimeView.importObjects(str);
2338
std::vector<App::DocumentObjectGroup*> grp = Gui::Selection().getObjectsOfType<App::DocumentObjectGroup>();
2339
if (grp.size() == 1) {
2340
Gui::Document* gui = Application::Instance->getDocument(doc);
2342
gui->addRootObjectsToGroup(newObj, grp.front());
2344
doc->commitTransaction();
2348
void MainWindow::setUrlHandler(const QString &scheme, Gui::UrlHandler* handler)
2350
d->urlHandler[scheme] = handler;
2353
void MainWindow::unsetUrlHandler(const QString &scheme)
2355
d->urlHandler.remove(scheme);
2358
void MainWindow::loadUrls(App::Document* doc, const QList<QUrl>& urls)
2361
for (const auto & it : urls) {
2362
QMap<QString, QPointer<UrlHandler> >::iterator jt = d->urlHandler.find(it.scheme());
2363
if (jt != d->urlHandler.end() && !jt->isNull()) {
2365
(*jt)->openUrl(doc, it);
2369
QFileInfo info(it.toLocalFile());
2370
if (info.exists() && info.isFile()) {
2371
if (info.isSymLink())
2372
info.setFile(info.symLinkTarget());
2373
std::vector<std::string> module = App::GetApplication()
2374
.getImportModules(info.completeSuffix().toLatin1());
2375
if (module.empty()) {
2376
module = App::GetApplication()
2377
.getImportModules(info.suffix().toLatin1());
2379
if (!module.empty()) {
2381
files << info.absoluteFilePath();
2384
Base::Console().Message("No support to load file '%s'\n",
2385
(const char*)info.absoluteFilePath().toUtf8());
2388
else if (it.scheme().toLower() == QLatin1String("http")) {
2389
Gui::Dialog::DownloadManager* dm = Gui::Dialog::DownloadManager::getInstance();
2390
dm->download(dm->redirectUrl(it));
2393
else if (it.scheme().toLower() == QLatin1String("https")) {
2395
QUrlQuery urlq(url);
2396
if (urlq.hasQueryItem(QLatin1String("sid"))) {
2397
urlq.removeAllQueryItems(QLatin1String("sid"));
2399
url.setScheme(QLatin1String("http"));
2401
Gui::Dialog::DownloadManager* dm = Gui::Dialog::DownloadManager::getInstance();
2402
dm->download(dm->redirectUrl(url));
2405
else if (it.scheme().toLower() == QLatin1String("ftp")) {
2406
Gui::Dialog::DownloadManager::getInstance()->download(it);
2410
QByteArray docName = doc ? QByteArray(doc->getName()) : qApp->translate("StdCmdNew","Unnamed").toUtf8();
2411
SelectModule::Dict dict = SelectModule::importHandler(files);
2413
for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
2415
Application::Instance->importFrom(it.key().toUtf8(), docName, it.value().toLatin1());
2419
void MainWindow::changeEvent(QEvent *e)
2421
if (e->type() == QEvent::LanguageChange) {
2422
d->sizeLabel->setText(tr("Dimension"));
2424
CommandManager& rclMan = Application::Instance->commandManager();
2425
std::vector<Command*> cmd = rclMan.getAllCommands();
2426
for (auto & it : cmd)
2427
it->languageChange();
2430
Workbench* wb = WorkbenchManager::instance()->active();
2431
if (wb) wb->retranslate();
2433
else if (e->type() == QEvent::ActivationChange) {
2434
if (isActiveWindow()) {
2435
QMdiSubWindow* mdi = d->mdiArea->currentSubWindow();
2437
auto view = dynamic_cast<MDIView*>(mdi->widget());
2438
if (view && getMainWindow()->activeWindow() != view) {
2439
d->activeView = view;
2440
Application::Instance->viewActivated(view);
2446
QMainWindow::changeEvent(e);
2450
void MainWindow::clearStatus() {
2451
d->currentStatusType = 100;
2452
statusBar()->setStyleSheet(QString::fromLatin1("#statusBar{}"));
2455
void MainWindow::statusMessageChanged() {
2456
if(d->currentStatusType<0)
2457
d->currentStatusType = -d->currentStatusType;
2462
d->statusTimer->stop();
2467
void MainWindow::showMessage(const QString& message, int timeout) {
2468
if(QApplication::instance()->thread() != QThread::currentThread()) {
2469
QApplication::postEvent(this, new CustomMessageEvent(MainWindow::Tmp,message,timeout));
2472
d->actionLabel->setText(message.simplified());
2474
d->actionTimer->setSingleShot(true);
2475
d->actionTimer->start(timeout);
2477
d->actionTimer->stop();
2480
void MainWindow::setRightSideMessage(const QString& message)
2482
d->rightSideLabel->setText(message.simplified());
2485
void MainWindow::showStatus(int type, const QString& message)
2487
if(QApplication::instance()->thread() != QThread::currentThread()) {
2488
QApplication::postEvent(this,
2489
new CustomMessageEvent(type,message));
2493
if(d->currentStatusType < type)
2496
d->statusTimer->setSingleShot(true);
2499
d->statusTimer->start(timeout);
2501
QFontMetrics fm(statusBar()->font());
2502
QString msg = fm.elidedText(message, Qt::ElideMiddle, this->d->actionLabel->width());
2504
case MainWindow::Err:
2505
statusBar()->setStyleSheet(d->status->err);
2507
case MainWindow::Wrn:
2508
statusBar()->setStyleSheet(d->status->wrn);
2510
case MainWindow::Pane:
2511
statusBar()->setStyleSheet(QString::fromLatin1("#statusBar{}"));
2514
statusBar()->setStyleSheet(d->status->msg);
2517
d->currentStatusType = -type;
2518
statusBar()->showMessage(msg.simplified(), timeout);
2523
void MainWindow::setPaneText(int i, QString text)
2526
showStatus(MainWindow::Pane, text);
2529
d->sizeLabel->setText(text);
2534
void MainWindow::setUserSchema(int userSchema)
2536
d->sizeLabel->setUserSchema(userSchema);
2540
void MainWindow::customEvent(QEvent* e)
2542
if (e->type() == QEvent::User) {
2543
auto ce = static_cast<Gui::CustomMessageEvent*>(e);
2544
QString msg = ce->message();
2545
switch(ce->type()) {
2546
case MainWindow::Log: {
2547
if (msg.startsWith(QLatin1String("#Inventor V2.1 ascii "))) {
2548
Gui::Document *d = Application::Instance->activeDocument();
2550
auto view = new ViewProviderExtern();
2552
view->setModeByString("1",msg.toLatin1().constData());
2553
d->setAnnotationViewProvider("Vdbg",view);
2561
} case MainWindow::Tmp: {
2562
showMessage(msg, ce->timeout());
2565
showStatus(ce->type(),msg);
2568
else if (e->type() == ActionStyleEvent::EventType) {
2569
QList<TaskView::TaskView*> tasks = findChildren<TaskView::TaskView*>();
2570
if (static_cast<ActionStyleEvent*>(e)->getType() == ActionStyleEvent::Clear) {
2571
for (auto & task : tasks) {
2572
task->clearActionStyle();
2576
for (auto & task : tasks) {
2577
task->restoreActionStyle();
2583
QMdiArea *MainWindow::getMdiArea() const
2588
void MainWindow::setWindowTitle(const QString& string)
2591
QString appname = QCoreApplication::applicationName();
2592
if (appname.isEmpty()) {
2593
appname = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
2597
ParameterGrp::handle hGen = App::GetApplication().GetParameterGroupByPath(
2598
"User parameter:BaseApp/Preferences/General");
2599
bool showVersion = hGen->GetBool("ShowVersionInTitle", true);
2603
auto config = App::Application::Config();
2604
QString major = QString::fromUtf8(config["BuildVersionMajor"].c_str());
2605
QString minor = QString::fromUtf8(config["BuildVersionMinor"].c_str());
2606
QString point = QString::fromUtf8(config["BuildVersionPoint"].c_str());
2607
QString suffix = QString::fromUtf8(config["BuildVersionSuffix"].c_str());
2608
title = QString::fromUtf8("%1 %2.%3.%4%5").arg(appname, major, minor, point, suffix);
2614
if (!string.isEmpty()) {
2615
title = QString::fromUtf8("[*] %1 - %2").arg(string, title);
2618
QMainWindow::setWindowTitle(title);
2623
StatusBarObserver::StatusBarObserver()
2624
: WindowParameter("OutputWindow")
2626
msg = QString::fromLatin1("#statusBar{color: #000000}");
2627
wrn = QString::fromLatin1("#statusBar{color: #ffaa00}");
2628
err = QString::fromLatin1("#statusBar{color: #ff0000}");
2629
Base::Console().AttachObserver(this);
2630
getWindowParameter()->Attach(this);
2631
getWindowParameter()->NotifyAll();
2634
StatusBarObserver::~StatusBarObserver()
2636
getWindowParameter()->Detach(this);
2637
Base::Console().DetachObserver(this);
2640
void StatusBarObserver::OnChange(Base::Subject<const char*> & rCaller, const char* sReason)
2642
ParameterGrp& rclGrp = ((ParameterGrp&)rCaller);
2643
auto format = QString::fromLatin1("#statusBar{color: %1}");
2644
if (strcmp(sReason, "colorText") == 0) {
2645
unsigned long col = rclGrp.GetUnsigned(sReason);
2646
this->msg = format.arg(App::Color::fromPackedRGB<QColor>(col).name());
2648
else if (strcmp(sReason, "colorWarning") == 0) {
2649
unsigned long col = rclGrp.GetUnsigned(sReason);
2650
this->wrn = format.arg(App::Color::fromPackedRGB<QColor>(col).name());
2652
else if (strcmp(sReason, "colorError") == 0) {
2653
unsigned long col = rclGrp.GetUnsigned(sReason);
2654
this->err = format.arg(App::Color::fromPackedRGB<QColor>(col).name());
2656
else if (strcmp(sReason, "colorCritical") == 0) {
2657
unsigned long col = rclGrp.GetUnsigned(sReason);
2658
this->critical = format.arg(
2659
QColor((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff).name());
2663
void StatusBarObserver::SendLog(const std::string& notifiername,
2664
const std::string& msg,
2665
Base::LogStyle level,
2666
Base::IntendedRecipient recipient,
2667
Base::ContentType content)
2672
if (recipient == Base::IntendedRecipient::Developer
2673
|| content == Base::ContentType::Untranslated
2674
|| content == Base::ContentType::Untranslatable)
2677
int messageType = -1;
2679
case Base::LogStyle::Warning:
2680
messageType = MainWindow::Wrn;
2682
case Base::LogStyle::Message:
2683
messageType = MainWindow::Msg;
2685
case Base::LogStyle::Error:
2686
messageType = MainWindow::Err;
2688
case Base::LogStyle::Log:
2689
messageType = MainWindow::Log;
2691
case Base::LogStyle::Critical:
2692
messageType = MainWindow::Critical;
2699
auto ev = new CustomMessageEvent(messageType, QString::fromUtf8(msg.c_str()));
2700
QApplication::postEvent(getMainWindow(), ev);
2705
int ActionStyleEvent::EventType = -1;
2707
ActionStyleEvent::ActionStyleEvent(Style type)
2708
: QEvent(QEvent::Type(EventType))
2712
ActionStyleEvent::Style ActionStyleEvent::getType() const
2718
#include "moc_MainWindow.cpp"
2719
#include "MainWindow.moc"