~choreonoid/choreonoid/debian

« back to all changes in this revision

Viewing changes to src/Base/MainWindow.cpp

  • Committer: Thomas Moulard
  • Date: 2012-10-23 12:43:24 UTC
  • Revision ID: git-v1:351cf736ad49bc7a9a7b9767dee760a013517a5d
Tags: upstream/1.1.0
ImportedĀ UpstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
   @author Shin'ichiro Nakaoka
 
3
*/
 
4
 
 
5
#include "MainWindow.h"
 
6
#include "App.h"
 
7
#include "View.h"
 
8
#include "ToolBar.h"
 
9
#include "ToolBarArea.h"
 
10
#include "InfoBar.h"
 
11
#include "MenuManager.h"
 
12
#include "AppConfig.h"
 
13
#include <cnoid/YamlNodes>
 
14
#include <QSplitter>
 
15
#include <QTabWidget>
 
16
#include <QTabBar>
 
17
#include <QMouseEvent>
 
18
#include <QApplication>
 
19
#include <QBoxLayout>
 
20
#include <QRubberBand>
 
21
#include <QFileDialog>
 
22
#include <boost/bind.hpp>
 
23
#include <boost/tuple/tuple.hpp>
 
24
#include <boost/filesystem.hpp>
 
25
#include <set>
 
26
#include <bitset>
 
27
#include <iostream>
 
28
 
 
29
#include "gettext.h"
 
30
 
 
31
using namespace std;
 
32
using namespace boost;
 
33
using namespace cnoid;
 
34
 
 
35
namespace {
 
36
 
 
37
    const bool TRACE_FUNCTIONS = false;
 
38
 
 
39
    MainWindow* mainWindow = 0;
 
40
 
 
41
    enum DropArea { OVER = -1, LEFT = 0, TOP, RIGHT, BOTTOM, NUM_DROP_AREAS };
 
42
    const int SPLIT_DISTANCE_THRESHOLD = 35;
 
43
 
 
44
    class TabWidget : public QTabWidget
 
45
    {
 
46
    public:
 
47
        TabWidget(MainWindowImpl* mwi, QWidget* parent = 0);
 
48
 
 
49
        int addView(View* view) {
 
50
            return addTab(view, view->windowTitle());
 
51
        }
 
52
            
 
53
        QTabBar* tabBar() const { return QTabWidget::tabBar(); }
 
54
        virtual bool eventFilter(QObject* object, QEvent* event);
 
55
 
 
56
        // For the whole tab widget dragging
 
57
        //virtual void mousePressEvent(QMouseEvent *event);
 
58
        //virtual void mouseMoveEvent(QMouseEvent *event);
 
59
        //virtual void mouseReleaseEvent(QMouseEvent *event);
 
60
 
 
61
        MainWindowImpl* mwi;
 
62
    };
 
63
}
 
64
 
 
65
namespace cnoid {
 
66
    
 
67
    class MainWindowImpl //: public boost::signals::trackable
 
68
    {
 
69
    public:
 
70
        MainWindow* self;
 
71
 
 
72
        MainWindowImpl(MainWindow* self, const char* appName, ExtensionManager* ext);
 
73
        ~MainWindowImpl();
 
74
 
 
75
        void setupMenus(ExtensionManager* ext);
 
76
        void createDefaultPanes();
 
77
 
 
78
        bool addView(const std::string& pluginName, View* view);
 
79
        bool removeView(View* view);
 
80
 
 
81
        void showFirst();
 
82
        void onFullScreenToggled(bool on);
 
83
        void resizeEvent(QResizeEvent* event);
 
84
        void keyPressEvent(QKeyEvent* event);
 
85
 
 
86
        bool viewTabMousePressEvent(TabWidget* pane, QMouseEvent* event);
 
87
        bool viewTabMouseMoveEvent(TabWidget* pane, QMouseEvent* event);
 
88
        bool viewTabMouseReleaseEvent(TabWidget* pane, QMouseEvent *event);
 
89
        
 
90
        void startViewDrag(View* view);
 
91
        void dragView(QMouseEvent* event);
 
92
        void dragViewInsidePane(const QPoint& posInDestPane);
 
93
        void dropViewInsidePane();
 
94
        void dragViewOutsidePane();
 
95
        void dropViewOutsidePane();
 
96
        void removePaneIfEmpty(TabWidget* pane);
 
97
        void clearAllPanes();
 
98
        void clearAllPanesSub(QSplitter* splitter);
 
99
        void clearEmptyPanes();
 
100
 
 
101
        void onSaveLayout();
 
102
        void onSaveLayoutAs();
 
103
        void storeLayout(YamlMappingPtr layout);
 
104
        YamlMapping* storeSplitterState(QSplitter* splitter);
 
105
        YamlMapping* storePaneState(TabWidget* pane);
 
106
        void onLoadLayout();
 
107
        void onLoadLayoutAs();
 
108
        void restoreLayout(const YamlMappingPtr layout);
 
109
        QWidget* restoreSplitterState(const YamlMapping& state, TabWidget*& out_firstPane);
 
110
        TabWidget* restorePaneState(const YamlMapping& state);
 
111
        void restoreDefaultLayout();
 
112
        
 
113
        std::vector<View*> views;
 
114
 
 
115
        typedef multimap<QString, View*> NameToViewMap;
 
116
        NameToViewMap nameToViewMap;
 
117
        typedef set<View*> ViewSet;
 
118
        ViewSet storedViews;
 
119
 
 
120
        std::vector<ToolBar*> toolBars;
 
121
 
 
122
        TabWidget* areaToPane[View::NUM_AREAS];
 
123
 
 
124
        struct AreaDetectionInfo {
 
125
            AreaDetectionInfo() {
 
126
                for(int i=0; i < View::NUM_AREAS; ++i){
 
127
                    scores[i] = 0;
 
128
                }
 
129
            }
 
130
            TabWidget* pane;
 
131
            int scores[View::NUM_AREAS];
 
132
        };
 
133
 
 
134
        typedef bitset<NUM_DROP_AREAS> EdgeContactState;
 
135
 
 
136
        ToolBarArea* toolBarArea;
 
137
        
 
138
        QWidget* centralWidget;
 
139
        QVBoxLayout* centralVBox;
 
140
        QSplitter* topSplitter;
 
141
 
 
142
        YamlMappingPtr config;
 
143
        YamlMappingPtr initialLayout;
 
144
 
 
145
        bool isBeforeShowing;
 
146
        bool isBeforeDoingInitialLayout;
 
147
        bool isMaximized;
 
148
        bool isMaximizedJustBeforeFullScreen;
 
149
        bool isFullScreen;
 
150
        QSize normalStateSize;
 
151
        
 
152
        QString currentLayoutFolder;
 
153
 
 
154
        Action* fullScreenCheck;
 
155
 
 
156
        QPoint tabDragStartPosition;
 
157
        bool isViewDragging;
 
158
        TabWidget* dragSrcPane;
 
159
        TabWidget* dragDestPane;
 
160
        bool isViewDraggingOutsidePane;
 
161
        int dropEdge;
 
162
        QRubberBand* rubberBand;
 
163
    };
 
164
}
 
165
 
 
166
 
 
167
TabWidget::TabWidget(MainWindowImpl* mwi, QWidget* parent)
 
168
    : QTabWidget(parent),
 
169
      mwi(mwi)
 
170
{
 
171
    setMovable(true);
 
172
    setUsesScrollButtons(true);
 
173
    tabBar()->installEventFilter(this);
 
174
}
 
175
 
 
176
 
 
177
bool TabWidget::eventFilter(QObject* object, QEvent* event)
 
178
{
 
179
    if(object == tabBar()){
 
180
        switch(event->type()){
 
181
        case QEvent::MouseButtonPress:
 
182
            return mwi->viewTabMousePressEvent(this, static_cast<QMouseEvent*>(event));
 
183
        case QEvent::MouseButtonDblClick:
 
184
            break;
 
185
        case QEvent::MouseButtonRelease:
 
186
            return mwi->viewTabMouseReleaseEvent(this, static_cast<QMouseEvent*>(event));
 
187
        case QEvent::MouseMove:
 
188
            return mwi->viewTabMouseMoveEvent(this, static_cast<QMouseEvent*>(event));
 
189
        default:
 
190
            break;
 
191
        }
 
192
    }
 
193
    return false;
 
194
}
 
195
 
 
196
 
 
197
void MainWindow::initialize(const char* appName, ExtensionManager* ext)
 
198
{
 
199
    if(!mainWindow){
 
200
        new MainWindow(appName, ext);
 
201
    }
 
202
}
 
203
 
 
204
 
 
205
MainWindow* MainWindow::instance()
 
206
{
 
207
    return mainWindow;
 
208
}
 
209
 
 
210
 
 
211
MainWindow::MainWindow(const char* appName, ExtensionManager* ext)
 
212
{
 
213
    mainWindow = this;
 
214
 
 
215
    setWindowTitle(appName);
 
216
    setFocusPolicy(Qt::WheelFocus);
 
217
 
 
218
    impl = new MainWindowImpl(this, appName, ext);
 
219
}
 
220
 
 
221
 
 
222
MainWindowImpl::MainWindowImpl(MainWindow* self, const char* appName, ExtensionManager* ext)
 
223
    : self(self)
 
224
{
 
225
    isBeforeDoingInitialLayout = true;
 
226
    isMaximized = false;
 
227
    isViewDragging = false;
 
228
    
 
229
    centralWidget = new QWidget(self);
 
230
    
 
231
    centralVBox = new QVBoxLayout(centralWidget);
 
232
    centralVBox->setSpacing(0);
 
233
    centralVBox->setContentsMargins(0, 0, 0, 0);
 
234
 
 
235
    toolBarArea = new ToolBarArea(centralWidget);
 
236
    centralVBox->addWidget(toolBarArea);
 
237
 
 
238
    //centralVBox->addSpacing(2);
 
239
    
 
240
    topSplitter = new QSplitter(centralWidget);
 
241
    centralVBox->addWidget(topSplitter, 1);
 
242
    
 
243
    self->setCentralWidget(centralWidget);
 
244
 
 
245
    rubberBand = new QRubberBand(QRubberBand::Rectangle, centralWidget);
 
246
    rubberBand->hide();
 
247
 
 
248
    config = AppConfig::archive()->openMapping("MainWindow");
 
249
 
 
250
    createDefaultPanes();
 
251
 
 
252
    self->setStatusBar(InfoBar::instance());
 
253
 
 
254
    setupMenus(ext);
 
255
 
 
256
    initialLayout = config;
 
257
    toolBarArea->setInitialLayout(config);
 
258
 
 
259
    isBeforeShowing = true;
 
260
 
 
261
    if(TRACE_FUNCTIONS){
 
262
        cout << "size = (" << self->width() << ", " << self->height() << ")" << endl;
 
263
    }
 
264
 
 
265
    normalStateSize.setWidth(config->get("width", self->width()));
 
266
    normalStateSize.setHeight(config->get("height", self->width()));
 
267
}
 
268
 
 
269
 
 
270
MainWindow::~MainWindow()
 
271
{
 
272
    if(impl){
 
273
        delete impl;
 
274
        impl = 0;
 
275
    }
 
276
}
 
277
 
 
278
 
 
279
MainWindowImpl::~MainWindowImpl()
 
280
{
 
281
    config->write("fullScreen", self->isFullScreen());
 
282
    config->write("maximized", isMaximized);
 
283
    config->write("width", normalStateSize.width());
 
284
    config->write("height", normalStateSize.height());
 
285
}
 
286
 
 
287
 
 
288
void MainWindowImpl::setupMenus(ExtensionManager* ext)
 
289
{
 
290
    MenuManager& mm = ext->menuManager();
 
291
 
 
292
    mm.setPath("/" N_("File")).setBackwardMode().addItem(_("Exit"))
 
293
        ->sigTriggered().connect(bind(&MainWindow::close, self));
 
294
 
 
295
    mm.setPath("/" N_("Edit"));
 
296
 
 
297
    mm.setPath("/" N_("View"));
 
298
    
 
299
    fullScreenCheck = mm.addCheckItem(_("Full Screen"));
 
300
    fullScreenCheck->setChecked(config->get("fullScreen", false));
 
301
    fullScreenCheck->sigToggled().connect(bind(&MainWindowImpl::onFullScreenToggled, this, _1));
 
302
 
 
303
    mm.setPath("/View").setPath(N_("Layout"));
 
304
    
 
305
    mm.addItem(_("Save Default Layout"))
 
306
        ->sigTriggered().connect(bind(&MainWindowImpl::onSaveLayout, this));
 
307
    mm.addItem(_("Load Default Layout"))
 
308
        ->sigTriggered().connect(bind(&MainWindowImpl::onLoadLayout, this));
 
309
    mm.addItem(_("Save Layout As"))
 
310
        ->sigTriggered().connect(bind(&MainWindowImpl::onSaveLayoutAs, this));
 
311
    mm.addItem(_("Load Layout As"))
 
312
        ->sigTriggered().connect(bind(&MainWindowImpl::onLoadLayoutAs, this));
 
313
 
 
314
    mm.setPath("/" N_("Tools"));
 
315
    mm.setPath("/" N_("Filters"));
 
316
    mm.setPath("/" N_("Options"));
 
317
    mm.setPath("/").setBackwardMode().setPath(N_("Help"));
 
318
}
 
319
 
 
320
 
 
321
void MainWindowImpl::createDefaultPanes()
 
