scide: LookupDialog - use more expressive function names
[supercollider.git] / editors / sc-ide / widgets / lookup_dialog.cpp
blobfb26fa261fdddff451cdabb5a347be61f4df8e08
1 /*
2 SuperCollider Qt IDE
3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "lookup_dialog.hpp"
22 #include "main_window.hpp"
23 #include "../core/sc_introspection.hpp"
24 #include "../core/main.hpp"
26 #include <QVBoxLayout>
27 #include <QHeaderView>
28 #include <QKeyEvent>
29 #include <QDesktopWidget>
30 #include <QApplication>
31 #include <QPainter>
33 #include "yaml-cpp/node.h"
34 #include "yaml-cpp/parser.h"
36 namespace ScIDE {
38 GenericLookupDialog::GenericLookupDialog( QWidget * parent ):
39 QDialog(parent, Qt::Popup | Qt::FramelessWindowHint)
41 mQueryEdit = new QLineEdit(this);
43 mResult = new QTreeView(this);
44 mResult->setRootIsDecorated(false);
45 mResult->setAllColumnsShowFocus(true);
46 mResult->setHeaderHidden(true);
47 mResult->header()->setStretchLastSection(false);
49 QVBoxLayout *layout = new QVBoxLayout;
50 layout->setContentsMargins(4,4,4,4);
51 layout->setSpacing(1);
52 layout->addWidget(mQueryEdit);
53 layout->addWidget(mResult);
54 setLayout(layout);
56 connect(mQueryEdit, SIGNAL(returnPressed()), this, SLOT(performQuery()));
57 connect(mResult, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onAccepted(QModelIndex)));
58 connect(mResult, SIGNAL(activated(QModelIndex)), this, SLOT(onAccepted(QModelIndex)));
60 mResult->installEventFilter(this);
62 QRect bounds(0,0,600,300);
63 if (parent) {
64 QRect parentRect = parent->rect();
65 bounds.moveCenter( parent->mapToGlobal( parentRect.center() ) );
66 } else {
67 QRect availableBounds = QApplication::desktop()->availableGeometry(this);
68 bounds.moveCenter( availableBounds.center() );
71 setGeometry(bounds);
73 mQueryEdit->setFocus( Qt::OtherFocusReason );
76 void GenericLookupDialog::onAccepted(QModelIndex currentIndex)
78 QStandardItemModel * model = qobject_cast<QStandardItemModel*>(mResult->model());
79 currentIndex = currentIndex.sibling(currentIndex.row(), 0);
80 QStandardItem *currentItem = model->itemFromIndex(currentIndex);
81 if (!currentItem) {
82 reject();
83 return;
86 QString path = currentItem->data( PathRole ).toString();
87 int pos = currentItem->data( CharPosRole ).toInt();
89 Main::documentManager()->open(path, pos);
90 accept();
93 bool GenericLookupDialog::eventFilter( QObject *object, QEvent *event )
95 if (object == mResult && event->type() == QEvent::KeyPress) {
96 QKeyEvent *ke = static_cast<QKeyEvent*>(event);
97 switch(ke->key()){
98 case Qt::Key_Enter:
99 case Qt::Key_Return:
100 onAccepted(mResult->currentIndex());
101 return true;
102 default:;
106 return QDialog::eventFilter(object,event);
109 void GenericLookupDialog::paintEvent( QPaintEvent * )
111 QPainter painter(this);
112 painter.setBrush(Qt::NoBrush);
113 painter.setPen(palette().color(QPalette::Dark));
114 painter.drawRect(rect().adjusted(0,0,-1,-1));
117 void GenericLookupDialog::focusResults()
119 mResult->header()->resizeSections(QHeaderView::ResizeToContents);
120 mResult->setFocus(Qt::OtherFocusReason);
122 QStandardItemModel * model = qobject_cast<QStandardItemModel*>(mResult->model());
123 QStandardItem * firstItem = model->item(0, 0);
124 if (firstItem) {
125 QModelIndex firstIndex = model->indexFromItem(firstItem);
126 mResult->setCurrentIndex(firstIndex);
130 using namespace ScLanguage;
131 using std::pair;
132 using std::vector;
134 LookupDialog::LookupDialog( QWidget * parent ):
135 GenericLookupDialog(parent)
137 setWindowTitle(tr("Look Up Class or Method Definition"));
139 mQueryEdit->setText(tr("Enter symbol to look up"));
140 mQueryEdit->selectAll();
143 void LookupDialog::performQuery()
145 QString queryString = mQueryEdit->text();
147 if (queryString.isEmpty()) {
148 mResult->setModel(NULL);
149 return;
152 const Introspection & introspection = Main::scProcess()->introspection();
153 if (!introspection.introspectionAvailable()) {
154 MainWindow::instance()->showStatusMessage("Introspection data not yet available");
155 return;
158 if (queryString[0].isUpper()) {
159 bool success = performClassQuery(queryString);
160 if (success) {
161 focusResults();
162 return;
164 } else {
165 bool success = performMethodQuery(queryString);
166 if (success) {
167 focusResults();
168 return;
172 bool success = performPartialQuery(queryString);
173 if (success)
174 focusResults();
177 QList<QStandardItem*> GenericLookupDialog::makeDialogItem( QString const & name, QString const & displayPath,
178 QString const & path, int position, bool isClassItem )
180 QStandardItem * item = new QStandardItem( name );
181 item->setData( path, PathRole );
182 item->setData( position, CharPosRole );
183 item->setData( isClassItem, IsClassRole );
184 QStandardItem * pathItem = new QStandardItem(displayPath);
186 QList<QStandardItem*> ret;
187 ret << item << pathItem;
189 return ret;
192 QStandardItemModel * LookupDialog::modelForClass(const QString &className)
194 const Introspection & introspection = Main::scProcess()->introspection();
195 const Class *klass = introspection.findClass(className);
197 if (!klass)
198 return NULL;
200 QStandardItemModel * model = new QStandardItemModel(this);
201 QStandardItem *parentItem = model->invisibleRootItem();
203 while (klass) {
204 Class *metaClass = klass->metaClass;
206 QString displayPath = introspection.compactLibraryPath(klass->definition.path);
208 parentItem->appendRow(makeDialogItem(klass->name.get(), displayPath,
209 klass->definition.path.get(),
210 klass->definition.position, true ));
212 foreach (const Method * method, metaClass->methods) {
213 QString signature = method->signature( Method::SignatureWithoutArguments );
214 QString displayPath = introspection.compactLibraryPath(method->definition.path);
216 parentItem->appendRow(makeDialogItem( signature, displayPath,
217 method->definition.path.get(),
218 method->definition.position, false ));
221 foreach (const Method * method, klass->methods) {
222 QString signature = method->signature( Method::SignatureWithoutArguments );
223 QString displayPath = introspection.compactLibraryPath(method->definition.path);
225 parentItem->appendRow(makeDialogItem( signature, displayPath,
226 method->definition.path.get(),
227 method->definition.position, false ));
230 klass = klass->superClass;
233 return model;
236 QStandardItemModel * LookupDialog::modelForMethod(const QString & methodName)
238 const Introspection & introspection = Main::scProcess()->introspection();
240 const MethodMap & methods = introspection.methodMap();
241 pair<MethodMap::const_iterator, MethodMap::const_iterator> matchingMethods = methods.equal_range(methodName);
243 if (matchingMethods.first == matchingMethods.second)
244 return NULL;
246 QStandardItemModel * model = new QStandardItemModel(this);
247 QStandardItem *parentItem = model->invisibleRootItem();
249 for (MethodMap::const_iterator it = matchingMethods.first; it != matchingMethods.second; ++it) {
250 Method *method = it->second.data();
251 QString signature = method->signature( Method::SignatureWithoutArguments );
253 const QString & path = method->definition.path;
254 QString displayPath = introspection.compactLibraryPath(path);
256 parentItem->appendRow(makeDialogItem( signature, displayPath,
257 method->definition.path.get(),
258 method->definition.position, false ));
261 model->sort(0);
262 return model;
265 QStandardItemModel * LookupDialog::modelForPartialQuery(const QString & queryString)
267 const Introspection & introspection = Main::scProcess()->introspection();
268 vector<const Class *> classes = introspection.findClassPartial(queryString);
269 vector<const Method *> methods = introspection.findMethodPartial(queryString);
270 typedef vector<const Method *>::const_iterator MethodIterator;
271 typedef vector<const Class *>::const_iterator ClassIterator;
273 if (classes.empty() && methods.empty()) {
274 MainWindow::instance()->showStatusMessage("No result for query");
275 return NULL;
278 QStandardItemModel * model = new QStandardItemModel(this);
279 QStandardItem *parentItem = model->invisibleRootItem();
281 for (MethodIterator it = methods.begin(); it != methods.end(); ++it) {
282 const Method *method = *it;
283 QString signature = method->signature( Method::SignatureWithoutArguments );
285 const QString & path = method->definition.path;
286 QString displayPath = introspection.compactLibraryPath(path);
288 parentItem->appendRow(makeDialogItem( signature, displayPath,
289 method->definition.path.get(),
290 method->definition.position, false ));
293 for (ClassIterator it = classes.begin(); it != classes.end(); ++it) {
294 const Class * klass = *it;
295 QString displayPath = introspection.compactLibraryPath(klass->definition.path);
297 parentItem->appendRow(makeDialogItem(klass->name.get(), displayPath,
298 klass->definition.path.get(),
299 klass->definition.position, true ));
302 model->sort(0);
303 return model;
306 bool LookupDialog::performClassQuery(const QString & className)
308 QStandardItemModel * model = modelForClass(className);
309 mResult->setModel(model);
310 return model;
313 bool LookupDialog::performMethodQuery(const QString & methodName)
315 QStandardItemModel * model = modelForMethod(methodName);
316 mResult->setModel(model);
317 return model;
320 bool LookupDialog::performPartialQuery(const QString & queryString)
322 QStandardItemModel * model = modelForPartialQuery(queryString);
323 mResult->setModel(model);
324 return model;
328 ReferencesDialog::ReferencesDialog(QWidget * parent):
329 LookupDialog(parent)
331 setWindowTitle(tr("Look Up References"));
333 mQueryEdit->setText(tr("Enter symbol to find references"));
334 mQueryEdit->selectAll();
337 void ReferencesDialog::performQuery()
339 QString queryString = mQueryEdit->text();
341 if (queryString.isEmpty()) {
342 mResult->setModel(NULL);
343 return;
346 SymbolReferenceRequest * request = new SymbolReferenceRequest(Main::scProcess(), this);
347 connect(request, SIGNAL(response(QString,QString)), this, SLOT(onResposeFromLanguage(QString,QString)));
348 connect(request, SIGNAL(requestCanceled()), this, SLOT(requestCanceled()));
349 request->sendRequest(queryString);
352 void ReferencesDialog::requestCanceled()
354 mResult->setModel(NULL);
357 void ReferencesDialog::onResposeFromLanguage(const QString &, const QString &responseData)
359 QStandardItemModel * model = parse(responseData);
360 mResult->setModel(model);
362 if (model)
363 focusResults();
366 QStandardItemModel * ReferencesDialog::parse(const QString &responseData)
368 using namespace ScLanguage;
369 const Introspection & introspection = Main::scProcess()->introspection();
371 if (!introspection.introspectionAvailable()) { // just required for short path name
372 MainWindow::instance()->showStatusMessage("Introspection data not yet available");
373 return NULL;
376 std::stringstream stream;
377 stream << responseData.toStdString();
378 YAML::Parser parser(stream);
380 YAML::Node doc;
381 if(!parser.GetNextDocument(doc)) {
382 qWarning("no YAML document");
383 return NULL;
386 assert (doc.Type() == YAML::NodeType::Sequence);
388 QString symbol = doc[0].to<std::string>().c_str();
390 QStandardItemModel * model = new QStandardItemModel(this);
391 QStandardItem *parentItem = model->invisibleRootItem();
393 YAML::Node const & references = doc[1];
395 for (YAML::Iterator refIt = references.begin(); refIt != references.end(); ++refIt ) {
396 YAML::Node const & reference = *refIt;
397 QString className = reference[0].to<std::string>().c_str();
398 QString methodName = reference[1].to<std::string>().c_str();
399 QString path = reference[2].to<std::string>().c_str();
400 int charPos = reference[3].to<int>();
402 QString displayPath = introspection.compactLibraryPath(path);
403 QString fullName = ScLanguage::makeFullMethodName(className, methodName);
405 parentItem->appendRow(makeDialogItem(fullName, displayPath, path, charPos, false));
408 return model;
412 } // namespace ScIDE