Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@59: Sonic Visualiser Chris@59: An audio file viewer and annotation editor. Chris@59: Centre for Digital Music, Queen Mary, University of London. Chris@59: This file copyright 2006 Chris Cannam. Chris@0: Chris@59: This program is free software; you can redistribute it and/or Chris@59: modify it under the terms of the GNU General Public License as Chris@59: published by the Free Software Foundation; either version 2 of the Chris@59: License, or (at your option) any later version. See the file Chris@59: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "PropertyStack.h" Chris@0: #include "PropertyBox.h" Chris@0: #include "base/PropertyContainer.h" Chris@128: #include "view/View.h" Chris@128: #include "layer/Layer.h" Chris@242: #include "layer/LayerFactory.h" Chris@190: #include "widgets/NotifyingTabBar.h" Chris@289: #include "widgets/IconLoader.h" Chris@377: #include "base/Command.h" Chris@377: #include "widgets/CommandHistory.h" Chris@732: #include "layer/ShowLayerCommand.h" Chris@0: Chris@1174: #include "WidgetScale.h" Chris@1174: Chris@0: #include Chris@0: #include Chris@0: Chris@0: #include Chris@0: Chris@939: //#define DEBUG_PROPERTY_STACK 1 Chris@0: Chris@0: PropertyStack::PropertyStack(QWidget *parent, View *client) : Chris@0: QTabWidget(parent), Chris@0: m_client(client) Chris@0: { Chris@190: NotifyingTabBar *bar = new NotifyingTabBar(); Chris@190: bar->setDrawBase(false); Chris@190: Chris@190: connect(bar, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredTabBar())); Chris@190: connect(bar, SIGNAL(mouseLeft()), this, SLOT(mouseLeftTabBar())); Chris@190: connect(bar, SIGNAL(activeTabClicked()), this, SLOT(activeTabClicked())); Chris@190: Chris@190: setTabBar(bar); Chris@190: Chris@242: setElideMode(Qt::ElideNone); Chris@241: tabBar()->setUsesScrollButtons(true); Chris@1174: tabBar()->setIconSize(WidgetScale::scaleQSize(QSize(16, 16))); Chris@980: Chris@0: repopulate(); Chris@0: Chris@0: connect(this, SIGNAL(currentChanged(int)), Chris@1266: this, SLOT(selectedContainerChanged(int))); Chris@0: Chris@0: connect(m_client, SIGNAL(propertyContainerAdded(PropertyContainer *)), Chris@1266: this, SLOT(propertyContainerAdded(PropertyContainer *))); Chris@0: Chris@0: connect(m_client, SIGNAL(propertyContainerRemoved(PropertyContainer *)), Chris@1266: this, SLOT(propertyContainerRemoved(PropertyContainer *))); Chris@0: Chris@0: connect(m_client, SIGNAL(propertyContainerPropertyChanged(PropertyContainer *)), Chris@1266: this, SLOT(propertyContainerPropertyChanged(PropertyContainer *))); Chris@0: Chris@197: connect(m_client, SIGNAL(propertyContainerPropertyRangeChanged(PropertyContainer *)), Chris@1266: this, SLOT(propertyContainerPropertyRangeChanged(PropertyContainer *))); Chris@197: Chris@0: connect(m_client, SIGNAL(propertyContainerNameChanged(PropertyContainer *)), Chris@1266: this, SLOT(propertyContainerNameChanged(PropertyContainer *))); Chris@0: Chris@52: connect(this, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)), Chris@1266: m_client, SLOT(propertyContainerSelected(View *, PropertyContainer *))); Chris@0: } Chris@0: Chris@729: PropertyStack::~PropertyStack() Chris@729: { Chris@729: } Chris@729: Chris@0: void Chris@0: PropertyStack::repopulate() Chris@0: { Chris@0: blockSignals(true); Chris@0: Chris@0: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack[" << this << "]::repopulate" << endl; Chris@0: #endif Chris@0: Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack[" << this << "]::repopulate: removing tabs" << endl; Chris@1525: #endif Chris@0: while (count() > 0) { Chris@1266: removeTab(0); Chris@0: } Chris@1525: Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack[" << this << "]::repopulate: deleting boxes" << endl; Chris@1525: #endif Chris@0: for (size_t i = 0; i < m_boxes.size(); ++i) { Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "(" << i << " of " << m_boxes.size() << ": " << m_boxes[i]->getContainer()->getPropertyContainerName() << ")" << endl; Chris@1525: #endif Chris@1266: delete m_boxes[i]; Chris@0: } Chris@1525: Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack[" << this << "]::repopulate: done, clearing m_boxes" << endl; Chris@1525: #endif Chris@0: m_boxes.clear(); Chris@0: Chris@807: for (int i = 0; i < m_client->getPropertyContainerCount(); ++i) { Chris@0: Chris@1266: PropertyContainer *container = m_client->getPropertyContainer(i); Chris@1266: QString name = container->getPropertyContainerName(); Chris@1266: Chris@835: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack[" << this << "]::repopulate: client " << m_client Chris@1525: << " returns container " << container << " (name " << name Chris@1525: << ") at position " << i << endl; Chris@835: #endif Chris@835: Chris@1266: PropertyBox *box = new PropertyBox(container); Chris@0: Chris@1266: connect(box, SIGNAL(showLayer(bool)), this, SLOT(showLayer(bool))); Chris@189: connect(box, SIGNAL(contextHelpChanged(const QString &)), Chris@189: this, SIGNAL(contextHelpChanged(const QString &))); Chris@47: Chris@185: Layer *layer = dynamic_cast(container); Chris@185: if (layer) { Chris@185: box->layerVisibilityChanged(!layer->isLayerDormant(m_client)); Chris@185: } Chris@185: Chris@242: QString shortName = name; Chris@242: Chris@242: if (layer) { Chris@242: shortName = LayerFactory::getInstance()->getLayerPresentationName Chris@242: (LayerFactory::getInstance()->getLayerType(layer)); Chris@552: if (layer->getLayerPresentationName() != "") { Chris@552: name = layer->getLayerPresentationName(); Chris@552: } Chris@242: } Chris@242: Chris@552: bool nameDiffers = (name != shortName); Chris@242: shortName = QString("&%1 %2").arg(i + 1).arg(shortName); Chris@242: Chris@1266: QString iconName = container->getPropertyContainerIconName(); Chris@242: Chris@289: QIcon icon(IconLoader().load(iconName)); Chris@1266: if (icon.isNull()) { Chris@1266: addTab(box, shortName); Chris@552: if (nameDiffers) { Chris@552: setTabToolTip(i, name); Chris@552: } Chris@1266: } else { Chris@1266: addTab(box, icon, QString("&%1").arg(i + 1)); Chris@1266: setTabToolTip(i, name); Chris@1266: } Chris@0: Chris@1266: m_boxes.push_back(box); Chris@0: } Chris@0: Chris@0: blockSignals(false); Chris@0: } Chris@0: Chris@0: bool Chris@0: PropertyStack::containsContainer(PropertyContainer *pc) const Chris@0: { Chris@807: for (int i = 0; i < m_client->getPropertyContainerCount(); ++i) { Chris@1266: PropertyContainer *container = m_client->getPropertyContainer(i); Chris@1266: if (pc == container) return true; Chris@0: } Chris@0: Chris@0: return false; Chris@0: } Chris@0: Chris@19: int Chris@19: PropertyStack::getContainerIndex(PropertyContainer *pc) const Chris@19: { Chris@723: // This is used to obtain an index to be passed to setCurrentIndex Chris@723: // -- which is the index of the property container's box in our Chris@723: // stack of boxes. That is not the same thing as the index of the Chris@723: // container (i.e. the layer) in the view: the view reorders its Chris@723: // containers whenever one is raised to the top, while our boxes Chris@723: // remain in the same order. So we must find this container in the Chris@723: // box list, not in the view. Chris@723: Chris@908: for (int i = 0; in_range_for(m_boxes, i); ++i) { Chris@1266: PropertyContainer *container = m_boxes[i]->getContainer(); Chris@1266: if (pc == container) { Chris@723: return i; Chris@723: } Chris@19: } Chris@19: Chris@19: return false; Chris@19: } Chris@19: Chris@0: void Chris@1525: PropertyStack::propertyContainerAdded(PropertyContainer * Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: c Chris@1525: #endif Chris@1525: ) Chris@0: { Chris@0: if (sender() != m_client) return; Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack::propertyContainerAdded(" << (c ? c->getPropertyContainerName() : "(none)") << ")" << endl; Chris@1525: #endif Chris@0: repopulate(); Chris@0: } Chris@0: Chris@0: void Chris@1525: PropertyStack::propertyContainerRemoved(PropertyContainer * Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: c Chris@1525: #endif Chris@1525: ) Chris@0: { Chris@0: if (sender() != m_client) return; Chris@1525: #ifdef DEBUG_PROPERTY_STACK Chris@1525: SVDEBUG << "PropertyStack::propertyContainerAdded(" << (c ? c->getPropertyContainerName() : "(none)") << ")" << endl; Chris@1525: #endif Chris@0: repopulate(); Chris@0: } Chris@0: Chris@0: void Chris@0: PropertyStack::propertyContainerPropertyChanged(PropertyContainer *pc) Chris@0: { Chris@298: Layer *layer = dynamic_cast(pc); Chris@0: for (unsigned int i = 0; i < m_boxes.size(); ++i) { Chris@1266: if (pc == m_boxes[i]->getContainer()) { Chris@1266: m_boxes[i]->propertyContainerPropertyChanged(pc); Chris@298: if (layer) { Chris@298: m_boxes[i]->layerVisibilityChanged Chris@298: (!layer->isLayerDormant(m_client)); Chris@298: } Chris@1266: } Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@197: PropertyStack::propertyContainerPropertyRangeChanged(PropertyContainer *pc) Chris@197: { Chris@197: for (unsigned int i = 0; i < m_boxes.size(); ++i) { Chris@1266: if (pc == m_boxes[i]->getContainer()) { Chris@1266: m_boxes[i]->propertyContainerPropertyRangeChanged(pc); Chris@1266: } Chris@197: } Chris@197: } Chris@197: Chris@197: void Chris@249: PropertyStack::propertyContainerNameChanged(PropertyContainer *) Chris@0: { Chris@0: if (sender() != m_client) return; Chris@0: repopulate(); Chris@0: } Chris@0: Chris@0: void Chris@47: PropertyStack::showLayer(bool show) Chris@47: { Chris@47: QObject *obj = sender(); Chris@47: Chris@47: for (unsigned int i = 0; i < m_boxes.size(); ++i) { Chris@1266: if (obj == m_boxes[i]) { Chris@1266: Layer *layer = dynamic_cast(m_boxes[i]->getContainer()); Chris@1266: if (layer) { Chris@377: CommandHistory::getInstance()->addCommand Chris@397: (new ShowLayerCommand(m_client, layer, show, Chris@397: tr("Change Layer Visibility"))); Chris@1266: return; Chris@1266: } Chris@1266: } Chris@47: } Chris@47: } Chris@47: Chris@47: void Chris@0: PropertyStack::selectedContainerChanged(int n) Chris@0: { Chris@0: if (n >= int(m_boxes.size())) return; Chris@52: emit propertyContainerSelected(m_client, m_boxes[n]->getContainer()); Chris@0: } Chris@0: Chris@190: void Chris@190: PropertyStack::mouseEnteredTabBar() Chris@190: { Chris@190: emit contextHelpChanged(tr("Click to change the current active layer")); Chris@190: } Chris@190: Chris@190: void Chris@190: PropertyStack::mouseLeftTabBar() Chris@190: { Chris@190: emit contextHelpChanged(""); Chris@190: } Chris@190: Chris@190: void Chris@190: PropertyStack::activeTabClicked() Chris@190: { Chris@190: emit viewSelected(m_client); Chris@190: } Chris@190: