MainWindow.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <QApplication>
00027 # include <QBuffer>
00028 # include <QByteArray>
00029 # include <QClipboard>
00030 # include <QMimeData>
00031 # include <QCloseEvent>
00032 # include <QContextMenuEvent>
00033 # include <QDesktopWidget>
00034 # include <QDockWidget>
00035 # include <QFontMetrics>
00036 # include <QLabel>
00037 # include <QMdiSubWindow>
00038 # include <QMessageBox>
00039 # include <QSettings>
00040 # include <QSignalMapper>
00041 # include <QStatusBar>
00042 # include <QTimer>
00043 # include <QToolBar>
00044 # include <QWhatsThis>
00045 #endif
00046 
00047 #include <boost/signals.hpp>
00048 #include <boost/bind.hpp>
00049 
00050 // FreeCAD Base header
00051 #include <Base/Parameter.h>
00052 #include <Base/Exception.h>
00053 #include <Base/FileInfo.h>
00054 #include <Base/Persistence.h>
00055 #include <Base/Stream.h>
00056 #include <Base/Reader.h>
00057 #include <Base/Writer.h>
00058 #include <App/Application.h>
00059 #include <App/DocumentObject.h>
00060 
00061 #include "MainWindow.h"
00062 #include "Application.h"
00063 #include "Assistant.h"
00064 
00065 #include "Action.h"
00066 #include "Command.h"
00067 
00068 #include "ToolBoxManager.h"
00069 #include "DockWindowManager.h"
00070 #include "ToolBarManager.h"
00071 #include "WorkbenchManager.h"
00072 #include "Workbench.h"
00073 
00074 #include "Window.h" 
00075 #include "View.h"
00076 #include "Macro.h"
00077 #include "ProgressBar.h"
00078 
00079 #include "Icons/background.xpm"
00080 #include "WidgetFactory.h"
00081 #include "BitmapFactory.h"
00082 #include "Splashscreen.h"
00083 
00084 #include "Tree.h"
00085 #include "PropertyView.h"
00086 #include "SelectionView.h"
00087 #include "TaskPanelView.h"
00088 #include "MenuManager.h"
00089 //#include "ToolBox.h"
00090 #include "HelpView.h"
00091 #include "ReportView.h"
00092 #include "CombiView.h"
00093 #include "PythonConsole.h"
00094 
00095 #include "DlgTipOfTheDayImp.h"
00096 #include "DlgUndoRedo.h"
00097 #include "DlgOnlineHelpImp.h"
00098 
00099 #include "Language/Translator.h"
00100 #include "GuiInitScript.h"
00101 
00102 #include "Document.h"
00103 #include "MergeDocuments.h"
00104 #include "ViewProviderExtern.h"
00105 
00106 #include "SpaceballEvent.h"
00107 
00108 #if defined(Q_OS_WIN32)
00109 #define slots
00110 #include <private/qmainwindowlayout_p.h>
00111 #include <private/qwidgetresizehandler_p.h>
00112 #endif
00113 
00114 using namespace Gui;
00115 using namespace Gui::DockWnd;
00116 using namespace std;
00117 
00118 
00119 MainWindow* MainWindow::instance = 0L;
00120 
00121 namespace Gui {
00122 
00123 // Pimpl class
00124 struct MainWindowP
00125 {
00126     QLabel* sizeLabel;
00127     QLabel* actionLabel;
00128     QTimer* actionTimer;
00129     QTimer* activityTimer;
00130     QTimer* visibleTimer;
00131 #if !defined (NO_USE_QT_MDI_AREA)
00132     QMdiArea* mdiArea;
00133 #else
00134     QWorkspace* workspace;
00135     QTabBar* tabs;
00136 #endif
00137     QPointer<MDIView> activeView;
00138     QSignalMapper* windowMapper;
00139     QSplashScreen* splashscreen;
00140     StatusBarObserver* status;
00141     bool whatsthis;
00142     QString whatstext;
00143     Assistant* assistant;
00144 };
00145 
00146 class MDITabbar : public QTabBar
00147 {
00148 public:
00149     MDITabbar( QWidget * parent = 0 ) : QTabBar(parent)
00150     {
00151         menu = new QMenu(this);
00152         // For Qt 4.2.x the tabs might be very wide
00153 #if QT_VERSION >= 0x040200
00154         setDrawBase(false);
00155         setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00156 #endif
00157     }
00158 
00159     ~MDITabbar()
00160     {
00161         delete menu;
00162     }
00163 
00164 protected:
00165     void contextMenuEvent ( QContextMenuEvent * e )
00166     {
00167         menu->clear();
00168         CommandManager& cMgr = Application::Instance->commandManager();
00169         if (tabRect(currentIndex()).contains(e->pos()))
00170             cMgr.getCommandByName("Std_CloseActiveWindow")->addTo(menu);
00171         cMgr.getCommandByName("Std_CloseAllWindows")->addTo(menu);
00172         menu->addSeparator();
00173         cMgr.getCommandByName("Std_CascadeWindows")->addTo(menu);
00174         cMgr.getCommandByName("Std_ArrangeIcons")->addTo(menu);
00175         cMgr.getCommandByName("Std_TileWindows")->addTo(menu);
00176         menu->addSeparator();
00177         cMgr.getCommandByName("Std_Windows")->addTo(menu);
00178         menu->popup(e->globalPos());
00179     }
00180 
00181 private:
00182     QMenu* menu;
00183 };
00184 
00185 #if defined(Q_OS_WIN32)
00186 class MainWindowTabBar : public QTabBar
00187 {
00188 public:
00189     MainWindowTabBar(QWidget *parent) : QTabBar(parent)
00190     {
00191         setExpanding(false);
00192     }
00193 protected:
00194     bool event(QEvent *e)
00195     {
00196         // show the tooltip if tab is too small to fit label
00197         if (e->type() != QEvent::ToolTip)
00198             return QTabBar::event(e);
00199         QSize size = this->size();
00200         QSize hint = sizeHint();
00201         if (shape() == QTabBar::RoundedWest || shape() == QTabBar::RoundedEast) {
00202             size.transpose();
00203             hint.transpose();
00204         }
00205         if (size.width() < hint.width())
00206             return QTabBar::event(e);
00207         e->accept();
00208         return true;
00209     }
00210     void tabInserted (int index)
00211     {
00212         // get all dock windows
00213         QList<QDockWidget*> dw = getMainWindow()->findChildren<QDockWidget*>();
00214         for (QList<QDockWidget*>::iterator it = dw.begin(); it != dw.end(); ++it) {
00215             // compare tab text and window title to get the right dock window
00216             if (this->tabText(index) == (*it)->windowTitle()) {
00217                 QWidget* dock = (*it)->widget();
00218                 if (dock) {
00219                     QIcon icon = dock->windowIcon();
00220                     if (!icon.isNull())
00221                         setTabIcon(index, icon);
00222                 }
00223                 break;
00224             }
00225         }
00226     }
00227 };
00228 #endif
00229 
00230 } // namespace Gui
00231 
00232 
00233 /* TRANSLATOR Gui::MainWindow */
00234 
00235 MainWindow::MainWindow(QWidget * parent, Qt::WFlags f)
00236   : QMainWindow( parent, f/*WDestructiveClose*/ )
00237 {
00238     d = new MainWindowP;
00239     d->splashscreen = 0;
00240     d->activeView = 0;
00241     d->whatsthis = false;
00242     d->assistant = new Assistant();
00243 
00244     // global access 
00245     instance = this;
00246 
00247     // Create the layout containing the workspace and a tab bar
00248 #if defined(NO_USE_QT_MDI_AREA)
00249     QFrame* vbox = new QFrame(this);
00250     vbox->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
00251     QVBoxLayout* layout = new QVBoxLayout();
00252     layout->setMargin(1);
00253     vbox->setLayout(layout);
00254 
00255     d->workspace = new QWorkspace();
00256     d->workspace->setScrollBarsEnabled( true );
00257     QPixmap backgnd((const char**) background);
00258     d->workspace->setBackground(backgnd);
00259 
00260     d->tabs = new MDITabbar();
00261     d->tabs->setShape(QTabBar:: RoundedSouth);
00262 
00263     layout->addWidget(d->workspace);
00264     layout->addWidget(d->tabs);
00265     setCentralWidget(vbox);
00266 #else
00267     d->mdiArea = new QMdiArea();
00268 #if QT_VERSION >= 0x040500
00269     d->mdiArea->setTabPosition(QTabWidget::South);
00270     d->mdiArea->setViewMode(QMdiArea::TabbedView);
00271     QTabBar* tab = d->mdiArea->findChild<QTabBar*>();
00272     if (tab) { 
00273         connect(tab, SIGNAL(tabCloseRequested(int)),
00274                 this, SLOT(tabCloseRequested(int)));
00275         tab->setTabsClosable(true);
00276         // The tabs might be very wide
00277         tab->setExpanding(false);
00278     }
00279 #endif
00280     d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
00281     d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
00282     d->mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, false);
00283     QPixmap backgnd((const char**) background);
00284     d->mdiArea->setBackground(backgnd);
00285     setCentralWidget(d->mdiArea);
00286 #endif
00287 
00288     // labels and progressbar
00289     d->status = new StatusBarObserver();
00290     d->actionLabel = new QLabel(statusBar());
00291     d->actionLabel->setMinimumWidth(120);
00292     d->sizeLabel = new QLabel(tr("Dimension"), statusBar());
00293     d->sizeLabel->setMinimumWidth(120);
00294     statusBar()->addWidget(d->actionLabel, 0);
00295     QProgressBar* progressBar = Gui::Sequencer::instance()->getProgressBar(statusBar());
00296     statusBar()->addPermanentWidget(progressBar, 0);
00297     statusBar()->addPermanentWidget(d->sizeLabel, 0);
00298 
00299     // clears the action label
00300     d->actionTimer = new QTimer( this );
00301     connect(d->actionTimer, SIGNAL(timeout()), d->actionLabel, SLOT(clear()));
00302 
00303     // update gui timer
00304     d->activityTimer = new QTimer(this);
00305     connect(d->activityTimer, SIGNAL(timeout()),this, SLOT(updateActions()));
00306     d->activityTimer->setSingleShot(true);
00307     d->activityTimer->start(300);
00308 
00309     // show main window timer
00310     d->visibleTimer = new QTimer(this);
00311     connect(d->visibleTimer, SIGNAL(timeout()),this, SLOT(showMainWindow()));
00312     d->visibleTimer->setSingleShot(true);
00313 
00314     d->windowMapper = new QSignalMapper(this);
00315 
00316     // connection between workspace, window menu and tab bar
00317 #if !defined (NO_USE_QT_MDI_AREA)
00318     connect(d->windowMapper, SIGNAL(mapped(QWidget *)),
00319             this, SLOT(onSetActiveSubWindow(QWidget*)));
00320     connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),
00321             this, SLOT(onWindowActivated(QMdiSubWindow* )));
00322 #else
00323     connect(d->windowMapper, SIGNAL(mapped(QWidget *)),
00324             d->workspace, SLOT(setActiveWindow(QWidget* )));
00325     connect(d->workspace, SIGNAL(windowActivated(QWidget *)),
00326             this, SLOT(onWindowActivated(QWidget* )));
00327     connect(d->tabs, SIGNAL(currentChanged(int)),
00328             this, SLOT(onTabSelected(int)));
00329 #endif
00330 
00331     DockWindowManager* pDockMgr = DockWindowManager::instance();
00332 
00333     // Show all dockable windows over the workbench facility
00334     //
00335 #if 0
00336     // Toolbox
00337     ToolBox* toolBox = new ToolBox(this);
00338     toolBox->setObjectName(QT_TRANSLATE_NOOP("QDockWidget","Toolbox"));
00339     pDockMgr->registerDockWindow("Std_ToolBox", toolBox);
00340     ToolBoxManager::getInstance()->setToolBox( toolBox );
00341 
00342     // Help View
00343     QString home = Gui::Dialog::DlgOnlineHelpImp::getStartpage();
00344     HelpView* pcHelpView = new HelpView( home, this );
00345     pDockMgr->registerDockWindow("Std_HelpView", pcHelpView);
00346 
00347     // TaskPanel view
00348     TaskPanelView* pcTaskPanelView = new TaskPanelView(0, this);
00349     pcTaskPanelView->setObjectName
00350         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Task View")));
00351     pcTaskPanelView->setMinimumWidth(210);
00352     pDockMgr->registerDockWindow("Std_TaskPanelView", pcTaskPanelView);
00353 #endif
00354 
00355     // Tree view
00356     TreeDockWidget* tree = new TreeDockWidget(0, this);
00357     tree->setObjectName
00358         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Tree view")));
00359     tree->setMinimumWidth(210);
00360     pDockMgr->registerDockWindow("Std_TreeView", tree);
00361 
00362     // Property view
00363     PropertyDockView* pcPropView = new PropertyDockView(0, this);
00364     pcPropView->setObjectName
00365         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Property view")));
00366     pcPropView->setMinimumWidth(210);
00367     pDockMgr->registerDockWindow("Std_PropertyView", pcPropView);
00368 
00369     // Selection view
00370     SelectionView* pcSelectionView = new SelectionView(0, this);
00371     pcSelectionView->setObjectName
00372         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Selection view")));
00373     pcSelectionView->setMinimumWidth(210);
00374     pDockMgr->registerDockWindow("Std_SelectionView", pcSelectionView);
00375 
00376     // Combo view
00377     CombiView* pcCombiView = new CombiView(0, this);
00378     pcCombiView->setObjectName(QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Combo View")));
00379     pcCombiView->setMinimumWidth(150);
00380     pDockMgr->registerDockWindow("Std_CombiView", pcCombiView);
00381 
00382 #if QT_VERSION < 0x040500
00383     // Report view
00384     Gui::DockWnd::ReportView* pcReport = new Gui::DockWnd::ReportView(this);
00385     pcReport->setObjectName
00386         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Report view")));
00387     pDockMgr->registerDockWindow("Std_ReportView", pcReport);
00388 #else
00389     // Report view (must be created before PythonConsole!)
00390     ReportOutput* pcReport = new ReportOutput(this);
00391     pcReport->setWindowIcon(BitmapFactory().pixmap("MacroEditor"));
00392     pcReport->setObjectName
00393         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Report view")));
00394     pDockMgr->registerDockWindow("Std_ReportView", pcReport);
00395 
00396     // Python console
00397     PythonConsole* pcPython = new PythonConsole(this);
00398     pcPython->setWordWrapMode(QTextOption::NoWrap);
00399     pcPython->setWindowIcon(Gui::BitmapFactory().pixmap("python_small"));
00400     pcPython->setObjectName
00401         (QString::fromAscii(QT_TRANSLATE_NOOP("QDockWidget","Python console")));
00402     pDockMgr->registerDockWindow("Std_PythonView", pcPython);
00403 
00404 #if defined(Q_OS_WIN32)
00405     // add our own QTabBar-derived class to the main window layout
00406     // NOTE: This uses some private stuff from QMainWindow which doesn't
00407     // seem to be accessible on all platforms.
00408     QMainWindowLayout* l = static_cast<QMainWindowLayout*>(this->layout());
00409     for (int i=0; i<5; i++) {
00410         MainWindowTabBar* result = new MainWindowTabBar(this);
00411         result->setDrawBase(true);
00412         result->setElideMode(Qt::ElideRight);
00413         result->hide(); // avoid to show horizontal bar in top left area
00414         //result->setDocumentMode(_documentMode);
00415         connect(result, SIGNAL(currentChanged(int)), l, SLOT(tabChanged()));
00416         l->unusedTabBars << result;
00417     }
00418 #endif
00419 #endif
00420 
00421     // accept drops on the window, get handled in dropEvent, dragEnterEvent
00422     setAcceptDrops(true);
00423     statusBar()->showMessage(tr("Ready"), 2001);
00424 }
00425 
00426 MainWindow::~MainWindow()
00427 {
00428     delete d->status;
00429     delete d;
00430     instance = 0;
00431 }
00432 
00433 MainWindow* MainWindow::getInstance()
00434 {
00435     // MainWindow has a public constructor
00436     return instance;
00437 }
00438 
00439 QMenu* MainWindow::createPopupMenu ()
00440 {
00441     QMenu* menu = QMainWindow::createPopupMenu();
00442     Workbench* wb = WorkbenchManager::instance()->active();
00443     if (wb) {
00444         MenuItem item;
00445         wb->createMainWindowPopupMenu(&item);
00446         if (item.hasItems()) {
00447             menu->addSeparator();
00448             QList<MenuItem*> items = item.getItems();
00449             for (QList<MenuItem*>::iterator it = items.begin(); it != items.end(); ++it) {
00450                 if ((*it)->command() == "Separator") {
00451                     menu->addSeparator();
00452                 }
00453                 else {
00454                     Command* cmd = Application::Instance->commandManager().getCommandByName((*it)->command().c_str());
00455                     if (cmd) cmd->addTo(menu);
00456                 }
00457             }
00458         }
00459     }
00460 
00461     return menu;
00462 }
00463 
00464 void MainWindow::arrangeIcons()
00465 {
00466 #if !defined (NO_USE_QT_MDI_AREA)
00467     d->mdiArea->tileSubWindows();
00468 #else
00469     d->workspace->arrangeIcons();
00470 #endif
00471 }
00472 
00473 void MainWindow::tile()
00474 {
00475 #if !defined (NO_USE_QT_MDI_AREA)
00476     d->mdiArea->tileSubWindows();
00477 #else
00478     d->workspace->tile();
00479 #endif
00480 }
00481 
00482 void MainWindow::cascade()
00483 {
00484 #if !defined (NO_USE_QT_MDI_AREA)
00485     d->mdiArea->cascadeSubWindows();
00486 #else
00487     d->workspace->cascade();
00488 #endif
00489 }
00490 
00491 void MainWindow::closeActiveWindow ()
00492 {
00493 #if !defined (NO_USE_QT_MDI_AREA)
00494     d->mdiArea->closeActiveSubWindow();
00495 #else
00496     d->workspace->closeActiveWindow();
00497 #endif
00498 }
00499 
00500 void MainWindow::closeAllWindows ()
00501 {
00502 #if !defined (NO_USE_QT_MDI_AREA)
00503     d->mdiArea->closeAllSubWindows();
00504 #else
00505     d->workspace->closeAllWindows();
00506 #endif
00507 }
00508 
00509 void MainWindow::activateNextWindow ()
00510 {
00511 #if !defined (NO_USE_QT_MDI_AREA)
00512     d->mdiArea->activateNextSubWindow();
00513 #else
00514     d->workspace->activateNextWindow();
00515 #endif
00516 }
00517 
00518 void MainWindow::activatePreviousWindow ()
00519 {
00520 #if !defined (NO_USE_QT_MDI_AREA)
00521     d->mdiArea->activatePreviousSubWindow();
00522 #else
00523     d->workspace->activatePreviousWindow();
00524 #endif
00525 }
00526 
00527 void MainWindow::activateWorkbench(const QString& name)
00528 {
00529     // emit this signal
00530     workbenchActivated(name);
00531 }
00532 
00533 void MainWindow::whatsThis()
00534 {
00535     QWhatsThis::enterWhatsThisMode();
00536 }
00537 
00538 void MainWindow::showDocumentation(const char* Article)
00539 {
00540     QString help;
00541     if (Article && Article[0] != '\0')
00542         help = QString::fromUtf8("%1.html").arg(QLatin1String(Article));
00543     d->assistant->showDocumentation(help);
00544 }
00545 
00546 bool MainWindow::event(QEvent *e)
00547 {
00548     if (e->type() == QEvent::EnterWhatsThisMode) {
00549         // Unfortunately, for top-level widgets such as menus or dialogs we
00550         // won't be notified when the user clicks the link in the hypertext of
00551         // the what's this text. Thus, we have to install the main window to
00552         // the application to observe what happens in eventFilter().
00553         d->whatstext.clear();
00554         if (!d->whatsthis) {
00555             d-> whatsthis = true;
00556             qApp->installEventFilter(this);
00557         }
00558     }
00559     else if (e->type() == QEvent::LeaveWhatsThisMode) {
00560         // Here we can't do anything because this event is sent
00561         // before the WhatThisClicked event is sent. Thus, we handle
00562         // this in eventFilter().
00563     }
00564     else if (e->type() == QEvent::WhatsThisClicked) {
00565         QWhatsThisClickedEvent* wt = static_cast<QWhatsThisClickedEvent*>(e);
00566         showDocumentation((const char*)wt->href().toUtf8());
00567     }
00568     else if (e->type() == QEvent::ApplicationWindowIconChange) {
00569         // if application icon changes apply it to the main window and the "About..." dialog
00570         this->setWindowIcon(QApplication::windowIcon());
00571         Command* about = Application::Instance->commandManager().getCommandByName("Std_About");
00572         if (about) {
00573             Action* action = about->getAction();
00574             if (action) action->setIcon(QApplication::windowIcon());
00575         }
00576     }
00577     else if (e->type() == Spaceball::ButtonEvent::ButtonEventType) {
00578         Spaceball::ButtonEvent *buttonEvent = dynamic_cast<Spaceball::ButtonEvent *>(e);
00579         if (!buttonEvent)
00580             return true;
00581         buttonEvent->setHandled(true);
00582         //only going to respond to button press events.
00583         if (buttonEvent->buttonStatus() != Spaceball::BUTTON_PRESSED)
00584             return true;
00585         ParameterGrp::handle group = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
00586                 GetGroup("Spaceball")->GetGroup("Buttons");
00587         QByteArray groupName(QVariant(buttonEvent->buttonNumber()).toByteArray());
00588         if (group->HasGroup(groupName.data())) {
00589             ParameterGrp::handle commandGroup = group->GetGroup(groupName.data());
00590             std::string commandName(commandGroup->GetASCII("Command"));
00591             if (commandName.empty())
00592                 return true;
00593             else
00594                 Application::Instance->commandManager().runCommandByName(commandName.c_str());
00595         }
00596         else
00597             return true;
00598     }
00599     return QMainWindow::event(e);
00600 }
00601 
00602 bool MainWindow::eventFilter(QObject* o, QEvent* e)
00603 {
00604     if (o != this) {
00605         if (e->type() == QEvent::WindowStateChange) {
00606             // notify all mdi views when the active view receives a show normal, show minimized 
00607             // or show maximized event 
00608             MDIView * view = qobject_cast<MDIView*>(o);
00609             if (view) { // emit this signal
00610                 Qt::WindowStates oldstate = static_cast<QWindowStateChangeEvent*>(e)->oldState();
00611                 Qt::WindowStates newstate = view->windowState();
00612                 if (oldstate != newstate)
00613                     windowStateChanged(view);
00614             }
00615         }
00616 
00617         // We don't want to show the bubble help for the what's this text but want to
00618         // start the help viewer with the according key word.
00619         // Thus, we have to observe WhatThis events if called for a widget, use its text and
00620         // must avoid to make the bubble widget visible.
00621         if (e->type() == QEvent::WhatsThis) {
00622             if (!o->isWidgetType())
00623                 return false;
00624             // clicked on a widget in what's this mode
00625             QWidget * w = static_cast<QWidget *>(o);
00626             d->whatstext = w->whatsThis();
00627         }
00628         if (e->type() == QEvent::WhatsThisClicked) {
00629             // if the widget is a top-level window
00630             if (o->isWidgetType() && qobject_cast<QWidget*>(o)->isWindow()) {
00631                 // re-direct to the widget
00632                 QApplication::sendEvent(this, e);
00633             }
00634         }
00635         // special treatment for menus because they directly call QWhatsThis::showText()
00636         // whereby we must be informed for which action the help should be shown
00637         if (o->inherits("QMenu") && QWhatsThis::inWhatsThisMode()) {
00638             bool whatthis = false;
00639             if (e->type() == QEvent::KeyPress) {
00640                 QKeyEvent* ke = static_cast<QKeyEvent*>(e);
00641                 if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_F1)
00642                     whatthis = true;
00643             }
00644             else if (e->type() == QEvent::MouseButtonRelease)
00645                 whatthis = true;
00646             else if (e->type() == QEvent::EnterWhatsThisMode)
00647                 whatthis = true;
00648             if (whatthis) {
00649                 QAction* cur = static_cast<QMenu*>(o)->activeAction();
00650                 if (cur) {
00651                     // get the help text for later usage
00652                     QString s = cur->whatsThis();
00653                     if (s.isEmpty())
00654                         s = static_cast<QMenu*>(o)->whatsThis();
00655                     d->whatstext = s;
00656                 }
00657             }
00658         }
00659         if (o->inherits("QWhatsThat") && e->type() == QEvent::Show) {
00660             // the bubble help should become visible which we avoid by marking the widget
00661             // that it is out of range. Instead of, we show the help viewer
00662             if (!d->whatstext.isEmpty()) {
00663                 QWhatsThisClickedEvent e(d->whatstext);
00664                 QApplication::sendEvent(this, &e);
00665             }
00666             static_cast<QWidget *>(o)->setAttribute(Qt::WA_OutsideWSRange);
00667             return true;
00668         }
00669         if (o->inherits("QWhatsThat") && e->type() == QEvent::Hide) {
00670             // leave what's this mode
00671             if (d->whatsthis) {
00672                 d->whatsthis = false;
00673                 d->whatstext.clear();
00674                 qApp->removeEventFilter(this);
00675             }
00676         }
00677     }
00678 
00679     return QMainWindow::eventFilter(o, e);
00680 }
00681 
00682 void MainWindow::addWindow(MDIView* view)
00683 {
00684     // make workspace parent of view
00685 #if !defined (NO_USE_QT_MDI_AREA)
00686     bool isempty = d->mdiArea->subWindowList().isEmpty();
00687     QMdiSubWindow* child = new QMdiSubWindow(d->mdiArea->viewport());
00688     child->setAttribute(Qt::WA_DeleteOnClose);
00689     child->setWidget(view);
00690     child->setWindowIcon(view->windowIcon());
00691     QMenu* menu = child->systemMenu();
00692     QAction* action = menu->addAction(tr("Close All"));
00693     connect(action, SIGNAL(triggered()), d->mdiArea, SLOT(closeAllSubWindows()));
00694     d->mdiArea->addSubWindow(child);
00695 #else
00696     QWidget* active = d->workspace->activeWindow();
00697     d->workspace->addWindow(view);
00698 #if defined(Q_OS_WIN32)
00699     // avoid dragging problem with not maximized mdi childs which have embedded a GL window
00700     QWidget* p = view->parentWidget();
00701     if (p) {
00702         QWidgetResizeHandler* handler = p->findChild<QWidgetResizeHandler*>();
00703         if (handler) handler->setMovingEnabled(false);
00704     }
00705 #endif
00706 #endif
00707     connect(view, SIGNAL(message(const QString&, int)),
00708             statusBar(), SLOT(showMessage(const QString&, int)));
00709     connect(this, SIGNAL(windowStateChanged(MDIView*)),
00710             view, SLOT(windowStateChanged(MDIView*)));
00711 
00712     // listen to the incoming events of the view
00713     view->installEventFilter(this);
00714 
00715     // show the very first window in maximized mode
00716 #if !defined (NO_USE_QT_MDI_AREA)
00717     if (isempty)
00718 #else
00719     if (d->workspace->windowList().isEmpty())
00720 #endif
00721         view->showMaximized();
00722     else
00723         view->show();
00724 
00725 #if defined(NO_USE_QT_MDI_AREA)
00726     // look if the window was already inserted
00727     for (int i=0; i < d->tabs->count(); i++) {
00728         if (d->tabs->tabData(i).value<QWidget*>() == view)
00729             return;
00730     }
00731 
00732     // being informed when the view is destroyed
00733     connect(view, SIGNAL(destroyed()),
00734             this, SLOT(onWindowDestroyed()));
00735 
00736     // add a new tab to our tabbar
00737     int index=-1;
00738     index = d->tabs->addTab(view->windowIcon(), view->windowTitle());
00739     d->tabs->setTabToolTip(index, view->windowTitle());
00740     QVariant var; var.setValue<QWidget*>(view);
00741     d->tabs->setTabData(index, var);
00742 
00743     tabChanged(view);
00744     if (d->tabs->count() == 1)
00745         d->tabs->show(); // invoke show() for the first tab
00746     d->tabs->update();
00747     d->tabs->setCurrentIndex(index);
00748 #endif
00749 
00750 #if defined (NO_USE_QT_MDI_AREA)
00751     // With the old QWorkspace class we have some strange update problem
00752     // when adding a 3d view and the first view is a web view or text view.
00753     static bool do_hack=true;
00754     MDIView *active_mdi = qobject_cast<MDIView*>(active);
00755     if (do_hack && active_mdi && active_mdi->getTypeId() != view->getTypeId()) {
00756         d->workspace->setActiveWindow(active);
00757         d->workspace->setActiveWindow(view);
00758         do_hack = false; // needs to be done only once
00759     }
00760 #endif
00761 }
00762 
00769 void MainWindow::removeWindow(Gui::MDIView* view)
00770 {
00771     // free all connections
00772     disconnect(view, SIGNAL(message(const QString&, int)),
00773                statusBar(), SLOT(message(const QString&, int )));
00774     disconnect(this, SIGNAL(windowStateChanged(MDIView*)),
00775                view, SLOT(windowStateChanged(MDIView*)));
00776     view->removeEventFilter(this);
00777 
00778 #if defined(NO_USE_QT_MDI_AREA)
00779     for (int i = 0; i < d->tabs->count(); i++) {
00780         if (d->tabs->tabData(i).value<QWidget*>() == view) {
00781             d->tabs->removeTab(i);
00782             if (d->tabs->count() == 0)
00783                 d->tabs->hide(); // no view open any more
00784             break;
00785         }
00786     }
00787 #endif
00788 
00789     // check if the focus widget is a child of the view
00790     QWidget* foc = this->focusWidget();
00791     if (foc) {
00792         QWidget* par = foc->parentWidget();
00793         while (par) {
00794             if (par == view) {
00795                 foc->clearFocus();
00796                 break;
00797             }
00798             par = par->parentWidget();
00799         }
00800     }
00801 
00802 #if defined(NO_USE_QT_MDI_AREA)
00803     // this view is not under control of the main window any more
00804     disconnect(view, SIGNAL(destroyed()),
00805                this, SLOT(onWindowDestroyed()));
00806 #else
00807     QWidget* parent = view->parentWidget();
00808     // The call of 'd->mdiArea->removeSubWindow(parent)' causes the QMdiSubWindow
00809     // to loose its parent and thus the notification in QMdiSubWindow::closeEvent
00810     // of other mdi windows to get maximized if this window is maximized will fail.
00811     // However, we must let it here otherwise deleting MDI child views directly can
00812     // cause other problems.
00813     d->mdiArea->removeSubWindow(parent);
00814     parent->deleteLater();
00815 #endif
00816 }
00817 
00818 void MainWindow::tabChanged(MDIView* view)
00819 {
00820 #if defined(NO_USE_QT_MDI_AREA)
00821     for (int i = 0; i < d->tabs->count(); i++) {
00822         if (d->tabs->tabData(i).value<QWidget*>() == view) {
00823             QString cap = view->windowTitle();
00824             int lastIndex = cap.lastIndexOf(QString::fromAscii("[*]"));
00825             if (lastIndex > 0) {
00826                 cap = cap.left(lastIndex);
00827                 if (view->isWindowModified())
00828                     cap = QString::fromAscii("%1*").arg(cap);
00829             }
00830             d->tabs->setTabToolTip(i, cap);
00831             
00832             // remove path separators
00833             int pos = cap.lastIndexOf(QLatin1Char('/'));
00834             cap = cap.mid( pos+1 );
00835             pos = cap.lastIndexOf(QLatin1Char('\\'));
00836             cap = cap.mid( pos+1 );
00837 
00838             d->tabs->setTabText(i, cap);
00839             break;
00840         }
00841     }
00842 #endif
00843 }
00844 
00845 #if defined(NO_USE_QT_MDI_AREA)
00846 void MainWindow::onWindowDestroyed()
00847 {
00848     QObject* view = (QObject*)sender();
00849     for (int i = 0; i < d->tabs->count(); i++) {
00850         if (d->tabs->tabData(i).value<QWidget*>() == view) {
00851             d->tabs->removeTab(i);
00852             if (d->tabs->count() == 0)
00853                 d->tabs->hide(); // no view open any more
00854             break;
00855         }
00856     }
00857 }
00858 
00859 void MainWindow::onTabSelected(int i)
00860 {
00861     QVariant var = d->tabs->tabData(i);
00862     if (var.isValid() && var.canConvert<QWidget*>()) {
00863         QWidget* view = var.value<QWidget*>();
00864         if (view && !view->hasFocus())
00865             view->setFocus();
00866     }
00867 }
00868 
00869 void MainWindow::setActiveWindow(MDIView* view)
00870 {
00871     d->workspace->setActiveWindow(view);
00872     d->activeView = view;
00873     Application::Instance->viewActivated(view);
00874 }
00875 #else
00876 void MainWindow::tabCloseRequested(int index)
00877 {
00878     QTabBar* tab = d->mdiArea->findChild<QTabBar*>();
00879     if (index < 0 || index >= tab->count())
00880         return;
00881 
00882     const QList<QMdiSubWindow *> subWindows = d->mdiArea->subWindowList();
00883     Q_ASSERT(index < subWindows.size());
00884 
00885     QMdiSubWindow *subWindow = d->mdiArea->subWindowList().at(index);
00886     Q_ASSERT(subWindow);
00887     subWindow->close();
00888 }
00889 
00890 void MainWindow::onSetActiveSubWindow(QWidget *window)
00891 {
00892     if (!window)
00893         return;
00894     d->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(window));
00895 }
00896 
00897 void MainWindow::setActiveWindow(MDIView* view)
00898 {
00899     onSetActiveSubWindow(view->parentWidget());
00900     d->activeView = view;
00901     Application::Instance->viewActivated(view);
00902 }
00903 #endif
00904 
00905 #if !defined (NO_USE_QT_MDI_AREA)
00906 void MainWindow::onWindowActivated(QMdiSubWindow* w)
00907 #else
00908 void MainWindow::onWindowActivated(QWidget* w)
00909 #endif
00910 {
00911 #if !defined (NO_USE_QT_MDI_AREA)
00912     if (!w) return;
00913     MDIView* view = dynamic_cast<MDIView*>(w->widget());
00914 #else
00915      MDIView* view = dynamic_cast<MDIView*>(w);
00916 #endif
00917 
00918     // Even if windowActivated() signal is emitted mdi doesn't need to be a top-level window.
00919     // This happens e.g. if two windows are top-level and one of them gets docked again.
00920     // QWorkspace emits the signal then even though the other window is in front.
00921     // The consequence is that the docked window becomes the active window and not the undocked
00922     // window on top. This means that all accel events, menu and toolbar actions get redirected
00923     // to the (wrong) docked window.
00924     // But just testing whether the view is active and ignore it if not leads to other more serious problems -
00925     // at least under Linux. It seems to be a problem with the window manager.
00926     // Under Windows it seems to work though it's not really sure that it works reliably.
00927     // Result: So, we accept the first problem to be sure to avoid the second one.
00928     if ( !view /*|| !mdi->isActiveWindow()*/ ) 
00929         return; // either no MDIView or no valid object or no top-level window
00930 
00931     // set active the appropriate window (it needs not to be part of mdiIds, e.g. directly after creation)
00932     d->activeView = view;
00933     Application::Instance->viewActivated(view);
00934 
00935 #if defined(NO_USE_QT_MDI_AREA)
00936     // set the appropriate tab to the new active window
00937     for (int i = 0; i < d->tabs->count(); i++) {
00938         if (d->tabs->tabData(i).value<QWidget*>() == view) {
00939             d->tabs->blockSignals(true);
00940             d->tabs->setCurrentIndex(i);
00941             d->tabs->blockSignals(false);
00942             break;
00943         }
00944     }
00945 #endif
00946 }
00947 
00948 void MainWindow::onWindowsMenuAboutToShow()
00949 {
00950 #if !defined (NO_USE_QT_MDI_AREA)
00951     QList<QMdiSubWindow*> windows = d->mdiArea->subWindowList(QMdiArea::CreationOrder);
00952     QWidget* active = d->mdiArea->activeSubWindow();
00953 #else
00954     QList<QWidget*> windows = d->workspace->windowList(QWorkspace::CreationOrder);
00955     QWidget* active = d->workspace->activeWindow();
00956 #endif
00957 
00958     // We search for the 'Std_WindowsMenu' command that provides the list of actions
00959     CommandManager& cMgr = Application::Instance->commandManager();
00960     Command* cmd = cMgr.getCommandByName("Std_WindowsMenu");
00961     QList<QAction*> actions = qobject_cast<ActionGroup*>(cmd->getAction())->actions();
00962 
00963     // do the connection only once
00964     static bool firstShow = true;
00965     if (firstShow) {
00966         firstShow = false;
00967         QAction* last = actions.isEmpty() ? 0 : actions.last();
00968         for (QList<QAction*>::Iterator it = actions.begin(); it != actions.end(); ++it) {
00969             if (*it == last)
00970                 break; // this is a separator
00971             connect(*it, SIGNAL(triggered()), d->windowMapper, SLOT(map()));
00972         }
00973     }
00974 
00975     int numWindows = std::min<int>(actions.count()-1, windows.count());
00976     for (int index = 0; index < numWindows; index++) {
00977         QWidget* child = windows.at(index);
00978         QAction* action = actions.at(index);
00979         QString text;
00980         QString title = child->windowTitle();
00981         int lastIndex = title.lastIndexOf(QString::fromAscii("[*]"));
00982         if (lastIndex > 0) {
00983             title = title.left(lastIndex);
00984             if (child->isWindowModified())
00985                 title = QString::fromAscii("%1*").arg(title);
00986         }
00987         if (index < 9)
00988             text = QString::fromAscii("&%1 %2").arg(index+1).arg(title);
00989         else
00990             text = QString::fromAscii("%1 %2").arg(index+1).arg(title);
00991         action->setText(text);
00992         action->setVisible(true);
00993         action->setChecked(child == active);
00994         d->windowMapper->setMapping(action, child);
00995     }
00996 
00997     // if less windows than actions
00998     for (int index = numWindows; index < actions.count(); index++)
00999         actions[index]->setVisible(false);
01000     // show the separator
01001     if (numWindows > 0)
01002         actions.last()->setVisible(true);
01003 }
01004 
01005 void MainWindow::onToolBarMenuAboutToShow()
01006 {
01007     QMenu* menu = static_cast<QMenu*>(sender());
01008     menu->clear();
01009     QList<QToolBar*> dock = this->findChildren<QToolBar*>();
01010     for (QList<QToolBar*>::Iterator it = dock.begin(); it != dock.end(); ++it) {
01011         if ((*it)->parentWidget() == this) {
01012             QAction* action = (*it)->toggleViewAction();
01013             action->setToolTip(tr("Toggles this toolbar"));
01014             action->setStatusTip(tr("Toggles this toolbar"));
01015             action->setWhatsThis(tr("Toggles this toolbar"));
01016             menu->addAction(action);
01017         }
01018     }
01019 }
01020 
01021 void MainWindow::onDockWindowMenuAboutToShow()
01022 {
01023     QMenu* menu = static_cast<QMenu*>(sender());
01024     menu->clear();
01025     QList<QDockWidget*> dock = this->findChildren<QDockWidget*>();
01026     for (QList<QDockWidget*>::Iterator it = dock.begin(); it != dock.end(); ++it) {
01027         QAction* action = (*it)->toggleViewAction();
01028         action->setToolTip(tr("Toggles this dockable window"));
01029         action->setStatusTip(tr("Toggles this dockable window"));
01030         action->setWhatsThis(tr("Toggles this dockable window"));
01031         menu->addAction(action);
01032     }
01033 }
01034 
01035 #if !defined (NO_USE_QT_MDI_AREA)
01036 QList<QWidget*> MainWindow::windows(QMdiArea::WindowOrder order) const
01037 {
01038     QList<QWidget*> mdis;
01039     QList<QMdiSubWindow*> wnds = d->mdiArea->subWindowList(order);
01040     for (QList<QMdiSubWindow*>::iterator it = wnds.begin(); it != wnds.end(); ++it) {
01041         mdis << (*it)->widget();
01042     }
01043     return mdis;
01044 }
01045 #else
01046 QList<QWidget*> MainWindow::windows(QWorkspace::WindowOrder order) const
01047 {
01048     return d->workspace->windowList(order);
01049 }
01050 #endif
01051 
01052 // set text to the pane
01053 void MainWindow::setPaneText(int i, QString text)
01054 {
01055     if (i==1) {
01056         d->actionLabel->setText(text);
01057         d->actionTimer->setSingleShot(true);
01058         d->actionTimer->start(5000);
01059     }
01060     else if (i==2) {
01061         d->sizeLabel->setText(text);
01062     }
01063 }
01064 
01065 MDIView* MainWindow::activeWindow(void) const
01066 {
01067     // each activated window notifies this main window when it is activated
01068     return d->activeView;
01069 }
01070 
01071 void MainWindow::closeEvent (QCloseEvent * e)
01072 {
01073     Application::Instance->tryClose(e);
01074     if (e->isAccepted()) {
01075         // Send close event to all non-modal dialogs
01076         QList<QDialog*> dialogs = this->findChildren<QDialog*>();
01077         for (QList<QDialog*>::iterator it = dialogs.begin(); it != dialogs.end(); ++it) {
01078             (*it)->close();
01079         }
01080         QList<MDIView*> mdis = this->findChildren<MDIView*>();
01081         // Force to close any remaining (passive) MDI child views
01082         for (QList<MDIView*>::iterator it = mdis.begin(); it != mdis.end(); ++it) {
01083             (*it)->hide();
01084             (*it)->deleteLater();
01085         }
01086         d->activityTimer->stop();
01087         saveWindowSettings();
01088         delete d->assistant;
01089         d->assistant = 0;
01090 
01091         /*emit*/ mainWindowClosed();
01092         qApp->quit(); // stop the event loop
01093     }
01094 }
01095 
01096 void MainWindow::showEvent(QShowEvent  * /*e*/)
01097 {
01098     // needed for logging
01099     std::clog << "Show main window" << std::endl;
01100     d->visibleTimer->start(15000);
01101 }
01102 
01103 void MainWindow::hideEvent(QHideEvent  * /*e*/)
01104 {
01105     // needed for logging
01106     std::clog << "Hide main window" << std::endl;
01107     d->visibleTimer->stop();
01108 }
01109 
01110 void MainWindow::showMainWindow()
01111 {
01112     // Under certain circumstances it can happen that at startup the main window
01113     // appears for a short moment and disappears immediately. The workaround
01114     // starts a timer to check for the visibility of the main window and call
01115     // ShowWindow() if needed.
01116     // So far, this phenomena only appeared with Qt4.1.4
01117 #if defined(Q_WS_WIN) && (QT_VERSION == 0x040104)
01118     WId id = this->winId();
01119     ShowWindow(id, SW_SHOW);
01120     std::cout << "Force to show main window" << std::endl;
01121 #endif
01122 }
01123 
01124 void MainWindow::delayedStartup()
01125 {
01126     // processing all command line files
01127     App::Application::processCmdLineFiles();
01128 
01129     // Create new document?
01130     ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Document");
01131     if (hGrp->GetBool("CreateNewDoc", false)) {
01132         App::GetApplication().newDocument();
01133     }
01134 }
01135 
01136 void MainWindow::appendRecentFile(const QString& filename)
01137 {
01138     RecentFilesAction *recent = this->findChild<RecentFilesAction *>
01139         (QString::fromAscii("recentFiles"));
01140     if (recent) {
01141         recent->appendFile(filename);
01142     }
01143 }
01144 
01145 void MainWindow::updateActions()
01146 {
01147     static QTime cLastCall;
01148 
01149     if (cLastCall.elapsed() > 250 && isVisible()) {
01150         Application::Instance->commandManager().testActive();
01151         cLastCall.start();
01152     }
01153 
01154     d->activityTimer->setSingleShot(true);
01155     d->activityTimer->start(300);       
01156 }
01157 
01158 void MainWindow::switchToTopLevelMode()
01159 {
01160     QList<QDockWidget*> dw = this->findChildren<QDockWidget*>();
01161     for (QList<QDockWidget*>::Iterator it = dw.begin(); it != dw.end(); ++it) {
01162         (*it)->setParent(0, Qt::Window);
01163         (*it)->show();
01164     }
01165     QList<QWidget*> mdi = getMainWindow()->windows();
01166     for (QList<QWidget*>::Iterator it = mdi.begin(); it != mdi.end(); ++it) {
01167         (*it)->setParent(0, Qt::Window);
01168         (*it)->show();
01169     }
01170 }
01171 
01172 void MainWindow::switchToDockedMode()
01173 {
01174     // Search for all top-level MDI views
01175     QWidgetList toplevel = QApplication::topLevelWidgets();
01176     for (QWidgetList::Iterator it = toplevel.begin(); it != toplevel.end(); ++it) {
01177         Gui::MDIView* view = qobject_cast<MDIView*>(*it);
01178         if (view)
01179             view->setCurrentViewMode(MDIView::Child);
01180     }
01181 }
01182 
01183 void MainWindow::loadWindowSettings()
01184 {
01185     QString vendor = QString::fromAscii(App::Application::Config()["ExeVendor"].c_str());
01186     QString application = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
01187     QString version = QString::fromAscii(App::Application::Config()["ExeVersion"].c_str());
01188     int major = (QT_VERSION >> 0x10) & 0xff;
01189     int minor = (QT_VERSION >> 0x08) & 0xff;
01190     QString qtver = QString::fromAscii("Qt%1.%2").arg(major).arg(minor);
01191     QSettings config(vendor, application);
01192 
01193     config.beginGroup(version);
01194     config.beginGroup(qtver);
01195     this->resize(config.value(QString::fromAscii("Size"), this->size()).toSize());
01196     QPoint pos = config.value(QString::fromAscii("Position"), this->pos()).toPoint();
01197     QRect rect = QApplication::desktop()->availableGeometry();
01198     int x1,x2,y1,y2;
01199     // make sure that the main window is not totally out of the visible rectangle
01200     rect.getCoords(&x1, &y1, &x2, &y2);
01201     pos.setX(qMin(qMax(pos.x(),x1-this->width()+30),x2-30));
01202     pos.setY(qMin(qMax(pos.y(),y1-10),y2-10));
01203     this->move(pos);
01204 
01205     // tmp. disable the report window to suppress some bothering warnings
01206     Base::Console().SetEnabledMsgType("ReportOutput", ConsoleMsgType::MsgType_Wrn, false);
01207     this->restoreState(config.value(QString::fromAscii("MainWindowState")).toByteArray());
01208     std::clog << "Main window restored" << std::endl;
01209     Base::Console().SetEnabledMsgType("ReportOutput", ConsoleMsgType::MsgType_Wrn, true);
01210 
01211     bool max = config.value(QString::fromAscii("Maximized"), false).toBool();
01212     max ? showMaximized() : show();
01213     config.endGroup();
01214     config.endGroup();
01215 
01216     ToolBarManager::getInstance()->restoreState();
01217     std::clog << "Toolbars restored" << std::endl;
01218 }
01219 
01220 void MainWindow::saveWindowSettings()
01221 {
01222     QString vendor = QString::fromAscii(App::Application::Config()["ExeVendor"].c_str());
01223     QString application = QString::fromAscii(App::Application::Config()["ExeName"].c_str());
01224     QString version = QString::fromAscii(App::Application::Config()["ExeVersion"].c_str());
01225     int major = (QT_VERSION >> 0x10) & 0xff;
01226     int minor = (QT_VERSION >> 0x08) & 0xff;
01227     QString qtver = QString::fromAscii("Qt%1.%2").arg(major).arg(minor);
01228     QSettings config(vendor, application);
01229 
01230     config.beginGroup(version);
01231     config.beginGroup(qtver);
01232     config.setValue(QString::fromAscii("Size"), this->size());
01233     config.setValue(QString::fromAscii("Position"), this->pos());
01234     config.setValue(QString::fromAscii("Maximized"), this->isMaximized());
01235     config.setValue(QString::fromAscii("MainWindowState"), this->saveState());
01236     config.endGroup();
01237     config.endGroup();
01238 
01239     DockWindowManager::instance()->saveState();
01240     ToolBarManager::getInstance()->saveState();
01241 }
01242 
01243 void MainWindow::startSplasher(void)
01244 {
01245     // startup splasher
01246     // when running in verbose mode no splasher
01247     if (!(App::Application::Config()["Verbose"] == "Strict") && 
01248          (App::Application::Config()["RunMode"] == "Gui")) {
01249         ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().
01250             GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("General");
01251         // first search for an external imahe file
01252         if (hGrp->GetBool("ShowSplasher", true)) {
01253             d->splashscreen = new SplashScreen(this->splashImage());
01254             d->splashscreen->show();
01255         }
01256         else
01257             d->splashscreen = 0;
01258     }
01259 }
01260 
01261 void MainWindow::stopSplasher(void)
01262 {
01263     if (d->splashscreen) {
01264         d->splashscreen->finish(this);
01265         delete d->splashscreen;
01266         d->splashscreen = 0;
01267     }
01268 }
01269 
01270 QPixmap MainWindow::splashImage() const
01271 {
01272     QPixmap splash_image;
01273     QDir dir(QString::fromUtf8(App::Application::Config()["UserAppData"].c_str()));
01274     QFileInfo fi(dir.filePath(QString::fromAscii("pixmaps/splash_image.png")));
01275     if (fi.isFile() && fi.exists())
01276         splash_image.load(fi.filePath(), "PNG");
01277     if (splash_image.isNull())
01278         splash_image = Gui::BitmapFactory().pixmap(App::Application::Config()["SplashPicture"].c_str());
01279     return splash_image;
01280 }
01281 
01282 void MainWindow::showTipOfTheDay(bool force)
01283 {
01284     // tip of the day?
01285     ParameterGrp::handle
01286     hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->
01287             GetGroup("Preferences")->GetGroup("General");
01288 
01289     const std::map<std::string,std::string>& config = App::Application::Config();
01290     std::map<std::string, std::string>::const_iterator tp = config.find("HideTipOfTheDay");
01291     bool tip = (tp == config.end());
01292 
01293     tip = hGrp->GetBool("Tipoftheday", tip);
01294     if (tip || force) {
01295         Gui::Dialog::DlgTipOfTheDayImp dlg(instance);
01296         dlg.exec();
01297     }
01298 }
01299 
01303 void MainWindow::dropEvent (QDropEvent* e)
01304 {
01305     const QMimeData* data = e->mimeData();
01306     if (data->hasUrls()) {
01307         // pass no document to let create a new one if needed
01308         loadUrls(0, data->urls());
01309     }
01310     else {
01311         QMainWindow::dropEvent(e);
01312     }
01313 }
01314 
01315 void MainWindow::dragEnterEvent (QDragEnterEvent * e)
01316 {
01317     // Here we must allow uri drafs and check them in dropEvent
01318     const QMimeData* data = e->mimeData();
01319     if (data->hasUrls())
01320         e->accept();
01321     else
01322         e->ignore();
01323 }
01324 
01325 QMimeData * MainWindow::createMimeDataFromSelection () const
01326 {
01327     std::vector<SelectionSingleton::SelObj> sel = Selection().getCompleteSelection();
01328     unsigned int memsize=1000; // ~ for the meta-information
01329     std::vector<App::DocumentObject*> obj;
01330     obj.reserve(sel.size());
01331     for (std::vector<SelectionSingleton::SelObj>::iterator it = sel.begin(); it != sel.end(); ++it) {
01332         if (it->pObject) {
01333             obj.push_back(it->pObject);
01334             memsize += it->pObject->getMemSize();
01335         }
01336     }
01337 
01338     // get a pointer to a document
01339     if (obj.empty()) return 0;
01340     App::Document* doc = obj.front()->getDocument();
01341     if (!doc) return 0;
01342 
01343     // if less than ~10 MB
01344     bool use_buffer=(memsize < 0xA00000);
01345     QByteArray res;
01346     try {
01347         res.reserve(memsize);
01348     }
01349     catch (const Base::MemoryException&) {
01350         use_buffer = false;
01351     }
01352 
01353     QString mime;
01354     if (use_buffer) {
01355         mime = QLatin1String("application/x-documentobject");
01356         Base::ByteArrayOStreambuf buf(res);
01357         std::ostream str(&buf);
01358         // need this instance to call MergeDocuments::Save()
01359         MergeDocuments mimeView(doc);
01360         doc->exportObjects(obj, str);
01361     }
01362     else {
01363         mime = QLatin1String("application/x-documentobject-file");
01364         static Base::FileInfo fi(Base::FileInfo::getTempFileName());
01365         Base::ofstream str(fi, std::ios::out | std::ios::binary);
01366         // need this instance to call MergeDocuments::Save()
01367         MergeDocuments mimeView(doc);
01368         doc->exportObjects(obj, str);
01369         str.close();
01370         res = fi.filePath().c_str();
01371     }
01372 
01373     QMimeData *mimeData = new QMimeData();
01374     mimeData->setData(mime,res);
01375     return mimeData;
01376 }
01377 
01378 bool MainWindow::canInsertFromMimeData (const QMimeData * source) const
01379 {
01380     if (!source)
01381         return false;
01382     return source->hasUrls() || 
01383         source->hasFormat(QLatin1String("application/x-documentobject")) ||
01384         source->hasFormat(QLatin1String("application/x-documentobject-file"));
01385 }
01386 
01387 void MainWindow::insertFromMimeData (const QMimeData * mimeData)
01388 {
01389     if (!mimeData)
01390         return;
01391     if (mimeData->hasFormat(QLatin1String("application/x-documentobject"))) {
01392         QByteArray res = mimeData->data(QLatin1String("application/x-documentobject"));
01393         App::Document* doc = App::GetApplication().getActiveDocument();
01394         if (!doc) doc = App::GetApplication().newDocument();
01395 
01396         Base::ByteArrayIStreambuf buf(res);
01397         std::istream in(0);
01398         in.rdbuf(&buf);
01399         MergeDocuments mimeView(doc);
01400         mimeView.importObjects(in);
01401     }
01402     else if (mimeData->hasFormat(QLatin1String("application/x-documentobject-file"))) {
01403         QByteArray res = mimeData->data(QLatin1String("application/x-documentobject-file"));
01404         App::Document* doc = App::GetApplication().getActiveDocument();
01405         if (!doc) doc = App::GetApplication().newDocument();
01406 
01407         Base::FileInfo fi((const char*)res);
01408         Base::ifstream str(fi, std::ios::in | std::ios::binary);
01409         MergeDocuments mimeView(doc);
01410         mimeView.importObjects(str);
01411         str.close();
01412     }
01413     else if (mimeData->hasUrls()) {
01414         // load the files into the active document if there is one, otherwise let create one
01415         loadUrls(App::GetApplication().getActiveDocument(), mimeData->urls());
01416     }
01417 }
01418 
01419 void MainWindow::loadUrls(App::Document* doc, const QList<QUrl>& url)
01420 {
01421     QStringList files;
01422     for (QList<QUrl>::ConstIterator it = url.begin(); it != url.end(); ++it) {
01423         QFileInfo info((*it).toLocalFile());
01424         if (info.exists() && info.isFile()) {
01425             if (info.isSymLink())
01426                 info.setFile(info.readLink());
01427             std::vector<std::string> module = App::GetApplication()
01428                 .getImportModules(info.completeSuffix().toAscii());
01429             if (module.empty()) {
01430                 module = App::GetApplication()
01431                     .getImportModules(info.suffix().toAscii());
01432             }
01433             if (!module.empty()) {
01434                 // ok, we support files with this extension
01435                 files << info.absoluteFilePath();
01436             }
01437             else {
01438                 Base::Console().Message("No support to load file '%s'\n",
01439                     (const char*)info.absoluteFilePath().toUtf8());
01440             }
01441         }
01442     }
01443 
01444     const char *docName = doc ? doc->getName() : "Unnamed";
01445     SelectModule::Dict dict = SelectModule::importHandler(files);
01446     // load the files with the associated modules
01447     for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
01448         // if the passed document name doesn't exist the module should create it, if needed
01449         Application::Instance->importFrom(it.key().toUtf8(), docName, it.value().toAscii());
01450     }
01451 }
01452 
01453 void MainWindow::changeEvent(QEvent *e)
01454 {
01455     if (e->type() == QEvent::LanguageChange) {
01456         d->sizeLabel->setText(tr("Dimension"));
01457     
01458         CommandManager& rclMan = Application::Instance->commandManager();
01459         std::vector<Command*> cmd = rclMan.getAllCommands();
01460         for (std::vector<Command*>::iterator it = cmd.begin(); it != cmd.end(); ++it)
01461             (*it)->languageChange();
01462 
01463         // reload current workbench to retranslate all actions and window titles
01464         Workbench* wb = WorkbenchManager::instance()->active();
01465         if (wb) wb->retranslate();
01466     }
01467     else {
01468         QMainWindow::changeEvent(e);
01469     }
01470 }
01471 
01472 void MainWindow::showMessage (const QString& message, int timeout)
01473 {
01474     QFontMetrics fm(statusBar()->font());
01475     QString msg = fm.elidedText(message, Qt::ElideMiddle, this->width()/2);
01476     this->statusBar()->showMessage(msg, timeout);
01477 }
01478 
01479 // -------------------------------------------------------------
01480 
01481 namespace Gui {
01482 
01491 class CustomMessageEvent : public QEvent
01492 {
01493 public:
01494     enum Type {Msg, Wrn, Err, Log};
01495     CustomMessageEvent(Type t, const QString& s)
01496       : QEvent(QEvent::User), _type(t), msg(s)
01497     { }
01498     ~CustomMessageEvent()
01499     { }
01500     Type type() const
01501     { return _type; }
01502     const QString& message() const
01503     { return msg; }
01504 private:
01505     Type _type;
01506     QString msg;
01507 };
01508 }
01509 
01510 void MainWindow::customEvent(QEvent* e)
01511 {
01512     if (e->type() == QEvent::User) {
01513         Gui::CustomMessageEvent* ce = static_cast<Gui::CustomMessageEvent*>(e);
01514         QString msg = ce->message();
01515         if (ce->type() == CustomMessageEvent::Log) {
01516             if (msg.startsWith(QLatin1String("#Inventor V2.1 ascii "))) {
01517                 Gui::Document *d = Application::Instance->activeDocument();
01518                 if (d) {
01519                     ViewProviderExtern *view = new ViewProviderExtern();
01520                     try {
01521                         view->setModeByString("1",msg.toAscii().constData());
01522                         d->setAnnotationViewProvider("Vdbg",view);
01523                     }
01524                     catch (...) {
01525                         delete view;
01526                     }
01527                 }
01528             }
01529         }
01530         else {
01531             d->actionLabel->setText(msg);
01532             d->actionTimer->setSingleShot(true);
01533             d->actionTimer->start(5000);
01534         }
01535     }
01536 }
01537 
01538 // ----------------------------------------------------------
01539 
01540 StatusBarObserver::StatusBarObserver()
01541   : WindowParameter("OutputWindow")
01542 {
01543     msg = QString::fromAscii("#000000"); // black
01544     wrn = QString::fromAscii("#ffaa00"); // orange
01545     err = QString::fromAscii("#ff0000"); // red
01546     Base::Console().AttachObserver(this);
01547     getWindowParameter()->Attach(this);
01548     getWindowParameter()->NotifyAll();
01549 }
01550 
01551 StatusBarObserver::~StatusBarObserver()
01552 {
01553     getWindowParameter()->Detach(this);
01554     Base::Console().DetachObserver(this);
01555 }
01556 
01557 void StatusBarObserver::OnChange(Base::Subject<const char*> &rCaller, const char * sReason)
01558 {
01559     ParameterGrp& rclGrp = ((ParameterGrp&)rCaller);
01560     if (strcmp(sReason, "colorText") == 0) {
01561         unsigned long col = rclGrp.GetUnsigned( sReason );
01562         this->msg = QColor((col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff).name();
01563     }
01564     else if (strcmp(sReason, "colorWarning") == 0) {
01565         unsigned long col = rclGrp.GetUnsigned( sReason );
01566         this->wrn = QColor((col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff).name();
01567     }
01568     else if (strcmp(sReason, "colorError") == 0) {
01569         unsigned long col = rclGrp.GetUnsigned( sReason );
01570         this->err = QColor((col >> 24) & 0xff,(col >> 16) & 0xff,(col >> 8) & 0xff).name();
01571     }
01572 }
01573 
01577 void StatusBarObserver::Message(const char * m)
01578 {
01579     // Send the event to the main window to allow thread-safety. Qt will delete it when done.
01580     QString txt = QString::fromAscii("<font color=\"%1\">%2</font>").arg(this->msg).arg(QString::fromUtf8(m));
01581     CustomMessageEvent* ev = new CustomMessageEvent(CustomMessageEvent::Msg, txt);
01582     QApplication::postEvent(getMainWindow(), ev);
01583 }
01584 
01588 void StatusBarObserver::Warning(const char *m)
01589 {
01590     // Send the event to the main window to allow thread-safety. Qt will delete it when done.
01591     QString txt = QString::fromAscii("<font color=\"%1\">%2</font>").arg(this->wrn).arg(QString::fromUtf8(m));
01592     CustomMessageEvent* ev = new CustomMessageEvent(CustomMessageEvent::Wrn, txt);
01593     QApplication::postEvent(getMainWindow(), ev);
01594 }
01595 
01599 void StatusBarObserver::Error  (const char *m)
01600 {
01601     // Send the event to the main window to allow thread-safety. Qt will delete it when done.
01602     QString txt = QString::fromAscii("<font color=\"%1\">%2</font>").arg(this->err).arg(QString::fromUtf8(m));
01603     CustomMessageEvent* ev = new CustomMessageEvent(CustomMessageEvent::Err, txt);
01604     QApplication::postEvent(getMainWindow(), ev);
01605 }
01606 
01610 void StatusBarObserver::Log(const char *m)
01611 {
01612     // Send the event to the main window to allow thread-safety. Qt will delete it when done.
01613     CustomMessageEvent* ev = new CustomMessageEvent(CustomMessageEvent::Log, QString::fromUtf8(m));
01614     QApplication::postEvent(getMainWindow(), ev);
01615 }
01616 
01617 
01618 #include "moc_MainWindow.cpp"

Generated on Wed Nov 23 19:00:21 2011 for FreeCAD by  doxygen 1.6.1