PaneStack.cpp

Go to the documentation of this file.
00001 
00002 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00003 
00004 /*
00005     Sonic Visualiser
00006     An audio file viewer and annotation editor.
00007     Centre for Digital Music, Queen Mary, University of London.
00008     This file copyright 2006 Chris Cannam and QMUL.
00009     
00010     This program is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU General Public License as
00012     published by the Free Software Foundation; either version 2 of the
00013     License, or (at your option) any later version.  See the file
00014     COPYING included with this distribution for more information.
00015 */
00016 
00017 #include "PaneStack.h"
00018 
00019 #include "Pane.h"
00020 #include "widgets/PropertyStack.h"
00021 #include "widgets/IconLoader.h"
00022 #include "layer/Layer.h"
00023 #include "ViewManager.h"
00024 
00025 #include <QApplication>
00026 #include <QHBoxLayout>
00027 #include <QVBoxLayout>
00028 #include <QPainter>
00029 #include <QPalette>
00030 #include <QLabel>
00031 #include <QPushButton>
00032 #include <QSplitter>
00033 #include <QStackedWidget>
00034 
00035 #include <iostream>
00036 
00037 //#define DEBUG_PANE_STACK 1
00038 
00039 PaneStack::PaneStack(QWidget *parent, ViewManager *viewManager) :
00040     QFrame(parent),
00041     m_currentPane(0),
00042     m_splitter(new QSplitter),
00043     m_propertyStackStack(new QStackedWidget),
00044     m_viewManager(viewManager),
00045     m_layoutStyle(PropertyStackPerPaneLayout)
00046 {
00047     QHBoxLayout *layout = new QHBoxLayout;
00048     layout->setMargin(0);
00049     layout->setSpacing(0);
00050 
00051     m_splitter->setOrientation(Qt::Vertical);
00052     m_splitter->setOpaqueResize(false);
00053 
00054     layout->addWidget(m_splitter);
00055     layout->setStretchFactor(m_splitter, 1);
00056     layout->addWidget(m_propertyStackStack);
00057     m_propertyStackStack->hide();
00058 
00059     setLayout(layout);
00060 }
00061 
00062 Pane *
00063 PaneStack::addPane(bool suppressPropertyBox)
00064 {
00065     QFrame *frame = new QFrame;
00066     QHBoxLayout *layout = new QHBoxLayout;
00067     layout->setMargin(0);
00068     layout->setSpacing(2);
00069 
00070     QVBoxLayout *vlayout = new QVBoxLayout;
00071     layout->addLayout(vlayout);
00072     layout->setStretchFactor(vlayout, 0);
00073 
00074     QPushButton *xButton = new QPushButton(frame);
00075     xButton->setIcon(IconLoader().load("cross"));
00076     xButton->setFixedSize(QSize(16, 16));
00077     vlayout->addWidget(xButton);
00078     vlayout->setStretchFactor(xButton, 0);
00079     connect(xButton, SIGNAL(clicked()), this, SLOT(paneDeleteButtonClicked()));
00080 
00081     QLabel *currentIndicator = new QLabel(frame);
00082 //    currentIndicator->setFixedWidth(QPainter(this).fontMetrics().width("x"));
00083     vlayout->addWidget(currentIndicator);
00084     vlayout->setStretchFactor(currentIndicator, 10);
00085     currentIndicator->setScaledContents(true);
00086 
00087     Pane *pane = new Pane(frame);
00088     pane->setViewManager(m_viewManager);
00089     layout->addWidget(pane);
00090     layout->setStretchFactor(pane, 10);
00091 
00092     m_xButtonMap[xButton] = pane;
00093 
00094     QWidget *properties = 0;
00095     if (suppressPropertyBox) {
00096         properties = new QFrame();
00097     } else {
00098         properties = new PropertyStack(frame, pane);
00099         connect(properties, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)),
00100                 this, SLOT(propertyContainerSelected(View *, PropertyContainer *)));
00101         connect(properties, SIGNAL(viewSelected(View  *)),
00102                 this, SLOT(viewSelected(View *)));
00103         connect(properties, SIGNAL(contextHelpChanged(const QString &)),
00104                 this, SIGNAL(contextHelpChanged(const QString &)));
00105     }
00106     if (m_layoutStyle == PropertyStackPerPaneLayout) {
00107         layout->addWidget(properties);
00108     } else {
00109         properties->setParent(m_propertyStackStack);
00110         m_propertyStackStack->addWidget(properties);
00111     }
00112     layout->setStretchFactor(properties, 1);
00113 
00114     PaneRec rec;
00115     rec.pane = pane;
00116     rec.propertyStack = properties;
00117     rec.currentIndicator = currentIndicator;
00118     rec.frame = frame;
00119     rec.layout = layout;
00120     m_panes.push_back(rec);
00121 
00122     frame->setLayout(layout);
00123     m_splitter->addWidget(frame);
00124 
00125     connect(pane, SIGNAL(propertyContainerAdded(PropertyContainer *)),
00126             this, SLOT(propertyContainerAdded(PropertyContainer *)));
00127     connect(pane, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
00128             this, SLOT(propertyContainerRemoved(PropertyContainer *)));
00129     connect(pane, SIGNAL(paneInteractedWith()),
00130             this, SLOT(paneInteractedWith()));
00131     connect(pane, SIGNAL(rightButtonMenuRequested(QPoint)),
00132             this, SLOT(rightButtonMenuRequested(QPoint)));
00133     connect(pane, SIGNAL(dropAccepted(QStringList)),
00134             this, SLOT(paneDropAccepted(QStringList)));
00135     connect(pane, SIGNAL(dropAccepted(QString)),
00136             this, SLOT(paneDropAccepted(QString)));
00137 
00138     emit paneAdded(pane);
00139     emit paneAdded();
00140 
00141     if (!m_currentPane) {
00142         setCurrentPane(pane);
00143     }
00144 
00145     return pane;
00146 }
00147 
00148 void
00149 PaneStack::setPropertyStackMinWidth(int mw)
00150 {
00151     for (std::vector<PaneRec>::iterator i = m_panes.begin();
00152          i != m_panes.end(); ++i) {
00153         i->propertyStack->setMinimumWidth(mw);
00154     }
00155     m_propertyStackMinWidth = mw;
00156 }
00157 
00158 void
00159 PaneStack::setLayoutStyle(LayoutStyle style)
00160 {
00161     if (style == m_layoutStyle) return;
00162     m_layoutStyle = style;
00163 
00164     std::vector<PaneRec>::iterator i;
00165 
00166     switch (style) {
00167 
00168     case NoPropertyStacks:
00169     case SinglePropertyStackLayout:
00170         
00171         for (i = m_panes.begin(); i != m_panes.end(); ++i) {
00172             i->layout->removeWidget(i->propertyStack);
00173             i->propertyStack->setParent(m_propertyStackStack);
00174             m_propertyStackStack->addWidget(i->propertyStack);
00175         }
00176         m_propertyStackStack->setVisible(style != NoPropertyStacks);
00177         break;
00178 
00179     case PropertyStackPerPaneLayout:
00180 
00181         for (i = m_panes.begin(); i != m_panes.end(); ++i) {
00182             m_propertyStackStack->removeWidget(i->propertyStack);
00183             i->propertyStack->setParent(i->frame);
00184             i->layout->addWidget(i->propertyStack);
00185             i->propertyStack->show();
00186         }
00187         m_propertyStackStack->hide();
00188         break;
00189     }
00190 }
00191 
00192 Pane *
00193 PaneStack::getPane(int n)
00194 {
00195     if (n < m_panes.size()) {
00196         return m_panes[n].pane;
00197     } else {
00198         return 0;
00199     }
00200 }
00201 
00202 int
00203 PaneStack::getPaneIndex(Pane *pane)
00204 {
00205     for (int i = 0; i < getPaneCount(); ++i) {
00206         if (pane == getPane(i)) {
00207             return i;
00208         }
00209     }
00210     return -1;
00211 }
00212 
00213 Pane *
00214 PaneStack::getHiddenPane(int n)
00215 {
00216     return m_hiddenPanes[n].pane;
00217 }
00218 
00219 void
00220 PaneStack::deletePane(Pane *pane)
00221 {
00222     std::vector<PaneRec>::iterator i;
00223     bool found = false;
00224 
00225     for (i = m_panes.begin(); i != m_panes.end(); ++i) {
00226         if (i->pane == pane) {
00227             m_panes.erase(i);
00228             found = true;
00229             break;
00230         }
00231     }
00232 
00233     if (!found) {
00234 
00235         for (i = m_hiddenPanes.begin(); i != m_hiddenPanes.end(); ++i) {
00236             if (i->pane == pane) {
00237                 m_hiddenPanes.erase(i);
00238                 found = true;
00239                 break;
00240             }
00241         }
00242 
00243         if (!found) {
00244             std::cerr << "WARNING: PaneStack::deletePane(" << pane << "): Pane not found in visible or hidden panes, not deleting" << std::endl;
00245             return;
00246         }
00247     }
00248 
00249     emit paneAboutToBeDeleted(pane);
00250 
00251     for (std::map<QWidget *, Pane *>::iterator i = m_xButtonMap.begin();
00252          i != m_xButtonMap.end(); ++i) {
00253 
00254         if (i->second == pane) {
00255             m_xButtonMap.erase(i);
00256             break;
00257         }
00258     }
00259 
00260     delete pane->parent();
00261 
00262     if (m_currentPane == pane) {
00263         if (m_panes.size() > 0) {
00264             setCurrentPane(m_panes[0].pane);
00265         } else {
00266             setCurrentPane(0);
00267         }
00268     }
00269 
00270     emit paneDeleted();
00271 }
00272 
00273 int
00274 PaneStack::getPaneCount() const
00275 {
00276     return m_panes.size();
00277 }
00278 
00279 int
00280 PaneStack::getHiddenPaneCount() const
00281 {
00282     return m_hiddenPanes.size();
00283 }
00284 
00285 void
00286 PaneStack::hidePane(Pane *pane)
00287 {
00288     std::vector<PaneRec>::iterator i = m_panes.begin();
00289 
00290     while (i != m_panes.end()) {
00291         if (i->pane == pane) {
00292 
00293             m_hiddenPanes.push_back(*i);
00294             m_panes.erase(i);
00295 
00296             QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
00297             if (pw) pw->hide();
00298 
00299             if (m_currentPane == pane) {
00300                 if (m_panes.size() > 0) {
00301                     setCurrentPane(m_panes[0].pane);
00302                 } else {
00303                     setCurrentPane(0);
00304                 }
00305             }
00306             
00307             return;
00308         }
00309         ++i;
00310     }
00311 
00312     std::cerr << "WARNING: PaneStack::hidePane(" << pane << "): Pane not found in visible panes" << std::endl;
00313     emit paneHidden(pane);
00314     emit paneHidden();
00315 }
00316 
00317 void
00318 PaneStack::showPane(Pane *pane)
00319 {
00320     std::vector<PaneRec>::iterator i = m_hiddenPanes.begin();
00321 
00322     while (i != m_hiddenPanes.end()) {
00323         if (i->pane == pane) {
00324             m_panes.push_back(*i);
00325             m_hiddenPanes.erase(i);
00326             QWidget *pw = dynamic_cast<QWidget *>(pane->parent());
00327             if (pw) pw->show();
00328 
00330 
00331             return;
00332         }
00333         ++i;
00334     }
00335 
00336     std::cerr << "WARNING: PaneStack::showPane(" << pane << "): Pane not found in hidden panes" << std::endl;
00337 }
00338 
00339 void
00340 PaneStack::setCurrentPane(Pane *pane) // may be null
00341 {
00342     if (m_currentPane == pane) return;
00343     
00344     std::vector<PaneRec>::iterator i = m_panes.begin();
00345 
00346     // We used to do this by setting the foreground and background
00347     // role, but it seems the background role is ignored and the
00348     // background drawn transparent in Qt 4.1 -- I can't quite see why
00349     
00350     QPixmap selectedMap(1, 1);
00351     selectedMap.fill(QApplication::palette().color(QPalette::Foreground));
00352     
00353     QPixmap unselectedMap(1, 1);
00354     unselectedMap.fill(QApplication::palette().color(QPalette::Background));
00355 
00356     bool found = false;
00357 
00358     while (i != m_panes.end()) {
00359         if (i->pane == pane) {
00360             i->currentIndicator->setPixmap(selectedMap);
00361             if (m_layoutStyle != PropertyStackPerPaneLayout) {
00362                 m_propertyStackStack->setCurrentWidget(i->propertyStack);
00363             }
00364             found = true;
00365         } else {
00366             i->currentIndicator->setPixmap(unselectedMap);
00367         }
00368         ++i;
00369     }
00370 
00371     if (found || pane == 0) {
00372         m_currentPane = pane;
00373         emit currentPaneChanged(m_currentPane);
00374     } else {
00375         std::cerr << "WARNING: PaneStack::setCurrentPane(" << pane << "): pane is not a visible pane in this stack" << std::endl;
00376     }
00377 }
00378 
00379 void
00380 PaneStack::setCurrentLayer(Pane *pane, Layer *layer) // may be null
00381 {
00382     setCurrentPane(pane);
00383 
00384     if (m_currentPane) {
00385 
00386         std::vector<PaneRec>::iterator i = m_panes.begin();
00387 
00388         while (i != m_panes.end()) {
00389 
00390             if (i->pane == pane) {
00391                 PropertyStack *stack = dynamic_cast<PropertyStack *>
00392                     (i->propertyStack);
00393                 if (stack) {
00394                     if (stack->containsContainer(layer)) {
00395                         stack->setCurrentIndex(stack->getContainerIndex(layer));
00396                         emit currentLayerChanged(pane, layer);
00397                     } else {
00398                         stack->setCurrentIndex
00399                             (stack->getContainerIndex
00400                              (pane->getPropertyContainer(0)));
00401                         emit currentLayerChanged(pane, 0);
00402                     }
00403                 }
00404                 break;
00405             }
00406             ++i;
00407         }
00408     }
00409 }
00410 
00411 Pane *
00412 PaneStack::getCurrentPane() 
00413 {
00414     return m_currentPane;
00415 }
00416 
00417 void
00418 PaneStack::propertyContainerAdded(PropertyContainer *)
00419 {
00420     sizePropertyStacks();
00421 }
00422 
00423 void
00424 PaneStack::propertyContainerRemoved(PropertyContainer *)
00425 {
00426     sizePropertyStacks();
00427 }
00428 
00429 void
00430 PaneStack::propertyContainerSelected(View *client, PropertyContainer *pc)
00431 {
00432     std::vector<PaneRec>::iterator i = m_panes.begin();
00433 
00434     while (i != m_panes.end()) {
00435         PropertyStack *stack = dynamic_cast<PropertyStack *>(i->propertyStack);
00436         if (stack &&
00437             stack->getClient() == client &&
00438             stack->containsContainer(pc)) {
00439             setCurrentPane(i->pane);
00440             break;
00441         }
00442         ++i;
00443     }
00444 
00445     Layer *layer = dynamic_cast<Layer *>(pc);
00446     if (layer) emit currentLayerChanged(m_currentPane, layer);
00447     else emit currentLayerChanged(m_currentPane, 0);
00448 }
00449 
00450 void
00451 PaneStack::viewSelected(View *v)
00452 {
00453     Pane *p = dynamic_cast<Pane *>(v);
00454     if (p) setCurrentPane(p);
00455 }
00456 
00457 void
00458 PaneStack::paneInteractedWith()
00459 {
00460     Pane *pane = dynamic_cast<Pane *>(sender());
00461     if (!pane) return;
00462     setCurrentPane(pane);
00463 }
00464 
00465 void
00466 PaneStack::rightButtonMenuRequested(QPoint position)
00467 {
00468     Pane *pane = dynamic_cast<Pane *>(sender());
00469     if (!pane) return;
00470     emit rightButtonMenuRequested(pane, position);
00471 }
00472 
00473 void
00474 PaneStack::sizePropertyStacks()
00475 {
00476     int maxMinWidth = 0;
00477 
00478     if (m_propertyStackMinWidth > 0) maxMinWidth = m_propertyStackMinWidth;
00479 
00480     for (size_t i = 0; i < m_panes.size(); ++i) {
00481         if (!m_panes[i].propertyStack) continue;
00482 #ifdef DEBUG_PANE_STACK
00483         std::cerr << "PaneStack::sizePropertyStacks: " << i << ": min " 
00484                   << m_panes[i].propertyStack->minimumSizeHint().width() << ", hint "
00485                   << m_panes[i].propertyStack->sizeHint().width() << ", current "
00486                   << m_panes[i].propertyStack->width() << std::endl;
00487 #endif
00488 
00489         if (m_panes[i].propertyStack->sizeHint().width() > maxMinWidth) {
00490             maxMinWidth = m_panes[i].propertyStack->sizeHint().width();
00491         }
00492     }
00493 
00494 #ifdef DEBUG_PANE_STACK
00495     std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl;
00496 #endif
00497 
00498     int setWidth = maxMinWidth;
00499 
00500     m_propertyStackStack->setMaximumWidth(setWidth + 10);
00501 
00502     for (size_t i = 0; i < m_panes.size(); ++i) {
00503         if (!m_panes[i].propertyStack) continue;
00504         m_panes[i].propertyStack->setMinimumWidth(setWidth);
00505     }
00506 
00507     emit propertyStacksResized(setWidth);
00508     emit propertyStacksResized();
00509 }
00510     
00511 void
00512 PaneStack::paneDropAccepted(QStringList uriList)
00513 {
00514     Pane *pane = dynamic_cast<Pane *>(sender());
00515     emit dropAccepted(pane, uriList);
00516 }
00517     
00518 void
00519 PaneStack::paneDropAccepted(QString text)
00520 {
00521     Pane *pane = dynamic_cast<Pane *>(sender());
00522     emit dropAccepted(pane, text);
00523 }
00524 
00525 void
00526 PaneStack::paneDeleteButtonClicked()
00527 {
00528     QObject *s = sender();
00529     QWidget *w = dynamic_cast<QWidget *>(s);
00530     if (w) {
00531         if (m_xButtonMap.find(w) != m_xButtonMap.end()) {
00532             Pane *p = m_xButtonMap[w];
00533             emit paneDeleteButtonClicked(p);
00534         }
00535     }
00536 }
00537 
00538 void
00539 PaneStack::sizePanesEqually()
00540 {
00541     QList<int> sizes = m_splitter->sizes();
00542     if (sizes.empty()) return;
00543 
00544     int count = sizes.size();
00545 
00546     int total = 0;
00547     for (int i = 0; i < count; ++i) {
00548         total += sizes[i];
00549     }
00550 
00551     if (total == 0) return;
00552 
00553     sizes.clear();
00554 
00555     int each = total / count;
00556     int remaining = total;
00557 
00558     for (int i = 0; i < count; ++i) {
00559         if (i == count - 1) {
00560             sizes.push_back(remaining);
00561         } else {
00562             sizes.push_back(each);
00563             remaining -= each;
00564         }
00565     }
00566 
00567 /*
00568     std::cerr << "sizes: ";
00569     for (int i = 0; i < sizes.size(); ++i) {
00570         std::cerr << sizes[i] << " ";
00571     }
00572     std::cerr << std::endl;
00573 */
00574 
00575     m_splitter->setSizes(sizes);
00576 }
00577 
00578 

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1