svgui  1.9
TransformFinder.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2008 QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "TransformFinder.h"
17 
18 #include "base/XmlExportable.h"
19 #include "transform/TransformFactory.h"
20 #include "SelectableLabel.h"
21 
22 #include <QVBoxLayout>
23 #include <QGridLayout>
24 #include <QLineEdit>
25 #include <QLabel>
26 #include <QDialogButtonBox>
27 #include <QScrollArea>
28 #include <QApplication>
29 #include <QDesktopWidget>
30 #include <QTimer>
31 #include <QAction>
32 
34  QDialog(parent),
35  m_resultsFrame(0),
36  m_resultsLayout(0)
37 {
38  setWindowTitle(tr("Find a Transform"));
39 
40  QGridLayout *mainGrid = new QGridLayout;
41  mainGrid->setVerticalSpacing(0);
42  setLayout(mainGrid);
43 
44  mainGrid->addWidget(new QLabel(tr("Find:")), 0, 0);
45 
46  QLineEdit *searchField = new QLineEdit;
47  mainGrid->addWidget(searchField, 0, 1);
48  connect(searchField, SIGNAL(textChanged(const QString &)),
49  this, SLOT(searchTextChanged(const QString &)));
50 
51 // m_infoLabel = new QLabel(tr("Type in this box to search descriptions of available and known transforms"));
52  m_infoLabel = new QLabel;
53  mainGrid->addWidget(m_infoLabel, 1, 1);
54 
55  m_resultsScroll = new QScrollArea;
56  mainGrid->addWidget(m_resultsScroll, 2, 0, 1, 2);
57  mainGrid->setRowStretch(2, 10);
58 
59  QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
60  QDialogButtonBox::Cancel);
61  mainGrid->addWidget(bb, 3, 0, 1, 2);
62  connect(bb, SIGNAL(accepted()), this, SLOT(accept()));
63  connect(bb, SIGNAL(rejected()), this, SLOT(reject()));
64 
65  m_resultsFrame = new QWidget;
66  QPalette palette = m_resultsFrame->palette();
67  palette.setColor(QPalette::Window, palette.color(QPalette::Base));
68  m_resultsFrame->setPalette(palette);
69  m_resultsScroll->setPalette(palette);
70  m_resultsLayout = new QVBoxLayout;
71  m_resultsLayout->setSpacing(0);
72  m_resultsLayout->setContentsMargins(0, 0, 0, 0);
73  m_resultsFrame->setLayout(m_resultsLayout);
74  m_resultsScroll->setWidget(m_resultsFrame);
75  m_resultsFrame->show();
76 
77  m_noResultsLabel = new QLabel(tr("<br>&nbsp;&nbsp;No results found"));
79  m_noResultsLabel->hide();
80 
81  m_beforeSearchLabel = new QLabel;
83  m_beforeSearchLabel->hide();
84 
85  QAction *up = new QAction(tr("Up"), this);
86  up->setShortcut(tr("Up"));
87  connect(up, SIGNAL(triggered()), this, SLOT(up()));
88  addAction(up);
89 
90  QAction *down = new QAction(tr("Down"), this);
91  down->setShortcut(tr("Down"));
92  connect(down, SIGNAL(triggered()), this, SLOT(down()));
93  addAction(down);
94 
95  QDesktopWidget *desktop = QApplication::desktop();
96  QRect available = desktop->availableGeometry();
97 
98  int width = available.width() / 2;
99  int height = available.height() / 2;
100  if (height < 450) {
101  if (available.height() > 500) height = 450;
102  }
103  if (width < 600) {
104  if (available.width() > 650) width = 600;
105  }
106 
107  resize(width, height);
108  raise();
109 
111 
112  m_upToDateCount = 0;
113  m_timer = new QTimer(this);
114  connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
115  m_timer->start(30);
116 }
117 
119 {
120 }
121 
122 void
124 {
125  bool haveInstalled =
126  TransformFactory::getInstance()->haveInstalledTransforms();
127  bool haveUninstalled =
128  TransformFactory::getInstance()->haveUninstalledTransforms();
129 
130  m_beforeSearchLabel->setWordWrap(true);
131  m_beforeSearchLabel->setOpenExternalLinks(true);
132  m_beforeSearchLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
133  m_beforeSearchLabel->setMargin(12);
134  m_beforeSearchLabel->setFixedWidth(this->width() - 40);
135 
136  QString base =
137  tr("<p>Type some text into the search box to search the descriptions of:<ul><li>All currently installed <a href=\"http://www.vamp-plugins.org/\">Vamp</a> audio feature extraction plugins</li><li>All currently installed <a href=\"http://www.ladspa.org/\">LADSPA</a> audio effects plugins</li><li>Vamp plugins that are not currently installed but that have descriptions published via the semantic web</li></ul>");
138 
139  QString nopull =
140  tr("<b>Unable to retrieve published descriptions from network!</b>");
141 
142  QString noinst =
143  tr("<b>No plugins are currently installed!</b>");
144 
145  if (haveInstalled) {
146  if (haveUninstalled) {
147  m_beforeSearchLabel->setText(base);
148  } else {
149  m_beforeSearchLabel->setText
150  (base +
151  tr("<p>%1<br>Perhaps the network connection is down, services are responding too slowly, or a processing problem has occurred.<br>Only the descriptions of installed plugins will be searched.").arg(nopull));
152  }
153  } else {
154  if (haveUninstalled) {
155  m_beforeSearchLabel->setText
156  (base +
157  tr("<p>%1<br>Only the published descriptions of Vamp feature extraction plugins will be searched.").arg(noinst));
158  } else {
159  m_beforeSearchLabel->setText
160  (base +
161  tr("<p>%1<br>%2<br>Perhaps the network connection is down, or services are responding too slowly.<br>No search results will be available.").arg(noinst).arg(nopull));
162  }
163  }
164 
165  m_beforeSearchLabel->show();
166  m_resultsFrame->resize(m_resultsFrame->sizeHint());
167 }
168 
169 void
171 {
172 // cerr << "text is " << text << endl;
173  m_newSearchText = text;
174 }
175 
176 void
178 {
179  int maxResults = 60;
180 
181  if (m_newSearchText != "") {
182 
183  QString text = m_newSearchText;
184  m_newSearchText = "";
185 
186  QStringList keywords = text.split(' ', QString::SkipEmptyParts);
187  TransformFactory::SearchResults results =
188  TransformFactory::getInstance()->search(keywords);
189 
190 // cerr << results.size() << " result(s)..." << endl;
191 
192  std::set<TextMatcher::Match> sorted;
193  sorted.clear();
194  for (TransformFactory::SearchResults::const_iterator j = results.begin();
195  j != results.end(); ++j) {
196  sorted.insert(j->second);
197  }
198 
199  m_sortedResults.clear();
200  for (std::set<TextMatcher::Match>::const_iterator j = sorted.end();
201  j != sorted.begin(); ) {
202  --j;
203  m_sortedResults.push_back(*j);
204  if ((int)m_sortedResults.size() == maxResults) break;
205  }
206 
207  if (m_sortedResults.empty()) m_selectedTransform = "";
208  else m_selectedTransform = m_sortedResults.begin()->key;
209 
210  m_upToDateCount = 0;
211 
212  for (int j = (int)m_labels.size(); j > (int)m_sortedResults.size(); ) {
213  m_labels[--j]->hide();
214  }
215 
216  m_beforeSearchLabel->hide();
217 
218  if (m_sortedResults.empty()) {
219  m_noResultsLabel->show();
220  m_resultsFrame->resize(m_resultsFrame->sizeHint());
221  } else {
222  m_noResultsLabel->hide();
223  }
224 
225  if (m_sortedResults.size() < sorted.size()) {
226  m_infoLabel->setText
227  (tr("Found %n description(s) containing <b>%1</b>, showing the first %2 only",
228  0, sorted.size()).arg(text).arg(m_sortedResults.size()));
229  } else {
230  m_infoLabel->setText
231  (tr("Found %n description(s) containing <b>%1</b>",
232  0, sorted.size()).arg(text));
233  }
234 
235  return;
236  }
237 
238  if (m_upToDateCount >= (int)m_sortedResults.size()) return;
239 
240  while (m_upToDateCount < (int)m_sortedResults.size()) {
241 
242  int i = m_upToDateCount;
243 
244 // cerr << "sorted size = " << m_sortedResults.size() << endl;
245 
246  TransformDescription desc;
247  TransformId tid = m_sortedResults[i].key;
248  TransformFactory *factory = TransformFactory::getInstance();
249  TransformFactory::TransformInstallStatus status =
250  factory->getTransformInstallStatus(tid);
251  QString suffix;
252 
253  if (status == TransformFactory::TransformInstalled) {
254  desc = factory->getTransformDescription(tid);
255  } else {
256  desc = factory->getUninstalledTransformDescription(tid);
257  suffix = tr("<i> (not installed)</i>");
258  }
259 
260  QString labelText;
261  labelText += tr("%1%2<br><small>")
262  .arg(XmlExportable::encodeEntities(desc.name))
263  .arg(suffix);
264 
265  labelText += "...";
266  for (TextMatcher::Match::FragmentMap::const_iterator k =
267  m_sortedResults[i].fragments.begin();
268  k != m_sortedResults[i].fragments.end(); ++k) {
269  labelText += k->second;
270  labelText += "... ";
271  }
272  labelText += tr("</small>");
273 
274  QString selectedText;
275  selectedText += tr("<b>%1</b>%2<br>")
276  .arg(XmlExportable::encodeEntities
277  (desc.name == "" ? desc.identifier : desc.name))
278  .arg(suffix);
279 
280  if (desc.longDescription != "") {
281  selectedText += tr("<small>%1</small>")
282  .arg(XmlExportable::encodeEntities(desc.longDescription));
283  } else if (desc.description != "") {
284  selectedText += tr("<small>%1</small>")
285  .arg(XmlExportable::encodeEntities(desc.description));
286  }
287 
288  selectedText += tr("<small>");
289  if (desc.type != TransformDescription::UnknownType) {
290  selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Plugin type: %1")
291  .arg(XmlExportable::encodeEntities(factory->getTransformTypeName(desc.type)));
292  }
293  if (desc.category != "") {
294  selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; Category: %1")
295  .arg(XmlExportable::encodeEntities(desc.category));
296  }
297  selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; System identifier: %1")
298  .arg(XmlExportable::encodeEntities(desc.identifier));
299  if (desc.infoUrl != "") {
300  selectedText += tr("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&mdash; More information: <a href=\"%1\">%1</a>")
301  .arg(desc.infoUrl);
302  }
303  selectedText += tr("</small>");
304 
305  if (i >= (int)m_labels.size()) {
307  m_resultsLayout->addWidget(label);
308  connect(label, SIGNAL(selectionChanged()), this,
309  SLOT(selectedLabelChanged()));
310  connect(label, SIGNAL(doubleClicked()), this,
311  SLOT(labelDoubleClicked()));
312  QPalette palette = label->palette();
313  label->setPalette(palette);
314  m_labels.push_back(label);
315  }
316 
317  m_labels[i]->setObjectName(desc.identifier);
318  m_labels[i]->setFixedWidth(this->width() - 40);
319  m_labels[i]->setUnselectedText(labelText);
320 
321 // cerr << "selected text: " << selectedText << endl;
322  m_labels[i]->setSelectedText(selectedText);
323 
324  m_labels[i]->setSelected(m_selectedTransform == desc.identifier);
325 
326  if (!m_labels[i]->isVisible()) m_labels[i]->show();
327 
328  ++m_upToDateCount;
329 
330  if (i == 0) break;
331  }
332 
333  m_resultsFrame->resize(m_resultsFrame->sizeHint());
334 }
335 
336 void
338 {
339  QObject *s = sender();
340  m_selectedTransform = "";
341  for (int i = 0; i < (int)m_labels.size(); ++i) {
342  if (!m_labels[i]->isVisible()) continue;
343  if (m_labels[i] == s) {
344  if (m_labels[i]->isSelected()) {
345  m_selectedTransform = m_labels[i]->objectName();
346  }
347  } else {
348  if (m_labels[i]->isSelected()) {
349  m_labels[i]->setSelected(false);
350  }
351  }
352  }
353  cerr << "selectedLabelChanged: selected transform is now \""
354  << m_selectedTransform << "\"" << endl;
355 }
356 
357 void
359 {
360  // The first click should have selected the label already
361  if (TransformFactory::getInstance()->getTransformInstallStatus
362  (m_selectedTransform) ==
363  TransformFactory::TransformInstalled) {
364  accept();
365  }
366 }
367 
368 TransformId
370 {
371  return m_selectedTransform;
372 }
373 
374 void
376 {
377  for (int i = 0; i < (int)m_labels.size(); ++i) {
378  if (!m_labels[i]->isVisible()) continue;
379  if (m_labels[i]->objectName() == m_selectedTransform) {
380  if (i > 0) {
381  m_labels[i]->setSelected(false);
382  m_labels[i-1]->setSelected(true);
383  m_selectedTransform = m_labels[i-1]->objectName();
384  }
385  return;
386  }
387  }
388 }
389 
390 void
392 {
393  for (int i = 0; i < (int)m_labels.size(); ++i) {
394  if (!m_labels[i]->isVisible()) continue;
395  if (m_labels[i]->objectName() == m_selectedTransform) {
396  if (i+1 < (int)m_labels.size() &&
397  m_labels[i+1]->isVisible()) {
398  m_labels[i]->setSelected(false);
399  m_labels[i+1]->setSelected(true);
400  m_selectedTransform = m_labels[i+1]->objectName();
401  }
402  return;
403  }
404  }
405 }
406 
QWidget * m_resultsFrame
QLabel * m_infoLabel
void searchTextChanged(const QString &)
QLabel * m_noResultsLabel
QVBoxLayout * m_resultsLayout
TransformId getTransform() const
TransformId m_selectedTransform
QLabel * m_beforeSearchLabel
TransformFinder(QWidget *parent=0)
QScrollArea * m_resultsScroll
QString m_newSearchText
std::vector< SelectableLabel * > m_labels
SortedResults m_sortedResults