322
{
 
323
    topSplitter->setOrientation(Qt::Horizontal);
 
324
    
 
325
    QSplitter* vSplitter0 = new QSplitter(Qt::Vertical, topSplitter);
 
326
    topSplitter->addWidget(vSplitter0);
 
327
    
 
328
    areaToPane[View::LEFT_TOP] = new TabWidget(this, vSplitter0);
 
329
    vSplitter0->addWidget(areaToPane[View::LEFT_TOP]);
 
330
    
 
331
    areaToPane[View::LEFT_BOTTOM] = new TabWidget(this, vSplitter0);
 
332
    vSplitter0->addWidget(areaToPane[View::LEFT_BOTTOM]);
 
333
    
 
334
    QSplitter* vSplitter1 = new QSplitter(Qt::Vertical, topSplitter);
 
335
    topSplitter->addWidget(vSplitter1);
 
336
 
 
337
    QSplitter* hSplitter1 = new QSplitter(Qt::Horizontal, vSplitter1);
 
338
    vSplitter1->addWidget(hSplitter1);
 
339
    
 
340
    areaToPane[View::BOTTOM] = new TabWidget(this, vSplitter1);
 
341
    vSplitter1->addWidget(areaToPane[View::BOTTOM]);
 
342
    
 
343
    areaToPane[View::CENTER] = new TabWidget(this, hSplitter1);
 
344
    hSplitter1->addWidget(areaToPane[View::CENTER]);
 
345
    
 
346
    areaToPane[View::RIGHT]  = new TabWidget(this, hSplitter1);
 
347
    hSplitter1->addWidget(areaToPane[View::RIGHT]);
 
348
 
 
349
    QList<int> sizes;
 
350
    sizes << 100 << 600;
 
351
    topSplitter->setSizes(sizes);
 
352
    sizes.last() = 100;
 
353
    vSplitter0->setSizes(sizes);
 
354
    sizes.last() = 40;
 
355
    vSplitter1->setSizes(sizes);
 
356
    sizes.last() = 160;
 
357
    hSplitter1->setSizes(sizes);
 
358
}
 
359
 
 
360
 
 
361
#if 0
 
362
void MainWindowImpl::detectExistingPaneAreas()
 
363
{
 
364
    for(int i=0; i < View::NUM_AREAS; ++i){
 
365
        areaToPane[i] = 0;
 
366
    }
 
367
 
 
368
    vector<AreaDetectionInfo> infos;
 
369
    EdgeContactState edge;
 
370
    edge.set();
 
371
    
 
372
    updateAreaDetectionInfos(topSplitter, edge, infos);
 
373
 
 
374
    if(infos.empty()){
 
375
        createDefaultPanes();
 
376
 
 
377
    } else {
 
378
        areaToPane[View::CENTER] = extractBestAreaMatchPane(infos, View::CENTER);
 
379
        areaToPane[View::LEFT]   = extractBestAreaMatchPane(infos, View::LEFT);
 
380
        areaToPane[View::RIGHT]  = extractBestAreaMatchPane(infos, View::RIGHT);
 
381
        areaToPane[View::BOTTOM] = extractBestAreaMatchPane(infos, View::BOTTOM);
 
382
    }
 
383
}
 
384
 
 
385
 
 
386
void MainWindowImpl::updateAreaDetectionInfos
 
387
(QSplitter* splitter, const EdgeContactState& edge, vector<AreaDetectionInfo>& infos)
 
388
{
 
389
    QWidget* childWidgets[2];
 
390
    childWidgets[0] = splitter->get_child1();
 
391
    childWidgets[1] = splitter->get_child2();
 
392
    bool isSingle = !(childWidgets[0] && childWidgets[1]);
 
393
 
 
394
    for(int i=0; i < 2; ++i){
 
395
        EdgeContactState currentEdge(edge);
 
396
        if(!isSingle){
 
397
            if(dynamic_cast<HSplitter*>(splitter)){
 
398
                currentEdge.reset((i == 0) ? BOTTOM : TOP);
 
399
            } else {
 
400
                currentEdge.reset((i == 0) ? RIGHT : LEFT);
 
401
            }
 
402
        }
 
403
        if(childWidgets[i]){
 
404
            Splitter* childSplitter = dynamic_cast<Splitter*>(childWidgets[i]);
 
405
            if(childSplitter){
 
406
                updateAreaDetectionInfos(childSplitter, currentEdge, infos);
 
407
            } else {
 
408
                Pane* pane = dynamic_cast<Pane*>(childWidgets[i]);
 
409
                if(pane){
 
410
                    AreaDetectionInfo info;
 
411
                    info.pane = pane;
 
412
                    
 
413
                    // calculate scores for area matching
 
414
                    static const int offset = 100000000;
 
415
                    int width = pane->get_width();
 
416
                    int height = pane->get_height();
 
417
 
 
418
                    info.scores[View::CENTER] = (4 - currentEdge.count()) * offset + width * height;
 
419
 
 
420
                    if(currentEdge.test(LEFT) && !currentEdge.test(RIGHT)){
 
421
                        info.scores[View::LEFT] = offset + height;
 
422
                    }
 
423
                    if(currentEdge.test(RIGHT) && !currentEdge.test(LEFT)){
 
424
                        info.scores[View::RIGHT] = offset + height;
 
425
                    }
 
426
                    if(currentEdge.test(BOTTOM) && !currentEdge.test(TOP)){
 
427
                        info.scores[View::BOTTOM] = offset + width;
 
428
                    }
 
429
                    
 
430
                    infos.push_back(info);
 
431
                }
 
432
            }
 
433
        }
 
434
    }
 
435
}
 
436
 
 
437
 
 
438
Pane* MainWindowImpl::extractBestAreaMatchPane(vector<AreaDetectionInfo>& infos, View::LayoutArea area)
 
439
{
 
440
    int topScore = 0;
 
441
    int topIndex = -1;
 
442
 
 
443
    for(int i=0; i < (signed)infos.size(); ++i){
 
444
        int s = infos[i].scores[area];
 
445
        if(s > topScore){
 
446
            topScore = s;
 
447
            topIndex = i;
 
448
        }
 
449
    }
 
450
 
 
451
    Pane* pane = 0;
 
452
    
 
453
    if(topIndex > 0){
 
454
        pane = infos[topIndex].pane;
 
455
        infos.erase(infos.begin() + topIndex);
 
456
    }
 
457
 
 
458
    return pane;
 
459
}
 
460
#endif
 
461
 
 
462
 
 
463
bool MainWindow::addView(const std::string& pluginName, View* view)
 
464
{
 
465
    return impl->addView(pluginName, view);
 
466
}
 
467
 
 
468
 
 
469
bool MainWindowImpl::addView(const std::string& pluginName, View* view)
 
