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@0: #include <QIcon>
Chris@0: #include <QTabWidget>
Chris@0: 
Chris@0: #include <iostream>
Chris@0: 
Chris@835: #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: #if (QT_VERSION >= 0x0402)
Chris@242:     setElideMode(Qt::ElideNone); 
Chris@241:     tabBar()->setUsesScrollButtons(true); 
Chris@241:     tabBar()->setIconSize(QSize(16, 16));
Chris@242: #endif
Chris@239:     
Chris@0:     repopulate();
Chris@0: 
Chris@0:     connect(this, SIGNAL(currentChanged(int)),
Chris@0: 	    this, SLOT(selectedContainerChanged(int)));
Chris@0: 
Chris@0:     connect(m_client, SIGNAL(propertyContainerAdded(PropertyContainer *)),
Chris@0: 	    this, SLOT(propertyContainerAdded(PropertyContainer *)));
Chris@0: 
Chris@0:     connect(m_client, SIGNAL(propertyContainerRemoved(PropertyContainer *)),
Chris@0: 	    this, SLOT(propertyContainerRemoved(PropertyContainer *)));
Chris@0: 
Chris@0:     connect(m_client, SIGNAL(propertyContainerPropertyChanged(PropertyContainer *)),
Chris@0: 	    this, SLOT(propertyContainerPropertyChanged(PropertyContainer *)));
Chris@0: 
Chris@197:     connect(m_client, SIGNAL(propertyContainerPropertyRangeChanged(PropertyContainer *)),
Chris@197: 	    this, SLOT(propertyContainerPropertyRangeChanged(PropertyContainer *)));
Chris@197: 
Chris@0:     connect(m_client, SIGNAL(propertyContainerNameChanged(PropertyContainer *)),
Chris@0: 	    this, SLOT(propertyContainerNameChanged(PropertyContainer *)));
Chris@0: 
Chris@52:     connect(this, SIGNAL(propertyContainerSelected(View *, PropertyContainer *)),
Chris@52: 	    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@835:     cerr << "PropertyStack[" << this << "]::repopulate" << endl;
Chris@0: #endif
Chris@0:     
Chris@0:     while (count() > 0) {
Chris@0: 	removeTab(0);
Chris@0:     }
Chris@0:     for (size_t i = 0; i < m_boxes.size(); ++i) {
Chris@0: 	delete m_boxes[i];
Chris@0:     }
Chris@0:     m_boxes.clear();
Chris@0:     
Chris@807:     for (int i = 0; i < m_client->getPropertyContainerCount(); ++i) {
Chris@0: 
Chris@0: 	PropertyContainer *container = m_client->getPropertyContainer(i);
Chris@0: 	QString name = container->getPropertyContainerName();
Chris@0: 	
Chris@835: #ifdef DEBUG_PROPERTY_STACK
Chris@835:         cerr << "PropertyStack[" << this << "]::repopulate: client " << m_client
Chris@835:              << " returns container " << container << " (name " << name
Chris@835:              << ") at position " << i << endl;
Chris@835: #endif
Chris@835: 
Chris@0: 	PropertyBox *box = new PropertyBox(container);
Chris@0: 
Chris@47: 	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<Layer *>(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@242: 	QString iconName = container->getPropertyContainerIconName();
Chris@242: 
Chris@289:         QIcon icon(IconLoader().load(iconName));
Chris@0: 	if (icon.isNull()) {
Chris@242: 	    addTab(box, shortName);
Chris@552:             if (nameDiffers) {
Chris@552:                 setTabToolTip(i, name);
Chris@552:             }
Chris@0: 	} else {
Chris@0: 	    addTab(box, icon, QString("&%1").arg(i + 1));
Chris@242: 	    setTabToolTip(i, name);
Chris@0: 	}
Chris@0: 
Chris@0: 	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@0: 	PropertyContainer *container = m_client->getPropertyContainer(i);
Chris@0: 	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@723: 	PropertyContainer *container = m_boxes[i]->getContainer();
Chris@723: 	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@0: PropertyStack::propertyContainerAdded(PropertyContainer *)
Chris@0: {
Chris@0:     if (sender() != m_client) return;
Chris@0:     repopulate();
Chris@0: }
Chris@0: 
Chris@0: void
Chris@0: PropertyStack::propertyContainerRemoved(PropertyContainer *)
Chris@0: {
Chris@0:     if (sender() != m_client) return;
Chris@0:     repopulate();
Chris@0: }
Chris@0: 
Chris@0: void
Chris@0: PropertyStack::propertyContainerPropertyChanged(PropertyContainer *pc)
Chris@0: {
Chris@298:     Layer *layer = dynamic_cast<Layer *>(pc);
Chris@0:     for (unsigned int i = 0; i < m_boxes.size(); ++i) {
Chris@0: 	if (pc == m_boxes[i]->getContainer()) {
Chris@0: 	    m_boxes[i]->propertyContainerPropertyChanged(pc);
Chris@298:             if (layer) {
Chris@298:                 m_boxes[i]->layerVisibilityChanged
Chris@298:                     (!layer->isLayerDormant(m_client));
Chris@298:             }
Chris@0: 	}
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@197: 	if (pc == m_boxes[i]->getContainer()) {
Chris@197: 	    m_boxes[i]->propertyContainerPropertyRangeChanged(pc);
Chris@197: 	}
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@47: 	if (obj == m_boxes[i]) {
Chris@47: 	    Layer *layer = dynamic_cast<Layer *>(m_boxes[i]->getContainer());
Chris@47: 	    if (layer) {
Chris@377:                 CommandHistory::getInstance()->addCommand
Chris@397:                     (new ShowLayerCommand(m_client, layer, show,
Chris@397:                                           tr("Change Layer Visibility")));
Chris@47: 		return;
Chris@47: 	    }
Chris@47: 	}
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: