+void
+PluginManager::load_tags ()
+{
+ vector<std::string> tmp;
+ find_files_matching_pattern (tmp, plugin_metadata_search_path (), "plugin_tags");
+
+ for (vector<std::string>::const_reverse_iterator p = tmp.rbegin ();
+ p != (vector<std::string>::const_reverse_iterator)tmp.rend(); ++p) {
+ std::string path = *p;
+ info << string_compose (_("Loading plugin meta data file %1"), path) << endmsg;
+ if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
+ return;
+ }
+
+ XMLTree tree;
+ if (!tree.read (path)) {
+ error << string_compose (_("Cannot parse plugin tag info from %1"), path) << endmsg;
+ return;
+ }
+
+ for (XMLNodeConstIterator i = tree.root()->children().begin(); i != tree.root()->children().end(); ++i) {
+ PluginType type;
+ string id;
+ string tags;
+ string name;
+ bool user_set;
+ if (!(*i)->get_property (X_("type"), type) ||
+ !(*i)->get_property (X_("id"), id) ||
+ !(*i)->get_property (X_("tags"), tags) ||
+ !(*i)->get_property (X_("name"), name)) {
+ }
+ if (!(*i)->get_property (X_("user-set"), user_set)) {
+ user_set = false;
+ }
+ strip_whitespace_edges (tags);
+ set_tags (type, id, tags, name, user_set ? FromUserFile : FromFactoryFile );
+ }
+ }
+}
+
+void
+PluginManager::set_tags (PluginType t, string id, string tag, std::string name, TagType ttype )
+{
+ string sanitized = sanitize_tag (tag);
+
+ PluginTag ps (to_generic_vst (t), id, sanitized, name, ttype );
+ PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
+ if (i == ptags.end()) {
+ ptags.insert (ps);
+ } else if ( (uint32_t) ttype >= (uint32_t) (*i).tagtype ) { // only overwrite if we are more important than the existing. Gui > UserFile > FactoryFile > Plugin
+ ptags.erase (ps);
+ ptags.insert (ps);
+ }
+ if ( ttype == FromGui ) {
+ PluginTagChanged (t, id, sanitized); /* EMIT SIGNAL */
+ }
+}
+
+void
+PluginManager::reset_tags (PluginInfoPtr const& pi)
+{
+ PluginTag ps (pi->type, pi->unique_id, pi->category, pi->name, FromPlug);
+
+ PluginTagList::const_iterator i = find (ptags.begin(), ptags.end(), ps);
+ if (i != ptags.end()) {
+ ptags.erase (ps);
+ ptags.insert (ps);
+ }
+}
+
+std::string
+PluginManager::sanitize_tag (const std::string to_sanitize) const
+{
+ if (to_sanitize.empty ()) {
+ return "";
+ }
+ string sanitized = to_sanitize;
+ vector<string> tags;
+ if (!PBD::tokenize (sanitized, string(" ,\n"), std::back_inserter (tags), true)) {
+#ifndef NDEBUG
+ cerr << _("PluginManager::sanitize_tag could not tokenize string: ") << sanitized << endmsg;
+#endif
+ return "";
+ }
+
+ /* convert tokens to lower-case, space-separated list */
+ sanitized = "";
+ for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
+ if (t != tags.begin ()) {
+ sanitized.append(" ");
+ }
+ sanitized.append (downcase (*t));
+ }
+
+ return sanitized;
+}
+
+std::vector<std::string>
+PluginManager::get_all_tags (TagFilter tag_filter) const
+{
+ std::vector<std::string> ret;
+
+ PluginTagList::const_iterator pt;
+ for (pt = ptags.begin(); pt != ptags.end(); ++pt) {
+ if ((*pt).tags.empty ()) {
+ continue;
+ }
+
+ /* if favorites_only then we need to check the info ptr and maybe skip */
+ if (tag_filter == OnlyFavorites) {
+ PluginStatus stat ((*pt).type, (*pt).unique_id);
+ PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
+ if ((i != statuses.end()) && (i->status == Favorite)) {
+ /* it's a favorite! */
+ } else {
+ continue;
+ }
+ }
+ if (tag_filter == NoHidden) {
+ PluginStatus stat ((*pt).type, (*pt).unique_id);
+ PluginStatusList::const_iterator i = find (statuses.begin(), statuses.end(), stat);
+ if ((i != statuses.end()) && (i->status == Hidden)) {
+ continue;
+ }
+ }
+
+ /* parse each plugin's tag string into separate tags */
+ vector<string> tags;
+ if (!PBD::tokenize ((*pt).tags, string(" "), std::back_inserter (tags), true)) {
+#ifndef NDEBUG
+ cerr << _("PluginManager: Could not tokenize string: ") << (*pt).tags << endmsg;
+#endif
+ continue;
+ }
+
+ /* maybe add the tags we've found */
+ for (vector<string>::iterator t = tags.begin(); t != tags.end(); ++t) {
+ /* if this tag isn't already in the list, add it */
+ vector<string>::iterator i = find (ret.begin(), ret.end(), *t);
+ if (i == ret.end()) {
+ ret.push_back (*t);
+ }
+ }
+ }
+
+ /* sort in alphabetical order */
+ SortByTag sorter;
+ sort (ret.begin(), ret.end(), sorter);
+
+ return ret;
+}
+
+
+const ARDOUR::PluginInfoList&