470
{
 
471
    if(view->isManagedByMainWindow){
 
472
        return false;
 
473
    }
 
474
    view->isManagedByMainWindow = true;
 
475
    
 
476
    areaToPane[view->defaultLayoutArea()]->addView(view);
 
477
    views.push_back(view);
 
478
    nameToViewMap.insert(make_pair(view->name(), view));
 
479
 
 
480
    return true;
 
481
}
 
482
 
 
483
 
 
484
bool MainWindow::removeView(View* view)
 
485
{
 
486
    return impl->removeView(view);
 
487
}
 
488
 
 
489
 
 
490
bool MainWindowImpl::removeView(View* view)
 
491
{
 
492
    bool removed = false;
 
493
 
 
494
    if(view && view->isManagedByMainWindow){
 
495
        std::remove(views.begin(), views.end(), view);
 
496
        
 
497
        TabWidget* tab = dynamic_cast<TabWidget*>(view->parentWidget());
 
498
        if(tab){
 
499
            tab->removeTab(tab->indexOf(view));
 
500
        }
 
501
        view->isManagedByMainWindow = false;
 
502
        view->hide();
 
503
        removed = true;
 
504
    }
 
505
 
 
506
    return removed;
 
507
}
 
508
 
 
509
 
 
510
void MainWindow::addToolBar(ToolBar* toolbar)
 
511
{
 
512
    impl->toolBarArea->addToolBar(toolbar);
 
513
}
 
514
 
 
515
 
 
516
std::vector<View*> MainWindow::allViews()
 
517
{
 
518
    return impl->views;
 
519
}
 
520
 
 
521
 
 
522
std::vector<ToolBar*> MainWindow::allToolBars()
 
523
{
 
524
    return impl->toolBarArea->getAllToolBars();
 
525
}
 
526
 
 
527
 
 
528
void MainWindow::setInitialLayout(const YamlMappingPtr layout)
 
529
{
 
530
    if(TRACE_FUNCTIONS){
 
531
        cout << "MainWindow::setInitialLayout()" << endl;
 
532
    }
 
533
    if(impl->isBeforeDoingInitialLayout){
 
534
        impl->initialLayout = layout;
 
535
        impl->toolBarArea->setInitialLayout(layout);
 
536
    }
 
537
}
 
538
 
 
539
 
 
540
void MainWindow::changeEvent(QEvent* event)
 
541
{
 
542
    if(event->type() == QEvent::WindowStateChange){
 
543
        if(TRACE_FUNCTIONS){
 
544
            cout << "MainWindow::changeEvent() of WindowStateChange: " << windowState() << endl;
 
545
        }
 
546
        if(!(windowState() & Qt::WindowFullScreen)){
 
547
            impl->isMaximized = (windowState() & Qt::WindowMaximized);
 
548
        }
 
549
    }
 
550
}
 
551
 
 
552
 
 
553
void MainWindow::show()
 
554
{
 
555
    impl->showFirst();
 
556
}
 
557
 
 
558
 
 
559
void MainWindowImpl::showFirst()
 
560
{
 
561
    if(TRACE_FUNCTIONS){
 
562
        cout << "MainWindowImpl::showFirst()" << endl;
 
563
    }
 
564
    if(isBeforeShowing){
 
565
 
 
566
        //self->resize(normalStateSize);
 
567
        
 
568
        if(config->get("fullScreen", false)){
 
569
            isMaximizedJustBeforeFullScreen = isMaximized;
 
570
            self->showFullScreen();
 
571
        } else if(config->get("maximized", true)){
 
572
            self->showMaximized();
 
573
        } else {
 
574
            self->QMainWindow::show();
 
575
        }
 
576
        isBeforeShowing = false;
 
577
    } else {
 
578
        self->QMainWindow::show();
 
579
    }
 
580
}
 
581
 
 
582
 
 
583
void MainWindowImpl::onFullScreenToggled(bool on)
 
584
{
 
585
    if(on){
 
586
        if(!self->isFullScreen()){
 
587
            isMaximizedJustBeforeFullScreen = isMaximized;
 
588
            self->showFullScreen();
 
589
        }
 
590
    } else {
 
591
        if(self->isFullScreen()){
 
592
            if(isMaximizedJustBeforeFullScreen){
 
593
                self->showMaximized();
 
594
            } else {
 
595
                self->showNormal();
 
596
            }
 
597
        }
 
598
    }
 
599
}
 
600
 
 
601
 
 
602
void MainWindow::resizeEvent(QResizeEvent* event)
 
603
{
 
604
    QMainWindow::resizeEvent(event);
 
605
    impl->resizeEvent(event);
 
606
}
 
607
 
 
608
 
 
609
void MainWindowImpl::resizeEvent(QResizeEvent* event)
 
610
{
 
611
    if(TRACE_FUNCTIONS){
 
612
        cout << "MainWindowImpl::resizeEvent(): size = (";
 
613
        cout << event->size().width() << ", " << event->size().height() << ")";
 
614
        cout << ", isMaximized = " << (self->windowState() & Qt::WindowMaximized) << ", " << isMaximized;
 
615
        cout << ", isVisible = " << self->isVisible() << endl;
 
616
    }
 
617
    
 
618
    if(isBeforeDoingInitialLayout){
 
619
 
 
620
        if(!(self->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) || self->isVisible()){
 
621
 
 
622
            if(TRACE_FUNCTIONS){
 
623
                cout << "MainWindowImpl::resizeEvent(): initializeLayout" << endl;
 
624
            }
 
625
            
 
626
            if(initialLayout){
 
627
                restoreLayout(initialLayout);
 
628
            } else {
 
629
                restoreDefaultLayout();
 
630
            }
 
631
            initialLayout = 0;
 
632
            isBeforeDoingInitialLayout = false;
 
633
        }
 
634
 
 
635
    } else {
 
636
        if(!(self->windowState() &
 
637
             (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen))){ // normal state ?
 
638
            normalStateSize = self->size();
 
639
        }
 
640
    }
 
641
}
 
642
 
 
643
 
 
644
void MainWindow::keyPressEvent(QKeyEvent* event)
 
645
{
 
646
    impl->keyPressEvent(event);
 
647
}
 
648
 
 
649
 
 
650
void MainWindowImpl::keyPressEvent(QKeyEvent* event)
 
651
{
 
652
    switch(event->key()){
 
653
    case Qt::Key_F11:
 
654
        fullScreenCheck->toggle();
 
655
        break;
 
656
 
 
657
    default:
 
658
        break;
 
659
    }
 
660
}
 
661
 
 
662
 
 
663
void MainWindowImpl::restoreDefaultLayout()
 
664
{
 
665
    /*
 
666
    detectExistingPaneAreas();
 
667
    
 
668
    for(ViewSet::iterator p = storedViews.begin(); p != storedViews.end(); ++p){
 
669
        
 
670
        View* view = *p;
 
671
        Pane* pane = areaToPane[view->defaultLayoutArea()];
 
672
        if(!pane){
 
673
            pane = areaToPane[View::CENTER];
 
674
        }
 
675
        pane->appendView(view);
 
676
    }
 
677
    
 
678
    storedViews.clear();
 
679
    topSplitter->show_all();
 
680
    */
 
681
}
 
682
 
 
683
 
 
684
void MainWindow::restoreLayout(const YamlMappingPtr layout)
 
685
{
 
686
    impl->restoreLayout(layout);
 
687
}
 
688
 
 
689
 
 
690
void MainWindowImpl::onLoadLayout()
 
691
{
 
692
    restoreLayout(config);
 
693
}
 
694
 
 
695
 
 
696
void MainWindowImpl::onLoadLayoutAs()
 
697
{
 
698
    QFileDialog dialog(self);
 
699
    dialog.setWindowTitle(_("Open a layout"));
 
700
    dialog.setFileMode(QFileDialog::ExistingFile);
 
701
    dialog.setViewMode(QFileDialog::List);
 
702
    dialog.setLabelText(QFileDialog::Accept, _("Open"));
 
703
    dialog.setLabelText(QFileDialog::Reject, _("Cancel"));
 
704
 
 
705
    QStringList filters;
 
706
    filters << _("Layout files (*.conf)");
 
707
    filters << _("Any files (*)");
 
708
    dialog.setNameFilters(filters);
 
709
 
 
710
    if(!currentLayoutFolder.isEmpty()){
 
711
        dialog.setDirectory(currentLayoutFolder);
 
712
    }
 
713
    if(dialog.exec()){
 
714
        currentLayoutFolder = dialog.directory().absolutePath();
 
715
        AppConfig::load(dialog.selectedFiles().front().toStdString());
 
716
        config = AppConfig::archive()->openMapping("MainWindow");
 
717
        restoreLayout(config);
 
718
    }
 
719
}
 
720
 
 
721
 
 
722
void MainWindowImpl::restoreLayout(const YamlMappingPtr layout)
 
723
{
 
724
    if(TRACE_FUNCTIONS){
 
725
        cout << "MainWindowImpl::restoreLayout()" << endl;
 
726
    }
 
727
 
 
728
    /*
 
729
    if(isBeforeDoingInitialLayout){
 
730
        self->setInitialLayout(layout);
 
731
        return;
 
732
    }
 
733
    */
 
734
 
 
735
    if(!isBeforeDoingInitialLayout){
 
736
        toolBarArea->restoreLayout(layout);
 
737
    } else {
 
738
        toolBarArea->doInitialLayout();
 
739
    }
 
740
    
 
741
    const YamlMappingPtr layoutOfViews = layout->findMapping("layoutOfViews");
 
742
 
 
743
    if(layoutOfViews->isValid()){
 
744
 
 
745
        clearAllPanes();
 
746
 
 
747
        TabWidget* firstPane = 0;
 
748
 
 
749
        QWidget* restoredWidget = restoreSplitterState(*layoutOfViews, firstPane);
 
750
 
 
751
        topSplitter = dynamic_cast<QSplitter*>(restoredWidget);
 
752
        
 
753
        if(!topSplitter){
 
754
            topSplitter = new QSplitter();
 
755
            firstPane = dynamic_cast<TabWidget*>(restoredWidget);
 
756
            if(!firstPane){
 
757
                firstPane = new TabWidget(this);
 
758
            }
 
759
            topSplitter->addWidget(firstPane);
 
760
        }
 
761
        centralVBox->addWidget(topSplitter, 1);
 
762
 
 
763
        for(ViewSet::iterator p = storedViews.begin(); p != storedViews.end(); ++p){
 
764
            firstPane->addView(*p);
 
765
        }
 
766
        storedViews.clear();
 
767
    }
 
768
}
 
769
 
 
770
 
 
771
void MainWindowImpl::clearAllPanes()
 
772
{
 
773
    if(TRACE_FUNCTIONS){
 
774
        cout << "clearAllPanes" << endl;
 
775
    }
 
776
    clearAllPanesSub(topSplitter);
 
777
    delete topSplitter;
 
778
    topSplitter = 0;
 
779
    if(TRACE_FUNCTIONS){
 
780
        cout << "End of clearAllPanes" << endl;
 
781
    }
 
782
}
 
783
 
 
784
 
 
785
void MainWindowImpl::clearAllPanesSub(QSplitter* splitter)
 
786
{
 
787
    if(TRACE_FUNCTIONS){
 
788
        cout << "clearAllPanesSub" << endl;
 
789
    }
 
790
    
 
791
    for(int i=0; i < splitter->count(); ++i){
 
792
        QSplitter* childSplitter = dynamic_cast<QSplitter*>(splitter->widget(i));
 
793
        if(childSplitter){
 
794
            clearAllPanesSub(childSplitter);
 
795
        } else {
 
796
            TabWidget* pane = dynamic_cast<TabWidget*>(splitter->widget(i));
 
797
            if(pane){
 
798
                for(int i=0; i < pane->count(); ++i){
 
799
                    View* view = dynamic_cast<View*>(pane->widget(i));
 
800
                    if(view){
 
801
                        storedViews.insert(view);
 
802
                    }
 
803
                }
 
804
                while(pane->count() > 0){
 
805
                    int index = pane->count() - 1;
 
806
                    QWidget* view = pane->widget(index);
 
807
                    pane->removeTab(index);
 
808
                    view->hide();
 
809
                    view->setParent(centralWidget);
 
810
                }
 
811
            }
 
812
        }
 
813
    }
 
814
}  
 
815
 
 
816
 
 
817
QWidget* MainWindowImpl::restoreSplitterState(const YamlMapping& state, TabWidget*& out_firstPane)
 
818
{
 
819
    if(TRACE_FUNCTIONS){
 
820
        cout << "MainWindowImpl::restoreSplitterState" << endl;
 
821
    }
 
822
    
 
823
    QWidget* restoredWidget = 0;
 
824
    QWidget* childWidgets[2] = { 0, 0 };
 
825
    
 
826
    const YamlSequence& children = *state.findSequence("children");
 
827
    if(children.isValid()){
 
828
        int numChildren = std::min(children.size(), 2);
 
829
        for(int i=0; i < numChildren; ++i){
 
830
            if(children[i].isMapping()){
 
831
                const YamlMapping& childState = *children[i].toMapping();
 
832
                string type;
 
833
                if(childState.read("type", type)){
 
834
                    if(type == "splitter"){
 
835
                        childWidgets[i] = restoreSplitterState(childState, out_firstPane);
 
836
                    } else if(type == "pane"){
 
837
                        TabWidget* pane = restorePaneState(childState);
 
838
                        if(pane){
 
839
                            childWidgets[i] = pane;
 
840
                            if(!out_firstPane){
 
841
                                out_firstPane = pane;
 
842
                            }
 
843
                        }
 
844
                    }
 
845
                }
 
846
            }
 
847
        }
 
848
 
 
849
        if(childWidgets[0] && childWidgets[1]){
 
850
 
 
851
            QSplitter* splitter = new QSplitter();
 
852
 
 
853
            string orientation;
 
854
            if(state.read("orientation", orientation)){
 
855
                splitter->setOrientation((orientation == "vertical") ? Qt::Vertical : Qt::Horizontal);
 
856
            }
 
857
 
 
858
            splitter->addWidget(childWidgets[0]);
 
859
            splitter->addWidget(childWidgets[1]);
 
860
 
 
861
            const YamlSequence& sizes = *state.findSequence("sizes");
 
862
            if(sizes.isValid() && sizes.size() == 2){
 
863
                QList<int> s;
 
864
                int size;
 
865
                for(int i=0; i < 2; ++i){
 
866
                    if(sizes[i].read(size)){
 
867
                        s.push_back(size);
 
868
                    }
 
869
                }
 
870
                splitter->setSizes(s);
 
871
            }
 
872
            restoredWidget = splitter;
 
873
            
 
874
        } else {
 
875
            for(int i=0; i < 2; ++i){
 
876
                if(childWidgets[i]){
 
877
                    restoredWidget = childWidgets[i];
 
878
                    break;
 
879
                }
 
880
            }
 
881
        }
 
882
    }
 
883
 
 
884
    return restoredWidget;
 
885
}
 
886
 
 
887
 
 
888
TabWidget* MainWindowImpl::restorePaneState(const YamlMapping& state)
 
889
{
 
890
    if(TRACE_FUNCTIONS){
 
891
        cout << "MainWindowImpl::restorePaneState" << endl;
 
892
    }
 
893
    
 
894
    TabWidget* pane = 0;
 
895
    const YamlSequence& viewNames = *state.findSequence("views");
 
896
    
 
897
    if(viewNames.isValid() && !viewNames.empty()){
 
898
        pane = new TabWidget(this);
 
899
        QString currentViewName(state.get("current", "").c_str());
 
900
        for(int i=0; i < viewNames.size(); ++i){
 
901
            if(viewNames[i].isString()){
 
902
                NameToViewMap::iterator p, upper_bound;
 
903
                tie(p, upper_bound) = nameToViewMap.equal_range(viewNames[i].toString().c_str());
 
904
                if(p != upper_bound){
 
905
                    View* view = p->second;
 
906
                    ViewSet::iterator q = storedViews.find(view);
 
907
                    if(q != storedViews.end()){
 
908
                        storedViews.erase(q);
 
909
                        pane->addView(view);
 
910
                        if(view->name() == currentViewName){
 
911
                            pane->setCurrentIndex(i);
 
912
                        }
 
913
                    }
 
914
                }
 
915
            }
 
916
        }
 
917
        if(pane->count() == 0){
 
918
            delete pane;
 
919
            pane = 0;
 
920
        }
 
921
    }
 
922
 
 
923
    return pane;
 
924
}
 
925
 
 
926
 
 
927
void MainWindow::storeLayout(YamlMappingPtr layout)
 
928
{
 
929
    impl->storeLayout(layout);
 
930
    AppConfig::flush();
 
931
}
 
932
 
 
933
 
 
934
void MainWindowImpl::onSaveLayout()
 
935
{
 
936
    storeLayout(config);
 
937
}
 
938
 
 
939
 
 
940
void MainWindowImpl::onSaveLayoutAs()
 
941
{
 
942
    QFileDialog dialog(self);
 
943
    dialog.setWindowTitle(_("Save a layout"));
 
944
    dialog.setFileMode(QFileDialog::AnyFile);
 
945
    dialog.setViewMode(QFileDialog::List);
 
946
    dialog.setLabelText(QFileDialog::Accept, _("Save"));
 
947
    dialog.setLabelText(QFileDialog::Reject, _("Cancel"));
 
948
    
 
949
    QStringList filters;
 
950
    filters << _("Layout files (*.conf)");
 
951
    filters << _("Any files (*)");
 
952
    dialog.setNameFilters(filters);
 
953
    
 
954
    if(!currentLayoutFolder.isEmpty()){
 
955
        dialog.setDirectory(currentLayoutFolder);
 
956
    }
 
957
    if(dialog.exec()){
 
958
        currentLayoutFolder = dialog.directory().absolutePath();
 
959
        string filename(dialog.selectedFiles().front().toStdString());
 
960
        string ext = filesystem::extension(filesystem::path(filename));
 
961
        if(ext != ".conf"){
 
962
            filename += ".conf";
 
963
        }
 
964
        storeLayout(config);
 
965
        AppConfig::save(filename);
 
966
    }
 
967
}
 
968
 
 
969
 
 
970
void MainWindowImpl::storeLayout(YamlMappingPtr layout)
 
971
{
 
972
    try {
 
973
        layout->insert("layoutOfViews", storeSplitterState(topSplitter));
 
974
        toolBarArea->storeLayout(layout);
 
975
    }
 
976
    catch(const YamlNode::Exception& ex){
 
977
        cout << ex.message() << endl;
 
978
    }
 
979
}
 
980
 
 
981
 
 
982
YamlMapping* MainWindowImpl::storeSplitterState(QSplitter* splitter)
 
983
{
 
984
    YamlMapping* state = new YamlMapping();
 
985
    
 
986
    state->write("type", "splitter");
 
987
 
 
988
    if(splitter->count() == 2){
 
989
        state->write("orientation", (splitter->orientation() == Qt::Vertical) ? "vertical" : "horizontal");
 
990
        YamlSequence* sizeSeq = state->createSequence("sizes");
 
991
        QList<int> sizes = splitter->sizes();
 
992
        for(int i=0; i < sizes.size(); ++i){
 
993
            sizeSeq->append(sizes[i]);
 
994
        }
 
995
    }
 
996
 
 
997
    YamlSequence* children = state->createSequence("children");
 
998
 
 
999
    for(int i=0; i < splitter->count(); ++i){
 
1000
        QSplitter* childSplitter = dynamic_cast<QSplitter*>(splitter->widget(i));
 
1001
        if(childSplitter){
 
1002
            children->append(storeSplitterState(childSplitter));
 
1003
        } else {
 
1004
            TabWidget* pane = dynamic_cast<TabWidget*>(splitter->widget(i));
 
1005
            if(pane && pane->count() > 0){
 
1006
                children->append(storePaneState(pane));
 
1007
            }
 
1008
        }
 
1009
    }
 
1010
 
 
1011
    return state;
 
1012
}
 
1013
 
 
1014
 
 
1015
YamlMapping* MainWindowImpl::storePaneState(TabWidget* pane)
 
1016
{
 
1017
    YamlMapping* state = new YamlMapping();
 
1018
    
 
1019
    state->write("type", "pane");
 
1020
    
 
1021
    YamlSequence* views = state->createFlowStyleSequence("views");
 
1022
    const int n = pane->count();
 
1023
    for(int i=0; i < n; ++i){
 
1024
        View* view = dynamic_cast<View*>(pane->widget(i));
 
1025
        if(view){
 
1026
            const string name(view->name().toStdString());
 
1027
            views->append(name, YAML_DOUBLE_QUOTED);
 
1028
            if(i == pane->currentIndex()){
 
1029
                state->write("current", name, YAML_DOUBLE_QUOTED);
 
1030
            }
 
1031
        }
 
1032
    }
 
1033
    return state;
 
1034
}
 
1035
 
 
1036
 
 
1037
void MainWindowImpl::clearEmptyPanes()
 
1038
{
 
1039
    
 
1040
}
 
1041
 
 
1042
 
 
1043
bool MainWindowImpl::viewTabMousePressEvent(TabWidget* pane, QMouseEvent* event)
 
1044
{            
 
1045
    if(event->button() == Qt::LeftButton){
 
1046
        tabDragStartPosition = event->pos();
 
1047
    }
 
1048
    return false;
 
1049
}
 
1050
 
 
1051
 
 
1052
bool MainWindowImpl::viewTabMouseMoveEvent(TabWidget* pane, QMouseEvent* event)
 
1053
{
 
1054
    if(!isViewDragging){
 
1055
        if(event->buttons() & Qt::LeftButton){
 
1056
            if((event->pos() - tabDragStartPosition).manhattanLength() > QApplication::startDragDistance()){
 
1057
                if(!pane->tabBar()->geometry().contains(event->pos())){
 
1058
                    View* view = dynamic_cast<View*>(pane->currentWidget());
 
1059
                    if(view){
 
1060
                        isViewDragging = true;
 
1061
                        dragSrcPane = pane;
 
1062
                        startViewDrag(view);
 
1063
                    }
 
1064
                }
 
1065
            }
 
1066
        }
 
1067
    } else {
 
1068
        dragDestPane = 0;
 
1069
        QWidget* pointed = topSplitter->childAt(topSplitter->mapFromGlobal(event->globalPos()));
 
1070
        while(pointed){
 
1071
            dragDestPane = dynamic_cast<TabWidget*>(pointed);
 
1072
            if(dragDestPane){
 
1073
                dragView(event);
 
1074
                break;
 
1075
            }
 
1076
            pointed = pointed->parentWidget();
 
1077
        }
 
1078
        if(!dragDestPane){
 
1079
            rubberBand->hide();
 
1080
        }
 
1081
    }
 
1082
    return false;
 
1083
}
 
1084
 
 
1085
 
 
1086
bool MainWindowImpl::viewTabMouseReleaseEvent(TabWidget* pane, QMouseEvent *event)
 
1087
{
 
1088
    if(isViewDragging){
 
1089
        if(dragDestPane){
 
1090
            if(isViewDraggingOutsidePane){
 
1091
                dropViewOutsidePane();
 
1092
            } else {
 
1093
                dropViewInsidePane();
 
1094
            }
 
1095
        }
 
1096
        QApplication::restoreOverrideCursor();
 
1097
    }
 
1098
    isViewDragging = false;
 
1099
    return false;
 
1100
}
 
1101
 
 
1102
 
 
1103
void MainWindowImpl::startViewDrag(View* view)
 
1104
{
 
1105
    QApplication::setOverrideCursor(Qt::ClosedHandCursor);
 
1106
}
 
1107
 
 
1108
 
 
1109
void MainWindowImpl::dragView(QMouseEvent* event)
 
1110
{
 
1111
    dropEdge = LEFT;
 
1112
        
 
1113
    QPoint p = topSplitter->mapFromGlobal(event->globalPos());
 
1114
    const int w = topSplitter->width();
 
1115
    const int h = topSplitter->height();
 
1116
    
 
1117
    int distance[4];
 
1118
    distance[LEFT] = p.x();
 
1119
    distance[TOP] = p.y();
 
1120
    distance[RIGHT] = w - p.x();
 
1121
    distance[BOTTOM] = h - p.y();
 
1122
        
 
1123
    for(int i=TOP; i <= BOTTOM; ++i){
 
1124
        if(distance[dropEdge] > distance[i]){
 
1125
            dropEdge = i;
 
1126
        }
 
1127
    }
 
1128
 
 
1129
    isViewDraggingOutsidePane = false;
 
1130
    if(distance[dropEdge] < 8){
 
1131
        isViewDraggingOutsidePane = true;
 
1132
        dragViewOutsidePane();
 
1133
    } else {
 
1134
        dragViewInsidePane(dragDestPane->mapFromGlobal(event->globalPos()));
 
1135
    }
 
1136
}
 
1137
 
 
1138
    
 
1139
void MainWindowImpl::dragViewInsidePane(const QPoint& posInDestPane)
 
1140
{
 
1141
    dropEdge = LEFT;
 
1142
        
 
1143
    const int w = dragDestPane->width();
 
1144
    const int h = dragDestPane->height();
 
1145
    
 
1146
    int distance[4];
 
1147
    distance[LEFT] = posInDestPane.x();
 
1148
    distance[TOP] = posInDestPane.y();
 
1149
    distance[RIGHT] = w - posInDestPane.x();
 
1150
    distance[BOTTOM] = h - posInDestPane.y();
 
1151
        
 
1152
    for(int i=TOP; i <= BOTTOM; ++i){
 
1153
        if(distance[dropEdge] > distance[i]){
 
1154
            dropEdge = i;
 
1155
        }
 
1156
    }
 
1157
 
 
1158
    QRect r;
 
1159
    if(SPLIT_DISTANCE_THRESHOLD < distance[dropEdge]){
 
1160
        r.setRect(0, 0, w, h);
 
1161
        dropEdge = OVER;
 
1162
    } else if(dropEdge == LEFT){
 
1163
        r.setRect(0, 0, w / 2, h);
 
1164
    } else if(dropEdge == TOP){
 
1165
        r.setRect(0, 0, w, h /2);
 
1166
    } else if(dropEdge == RIGHT){
 
1167
        r.setRect(w / 2, 0, w / 2, h);
 
1168
    } else if(dropEdge == BOTTOM){
 
1169
        r.setRect(0, h / 2, w, h / 2);
 
1170
    }
 
1171
 
 
1172
    r.translate(centralWidget->mapFromGlobal(dragDestPane->mapToGlobal(QPoint(0, 0))));
 
1173
    rubberBand->setGeometry(r);
 
1174
    rubberBand->show();
 
1175
}
 
1176
 
 
1177
 
 
1178
void MainWindowImpl::dropViewInsidePane()
 
1179
{
 
1180
    View* view = static_cast<View*>(dragSrcPane->currentWidget());
 
1181
    if(dropEdge == OVER){
 
1182
        int index = dragDestPane->addView(view);
 
1183
        dragDestPane->setCurrentIndex(index);
 
1184
    } else {
 
1185
 
 
1186
        QSize destSize = dragDestPane->size();
 
1187
 
 
1188
        QSplitter* parentSplitter = static_cast<QSplitter*>(dragDestPane->parentWidget());
 
1189
        QList<int> parentSizes = parentSplitter->sizes();
 
1190
        QSplitter* newSplitter = new QSplitter(parentSplitter);
 
1191
        parentSplitter->insertWidget(parentSplitter->indexOf(dragDestPane), newSplitter);
 
1192
        TabWidget* newTabWidget = new TabWidget(this, newSplitter);
 
1193
 
 
1194
        if(dropEdge == LEFT){
 
1195
            newSplitter->setOrientation(Qt::Horizontal);
 
1196
            newSplitter->addWidget(newTabWidget);
 
1197
            newSplitter->addWidget(dragDestPane);
 
1198
        } else if(dropEdge == RIGHT){
 
1199
            newSplitter->setOrientation(Qt::Horizontal);
 
1200
            newSplitter->addWidget(dragDestPane);
 
1201
            newSplitter->addWidget(newTabWidget);
 
1202
        } else if(dropEdge == TOP){
 
1203
            newSplitter->setOrientation(Qt::Vertical);
 
1204
            newSplitter->addWidget(newTabWidget);
 
1205
            newSplitter->addWidget(dragDestPane);
 
1206
        } else {
 
1207
            newSplitter->setOrientation(Qt::Vertical);
 
1208
            newSplitter->addWidget(dragDestPane);
 
1209
            newSplitter->addWidget(newTabWidget);
 
1210
        }
 
1211
        newTabWidget->addView(view);
 
1212
 
 
1213
        int half;
 
1214
        if(newSplitter->orientation() == Qt::Horizontal){
 
1215
            half = destSize.height() / 2;
 
1216
        } else {
 
1217
            half = destSize.width() / 2;
 
1218
        }
 
1219
        QList<int> sizes;
 
1220
        sizes << half << half;
 
1221
        newSplitter->setSizes(sizes);
 
1222
 
 
1223
        parentSplitter->setSizes(parentSizes);
 
1224
    }
 
1225
    if(dragSrcPane->count() > 0){
 
1226
        dragSrcPane->setCurrentIndex(0);
 
1227
    }
 
1228
    removePaneIfEmpty(dragSrcPane);
 
1229
    rubberBand->hide();
 
1230
}
 
1231
 
 
1232
 
 
1233
void MainWindowImpl::dragViewOutsidePane()
 
1234
{
 
1235
    QRect r;
 
1236
    int w = topSplitter->width();
 
1237
    int h = topSplitter->height();
 
1238
    if(dropEdge == LEFT){
 
1239
        r.setRect(0, 0, w / 2, h);
 
1240
    } else if(dropEdge == TOP){
 
1241
        r.setRect(0, 0, w, h /2);
 
1242
    } else if(dropEdge == RIGHT){
 
1243
        r.setRect(w / 2, 0, w / 2, h);
 
1244
    } else if(dropEdge == BOTTOM){
 
1245
        r.setRect(0, h / 2, w, h / 2);
 
1246
    }
 
1247
    r.translate(topSplitter->pos());
 
1248
    rubberBand->setGeometry(r);
 
1249
    rubberBand->show();
 
1250
}
 
1251
 
 
1252
 
 
1253
void MainWindowImpl::dropViewOutsidePane()
 
1254
{
 
1255
    View* view = static_cast<View*>(dragSrcPane->currentWidget());
 
1256
 
 
1257
    QSize size = topSplitter->size();
 
1258
 
 
1259
    if(topSplitter->count() >= 2){
 
1260
        QSplitter* newTopSplitter = new QSplitter(centralWidget);
 
1261
        newTopSplitter->addWidget(topSplitter);
 
1262
        topSplitter = newTopSplitter;
 
1263
        centralVBox->addWidget(topSplitter, 1);
 
1264
    }
 
1265
    TabWidget* newTabWidget = new TabWidget(this, topSplitter);
 
1266
 
 
1267
    if(dropEdge == LEFT){
 
1268
        topSplitter->setOrientation(Qt::Horizontal);
 
1269
        topSplitter->insertWidget(0, newTabWidget);
 
1270
    } else if(dropEdge == RIGHT){
 
1271
        topSplitter->setOrientation(Qt::Horizontal);
 
1272
        topSplitter->addWidget(newTabWidget);
 
1273
    } else if(dropEdge == TOP){
 
1274
        topSplitter->setOrientation(Qt::Vertical);
 
1275
        topSplitter->insertWidget(0, newTabWidget);
 
1276
    } else {
 
1277
        topSplitter->setOrientation(Qt::Vertical);
 
1278
        topSplitter->addWidget(newTabWidget);
 
1279
    }
 
1280
    newTabWidget->addView(view);
 
1281
 
 
1282
    int half;
 
1283
    if(topSplitter->orientation() == Qt::Horizontal){
 
1284
        half = size.height() / 2;
 
1285
    } else {
 
1286
        half = size.width() / 2;
 
1287
    }
 
1288
    QList<int> sizes;
 
1289
    sizes << half << half;
 
1290
    topSplitter->setSizes(sizes);
 
1291
    
 
1292
    removePaneIfEmpty(dragSrcPane);
 
1293
    rubberBand->hide();
 
1294
}
 
1295
 
 
1296
 
 
1297
void MainWindowImpl::removePaneIfEmpty(TabWidget* pane)
 
1298
{
 
1299
    if(pane->count() == 0){
 
1300
        QSplitter* parentSplitter = dynamic_cast<QSplitter*>(pane->parentWidget());
 
1301
        pane->deleteLater();
 
1302
        if(parentSplitter){
 
1303
            if(parentSplitter->count() <= 1){
 
1304
                QSplitter* grandParentSplitter = dynamic_cast<QSplitter*>(parentSplitter->parentWidget());
 
1305
                if(grandParentSplitter){
 
1306
                    if(parentSplitter->count() == 1){
 
1307
                        int parentSplitterIndex = grandParentSplitter->indexOf(parentSplitter);
 
1308
                        grandParentSplitter->insertWidget(parentSplitterIndex, parentSplitter->widget(0));
 
1309
                    }
 
1310
                    delete parentSplitter;
 
1311
                }
 
1312
            }
 
1313
        }
 
1314
    }
 
1315
}