changeset 33:544ab25d2372

* Add support for plugin classification using category files. Add separate menus listing plugins by category, maker, and plugin name.
author Chris Cannam
date Thu, 21 Sep 2006 16:43:50 +0000
parents e3b32dc5180b
children 8ad306d8a568
files main/MainWindow.cpp transform/FeatureExtractionPluginTransform.cpp transform/TransformFactory.cpp transform/TransformFactory.h
diffstat 4 files changed, 217 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/main/MainWindow.cpp	Thu Sep 21 11:17:19 2006 +0000
+++ b/main/MainWindow.cpp	Thu Sep 21 16:43:50 2006 +0000
@@ -87,6 +87,10 @@
 using std::cerr;
 using std::endl;
 
+using std::vector;
+using std::map;
+using std::set;
+
 
 MainWindow::MainWindow() :
     m_document(0),
@@ -571,14 +575,80 @@
     TransformFactory::TransformList transforms =
 	TransformFactory::getInstance()->getAllTransforms();
 
-    std::vector<QString> types =
+    vector<QString> types =
         TransformFactory::getInstance()->getAllTransformTypes();
 
-    std::map<QString, QMenu *> transformMenus;
-
-    for (std::vector<QString>::iterator i = types.begin(); i != types.end(); ++i) {
-        transformMenus[*i] = m_layerMenu->addMenu(*i);
-        m_rightButtonLayerMenu->addMenu(transformMenus[*i]);
+    map<QString, map<QString, QMenu *> > categoryMenus;
+    map<QString, map<QString, QMenu *> > makerMenus;
+
+    map<QString, QMenu *> byPluginNameMenus;
+    map<QString, map<QString, QMenu *> > pluginNameMenus;
+
+    for (vector<QString>::iterator i = types.begin(); i != types.end(); ++i) {
+
+        if (i != types.begin()) {
+            m_layerMenu->addSeparator();
+            m_rightButtonLayerMenu->addSeparator();
+        }
+
+        QString byCategoryLabel = tr("%1 by Category").arg(*i);
+        QMenu *byCategoryMenu = m_layerMenu->addMenu(byCategoryLabel);
+        m_rightButtonLayerMenu->addMenu(byCategoryMenu);
+
+        vector<QString> categories = 
+            TransformFactory::getInstance()->getTransformCategories(*i);
+
+        for (vector<QString>::iterator j = categories.begin();
+             j != categories.end(); ++j) {
+
+            QString category = *j;
+            if (category == "") category = tr("Unclassified");
+
+            if (categories.size() < 2) {
+                categoryMenus[*i][category] = byCategoryMenu;
+                continue;
+            }
+
+            QStringList components = category.split(" > ");
+            QString key;
+
+            for (QStringList::iterator k = components.begin();
+                 k != components.end(); ++k) {
+
+                QString parentKey = key;
+                if (key != "") key += " > ";
+                key += *k;
+
+                if (categoryMenus[*i].find(key) == categoryMenus[*i].end()) {
+                    if (parentKey == "") {
+                        categoryMenus[*i][key] = byCategoryMenu->addMenu(*k);
+                    } else {
+                        categoryMenus[*i][key] =
+                            categoryMenus[*i][parentKey]->addMenu(*k);
+                    }
+                }
+            }
+        }
+
+        QString byMakerLabel = tr("%1 by Maker").arg(*i);
+        QMenu *byMakerMenu = m_layerMenu->addMenu(byMakerLabel);
+        m_rightButtonLayerMenu->addMenu(byMakerMenu);
+
+        vector<QString> makers = 
+            TransformFactory::getInstance()->getTransformMakers(*i);
+        
+        for (vector<QString>::iterator j = makers.begin();
+             j != makers.end(); ++j) {
+
+            QString maker = *j;
+            if (maker == "") maker = tr("Unknown");
+            
+            makerMenus[*i][maker] = byMakerMenu->addMenu(maker);
+        }
+
+        QString byPluginNameLabel = tr("%1 by Plugin Name").arg(*i);
+        byPluginNameMenus[*i] = m_layerMenu->addMenu(byPluginNameLabel);
+        m_rightButtonLayerMenu->addMenu(byPluginNameMenus[*i]);
     }
 
     for (unsigned int i = 0; i < transforms.size(); ++i) {
@@ -586,16 +656,63 @@
 	QString description = transforms[i].description;
 	if (description == "") description = transforms[i].name;
 
-	QString actionText = description;
-        if (transforms[i].configurable) {
-            actionText = QString("%1...").arg(actionText);
-        }
-
-	action = new QAction(actionText, this);
+        QString type = transforms[i].type;
+
+        QString category = transforms[i].category;
+        if (category == "") category = tr("Unclassified");
+
+        QString maker = transforms[i].maker;
+        if (maker == "") maker = tr("Unknown");
+
+        QString pluginName = description.section(": ", 0, 0);
+        QString output = description.section(": ", 1);
+
+	action = new QAction(tr("%1...").arg(description), this);
 	connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
 	m_layerTransformActions[action] = transforms[i].name;
 	connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
-	transformMenus[transforms[i].type]->addAction(action);
+
+        if (categoryMenus[type].find(category) == categoryMenus[type].end()) {
+            std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
+                      << "No category menu for transform \""
+                      << description.toStdString() << "\" (category = \""
+                      << category.toStdString() << "\")" << std::endl;
+        } else {
+            categoryMenus[type][category]->addAction(action);
+        }
+
+        if (makerMenus[type].find(maker) == makerMenus[type].end()) {
+            std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
+                      << "No maker menu for transform \""
+                      << description.toStdString() << "\" (maker = \""
+                      << maker.toStdString() << "\")" << std::endl;
+        } else {
+            makerMenus[type][maker]->addAction(action);
+        }
+
+        action = new QAction(tr("%1...").arg(output == "" ? pluginName : output), this);
+        connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
+        m_layerTransformActions[action] = transforms[i].name;
+        connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
+
+        if (pluginNameMenus[type].find(pluginName) ==
+            pluginNameMenus[type].end()) {
+
+            if (output == "") {
+                byPluginNameMenus[type]->addAction(action);
+            } else {
+                pluginNameMenus[type][pluginName] =
+                    byPluginNameMenus[type]->addMenu(pluginName);
+                connect(this, SIGNAL(canAddLayer(bool)),
+                        pluginNameMenus[type][pluginName],
+                        SLOT(setEnabled(bool)));
+            }
+        }
+
+        if (pluginNameMenus[type].find(pluginName) !=
+            pluginNameMenus[type].end()) {
+            pluginNameMenus[type][pluginName]->addAction(action);
+        }
     }
 
     m_rightButtonLayerMenu->addSeparator();
@@ -871,7 +988,7 @@
 MainWindow::setupRecentFilesMenu()
 {
     m_recentFilesMenu->clear();
-    std::vector<QString> files = RecentFiles::getInstance()->getRecentFiles();
+    vector<QString> files = RecentFiles::getInstance()->getRecentFiles();
     for (size_t i = 0; i < files.size(); ++i) {
 	QAction *action = new QAction(files[i], this);
 	connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
@@ -889,8 +1006,8 @@
     m_existingLayersMenu->clear();
     m_existingLayerActions.clear();
 
-    std::vector<Layer *> orderedLayers;
-    std::set<Layer *> observedLayers;
+    vector<Layer *> orderedLayers;
+    set<Layer *> observedLayers;
 
     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
 
@@ -914,7 +1031,7 @@
 	}
     }
 
-    std::map<QString, int> observedNames;
+    map<QString, int> observedNames;
 
     for (int i = 0; i < orderedLayers.size(); ++i) {
 	
@@ -2788,32 +2905,16 @@
 	}
     }
 
-    bool needConfiguration = false;
-
-    //!!! actually we should probably always ask for configuration
-    //because we need the execution context
-
-    if (factory->isTransformConfigurable(transform)) {
-        needConfiguration = true;
-    } else {
-        int minChannels, maxChannels;
-        int myChannels = m_document->getMainModel()->getChannelCount();
-        if (factory->getTransformChannelRange(transform,
-                                              minChannels,
-                                              maxChannels)) {
-//            std::cerr << "myChannels: " << myChannels << ", minChannels: " << minChannels << ", maxChannels: " << maxChannels << std::endl;
-            needConfiguration = (myChannels > maxChannels && maxChannels == 1);
-        }
-    }
+    // We always ask for configuration, even if the plugin isn't
+    // supposed to be configurable, because we need to let the user
+    // change the execution context (block size etc).
 
     PluginTransform::ExecutionContext context(channel);
 
-    if (needConfiguration) {
-        bool ok =
-            factory->getConfigurationForTransform
-            (transform, m_document->getMainModel(), context, configurationXml);
-        if (!ok) return;
-    }
+    bool ok =
+        factory->getConfigurationForTransform
+        (transform, m_document->getMainModel(), context, configurationXml);
+    if (!ok) return;
 
     Layer *newLayer = m_document->createDerivedLayer(transform,
                                                      m_document->getMainModel(),
--- a/transform/FeatureExtractionPluginTransform.cpp	Thu Sep 21 11:17:19 2006 +0000
+++ b/transform/FeatureExtractionPluginTransform.cpp	Thu Sep 21 16:43:50 2006 +0000
@@ -269,8 +269,8 @@
             if (blockFrame >= endFrame) break;
         }
 
-	std::cerr << "FeatureExtractionPluginTransform::run: blockFrame "
-		  << blockFrame << std::endl;
+//	std::cerr << "FeatureExtractionPluginTransform::run: blockFrame "
+//		  << blockFrame << std::endl;
 
 	long completion =
 	    (((blockFrame - startFrame) / m_context.stepSize) * 99) /
@@ -463,16 +463,21 @@
 	binCount = m_descriptor->binCount;
     }
 
+    std::cerr << "FeatureExtractionPluginTransform::setCompletion("
+              << completion << ")" << std::endl;
+
     if (binCount == 0) {
 
 	SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
 	if (!model) return;
+        std::cerr << "setting on SparseOneDimensionalModel" << std::endl;
 	model->setCompletion(completion);
 
     } else if (binCount == 1) {
 
 	SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
 	if (!model) return;
+        std::cerr << "setting on SparseTimeValueModel" << std::endl;
 	model->setCompletion(completion);
 
     } else if (m_descriptor->sampleType ==
@@ -480,6 +485,7 @@
 
 	NoteModel *model = getOutput<NoteModel>();
 	if (!model) return;
+        std::cerr << "setting on NoteModel" << std::endl;
 	model->setCompletion(completion);
 
     } else {
@@ -487,6 +493,7 @@
 	EditableDenseThreeDimensionalModel *model =
             getOutput<EditableDenseThreeDimensionalModel>();
 	if (!model) return;
+        std::cerr << "setting on EditableDenseThreeDimensionalModel" << std::endl;
 	model->setCompletion(completion);
     }
 }
--- a/transform/TransformFactory.cpp	Thu Sep 21 11:17:19 2006 +0000
+++ b/transform/TransformFactory.cpp	Thu Sep 21 16:43:50 2006 +0000
@@ -79,6 +79,60 @@
     return rv;
 }
 
+std::vector<QString>
+TransformFactory::getTransformCategories(QString transformType)
+{
+    if (m_transforms.empty()) populateTransforms();
+
+    std::set<QString> categories;
+    for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
+         i != m_transforms.end(); ++i) {
+        if (i->second.type == transformType) {
+            categories.insert(i->second.category);
+        }
+    }
+
+    bool haveEmpty = false;
+    
+    std::vector<QString> rv;
+    for (std::set<QString>::iterator i = categories.begin(); 
+         i != categories.end(); ++i) {
+        if (*i != "") rv.push_back(*i);
+        else haveEmpty = true;
+    }
+
+    if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
+
+    return rv;
+}
+
+std::vector<QString>
+TransformFactory::getTransformMakers(QString transformType)
+{
+    if (m_transforms.empty()) populateTransforms();
+
+    std::set<QString> makers;
+    for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
+         i != m_transforms.end(); ++i) {
+        if (i->second.type == transformType) {
+            makers.insert(i->second.maker);
+        }
+    }
+
+    bool haveEmpty = false;
+    
+    std::vector<QString> rv;
+    for (std::set<QString>::iterator i = makers.begin(); 
+         i != makers.end(); ++i) {
+        if (*i != "") rv.push_back(*i);
+        else haveEmpty = true;
+    }
+
+    if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
+
+    return rv;
+}
+
 void
 TransformFactory::populateTransforms()
 {
@@ -151,6 +205,8 @@
 	}
 		
 	QString pluginDescription = plugin->getDescription().c_str();
+        QString category = factory->getPluginCategory(pluginId);
+
 	Vamp::Plugin::OutputList outputs =
 	    plugin->getOutputDescriptors();
 
@@ -178,6 +234,7 @@
 
 	    transforms[transformName] = 
                 TransformDesc(tr("Analysis Plugins"),
+                              category,
                               transformName,
                               userDescription,
                               friendlyName,
@@ -222,6 +279,7 @@
 //        std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
 	
 	QString pluginDescription = descriptor->name.c_str();
+        QString category = factory->getPluginCategory(pluginId);
 
 	for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
 
@@ -258,6 +316,7 @@
 
 	    transforms[transformName] = 
                 TransformDesc(tr("Other Plugins"),
+                              category,
                               transformName,
                               userDescription,
                               userDescription,
--- a/transform/TransformFactory.h	Thu Sep 21 11:17:19 2006 +0000
+++ b/transform/TransformFactory.h	Thu Sep 21 16:43:50 2006 +0000
@@ -42,13 +42,16 @@
 
     struct TransformDesc {
         TransformDesc() { }
-	TransformDesc(QString _type, TransformName _name, QString _description,
+	TransformDesc(QString _type, QString _category,
+                      TransformName _name, QString _description,
                       QString _friendlyName, QString _maker,
                       QString _units, bool _configurable) :
-	    type(_type), name(_name), description(_description),
+	    type(_type), category(_category),
+            name(_name), description(_description),
             friendlyName(_friendlyName),
             maker(_maker), units(_units), configurable(_configurable) { }
         QString type;
+        QString category;
 	TransformName name;
 	QString description;
         QString friendlyName;
@@ -62,6 +65,9 @@
 
     std::vector<QString> getAllTransformTypes();
 
+    std::vector<QString> getTransformCategories(QString transformType);
+    std::vector<QString> getTransformMakers(QString transformType);
+
     /**
      * Get a configuration XML string for the given transform (by
      * asking the user, most likely).  Returns true if the transform