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>
29 #include <QDesktopWidget>
30 #include <QApplication>
33 #include "yaml-cpp/node.h"
34 #include "yaml-cpp/parser.h"
38 bool LookupDialogTreeView::openDocumentation()
40 GenericLookupDialog
* parent
= qobject_cast
<GenericLookupDialog
*>(parentWidget());
41 parent
->openDocumentation();
46 GenericLookupDialog::GenericLookupDialog( QWidget
* parent
):
47 QDialog(parent
, Qt::Popup
| Qt::FramelessWindowHint
)
49 addAction(MainWindow::instance()->action(MainWindow::HelpForSelection
));
51 mQueryEdit
= new QLineEdit(this);
53 mResult
= new LookupDialogTreeView(this);
54 mResult
->setRootIsDecorated(false);
55 mResult
->setAllColumnsShowFocus(true);
56 mResult
->setHeaderHidden(true);
57 mResult
->header()->setStretchLastSection(false);
59 QVBoxLayout
*layout
= new QVBoxLayout
;
60 layout
->setContentsMargins(4,4,4,4);
61 layout
->setSpacing(1);
62 layout
->addWidget(mQueryEdit
);
63 layout
->addWidget(mResult
);
66 connect(mQueryEdit
, SIGNAL(returnPressed()), this, SLOT(performQuery()));
67 connect(mResult
, SIGNAL(doubleClicked(QModelIndex
)), this, SLOT(onAccepted(QModelIndex
)));
68 connect(mResult
, SIGNAL(activated(QModelIndex
)), this, SLOT(onAccepted(QModelIndex
)));
70 mResult
->installEventFilter(this);
72 QRect
bounds(0,0,600,300);
74 QRect parentRect
= parent
->rect();
75 bounds
.moveCenter( parent
->mapToGlobal( parentRect
.center() ) );
77 QRect availableBounds
= QApplication::desktop()->availableGeometry(this);
78 bounds
.moveCenter( availableBounds
.center() );
83 mQueryEdit
->setFocus( Qt::OtherFocusReason
);
86 void GenericLookupDialog::openDocumentation()
88 QModelIndex currentIndex
= mResult
->currentIndex();
89 QStandardItemModel
* model
= qobject_cast
<QStandardItemModel
*>(mResult
->model());
93 currentIndex
= currentIndex
.sibling(currentIndex
.row(), 0);
94 QStandardItem
*currentItem
= model
->itemFromIndex(currentIndex
);
98 bool isClass
= currentItem
->data(IsClassRole
).toBool();
100 Main::openDocumentation(currentItem
->text());
105 void GenericLookupDialog::onAccepted(QModelIndex currentIndex
)
107 QStandardItemModel
* model
= qobject_cast
<QStandardItemModel
*>(mResult
->model());
108 currentIndex
= currentIndex
.sibling(currentIndex
.row(), 0);
109 QStandardItem
*currentItem
= model
->itemFromIndex(currentIndex
);
115 QString path
= currentItem
->data( PathRole
).toString();
116 int pos
= currentItem
->data( CharPosRole
).toInt();
118 Main::documentManager()->open(path
, pos
);
122 bool GenericLookupDialog::eventFilter( QObject
*object
, QEvent
*event
)
124 if (object
== mResult
&& event
->type() == QEvent::KeyPress
) {
125 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(event
);
129 onAccepted(mResult
->currentIndex());
135 return QDialog::eventFilter(object
,event
);
138 void GenericLookupDialog::paintEvent( QPaintEvent
* )
140 QPainter
painter(this);
141 painter
.setBrush(Qt::NoBrush
);
142 painter
.setPen(palette().color(QPalette::Dark
));
143 painter
.drawRect(rect().adjusted(0,0,-1,-1));
146 void GenericLookupDialog::focusResults()
148 mResult
->header()->resizeSections(QHeaderView::ResizeToContents
);
149 mResult
->setFocus(Qt::OtherFocusReason
);
151 QStandardItemModel
* model
= qobject_cast
<QStandardItemModel
*>(mResult
->model());
152 QStandardItem
* firstItem
= model
->item(0, 0);
154 QModelIndex firstIndex
= model
->indexFromItem(firstItem
);
155 mResult
->setCurrentIndex(firstIndex
);
159 using namespace ScLanguage
;
163 LookupDialog::LookupDialog( QWidget
* parent
):
164 GenericLookupDialog(parent
), mIsPartialQuery(false)
166 setWindowTitle(tr("Look Up Class or Method Definition"));
168 mQueryEdit
->setText(tr("Enter symbol to look up"));
169 mQueryEdit
->selectAll();
172 void LookupDialog::performQuery()
174 QString queryString
= mQueryEdit
->text();
176 if (queryString
.isEmpty()) {
177 mResult
->setModel(NULL
);
181 const Introspection
& introspection
= Main::scProcess()->introspection();
182 if (!introspection
.introspectionAvailable()) {
183 MainWindow::instance()->showStatusMessage("Introspection data not yet available");
187 mIsPartialQuery
= false;
188 if (queryString
[0].isUpper()) {
189 bool success
= performClassQuery(queryString
);
195 bool success
= performMethodQuery(queryString
);
202 bool success
= performPartialQuery(queryString
);
207 void LookupDialog::onAccepted(QModelIndex currentIndex
)
209 if (!mIsPartialQuery
) {
210 GenericLookupDialog::onAccepted(currentIndex
);
214 QStandardItemModel
* model
= qobject_cast
<QStandardItemModel
*>(mResult
->model());
215 currentIndex
= currentIndex
.sibling(currentIndex
.row(), 0);
216 QStandardItem
*currentItem
= model
->itemFromIndex(currentIndex
);
223 bool isClass
= currentItem
->data(IsClassRole
).toBool();
225 GenericLookupDialog::onAccepted(currentIndex
);
229 QString className
= currentItem
->text();
230 mQueryEdit
->setText(className
);
234 QList
<QStandardItem
*> GenericLookupDialog::makeDialogItem( QString
const & name
, QString
const & displayPath
,
235 QString
const & path
, int position
, bool isClassItem
)
237 QStandardItem
* item
= new QStandardItem( name
);
238 item
->setData( path
, PathRole
);
239 item
->setData( position
, CharPosRole
);
240 item
->setData( isClassItem
, IsClassRole
);
241 QStandardItem
* pathItem
= new QStandardItem(displayPath
);
243 QList
<QStandardItem
*> ret
;
244 ret
<< item
<< pathItem
;
249 QStandardItemModel
* LookupDialog::modelForClass(const QString
&className
)
251 const Introspection
& introspection
= Main::scProcess()->introspection();
252 const Class
*klass
= introspection
.findClass(className
);
257 QStandardItemModel
* model
= new QStandardItemModel(this);
258 QStandardItem
*parentItem
= model
->invisibleRootItem();
261 Class
*metaClass
= klass
->metaClass
;
263 QString displayPath
= introspection
.compactLibraryPath(klass
->definition
.path
);
265 parentItem
->appendRow(makeDialogItem(klass
->name
.get(), displayPath
,
266 klass
->definition
.path
.get(),
267 klass
->definition
.position
, true ));
269 foreach (const Method
* method
, metaClass
->methods
) {
270 QString signature
= method
->signature( Method::SignatureWithoutArguments
);
271 QString displayPath
= introspection
.compactLibraryPath(method
->definition
.path
);
273 parentItem
->appendRow(makeDialogItem( signature
, displayPath
,
274 method
->definition
.path
.get(),
275 method
->definition
.position
, false ));
278 foreach (const Method
* method
, klass
->methods
) {
279 QString signature
= method
->signature( Method::SignatureWithoutArguments
);
280 QString displayPath
= introspection
.compactLibraryPath(method
->definition
.path
);
282 parentItem
->appendRow(makeDialogItem( signature
, displayPath
,
283 method
->definition
.path
.get(),
284 method
->definition
.position
, false ));
287 klass
= klass
->superClass
;
293 QStandardItemModel
* LookupDialog::modelForMethod(const QString
& methodName
)
295 const Introspection
& introspection
= Main::scProcess()->introspection();
297 const MethodMap
& methods
= introspection
.methodMap();
298 pair
<MethodMap::const_iterator
, MethodMap::const_iterator
> matchingMethods
= methods
.equal_range(methodName
);
300 if (matchingMethods
.first
== matchingMethods
.second
)
303 QStandardItemModel
* model
= new QStandardItemModel(this);
304 QStandardItem
*parentItem
= model
->invisibleRootItem();
306 for (MethodMap::const_iterator it
= matchingMethods
.first
; it
!= matchingMethods
.second
; ++it
) {
307 Method
*method
= it
->second
.data();
308 QString signature
= method
->signature( Method::SignatureWithoutArguments
);
310 const QString
& path
= method
->definition
.path
;
311 QString displayPath
= introspection
.compactLibraryPath(path
);
313 parentItem
->appendRow(makeDialogItem( signature
, displayPath
,
314 method
->definition
.path
.get(),
315 method
->definition
.position
, false ));
322 QStandardItemModel
* LookupDialog::modelForPartialQuery(const QString
& queryString
)
324 const Introspection
& introspection
= Main::scProcess()->introspection();
325 vector
<const Class
*> classes
= introspection
.findClassPartial(queryString
);
326 vector
<const Method
*> methods
= introspection
.findMethodPartial(queryString
);
327 typedef vector
<const Method
*>::const_iterator MethodIterator
;
328 typedef vector
<const Class
*>::const_iterator ClassIterator
;
330 if (classes
.empty() && methods
.empty()) {
331 MainWindow::instance()->showStatusMessage("No result for query");
335 mIsPartialQuery
= true;
336 QStandardItemModel
* model
= new QStandardItemModel(this);
337 QStandardItem
*parentItem
= model
->invisibleRootItem();
339 for (MethodIterator it
= methods
.begin(); it
!= methods
.end(); ++it
) {
340 const Method
*method
= *it
;
341 QString signature
= method
->signature( Method::SignatureWithoutArguments
);
343 const QString
& path
= method
->definition
.path
;
344 QString displayPath
= introspection
.compactLibraryPath(path
);
346 parentItem
->appendRow(makeDialogItem( signature
, displayPath
,
347 method
->definition
.path
.get(),
348 method
->definition
.position
, false ));
351 for (ClassIterator it
= classes
.begin(); it
!= classes
.end(); ++it
) {
352 const Class
* klass
= *it
;
353 QString displayPath
= introspection
.compactLibraryPath(klass
->definition
.path
);
355 parentItem
->appendRow(makeDialogItem(klass
->name
.get(), displayPath
,
356 klass
->definition
.path
.get(),
357 klass
->definition
.position
, true ));
364 bool LookupDialog::performClassQuery(const QString
& className
)
366 QStandardItemModel
* model
= modelForClass(className
);
367 mResult
->setModel(model
);
371 bool LookupDialog::performMethodQuery(const QString
& methodName
)
373 QStandardItemModel
* model
= modelForMethod(methodName
);
374 mResult
->setModel(model
);
378 bool LookupDialog::performPartialQuery(const QString
& queryString
)
380 QStandardItemModel
* model
= modelForPartialQuery(queryString
);
381 mResult
->setModel(model
);
386 ReferencesDialog::ReferencesDialog(QWidget
* parent
):
389 setWindowTitle(tr("Look Up References"));
391 mQueryEdit
->setText(tr("Enter symbol to find references"));
392 mQueryEdit
->selectAll();
395 void ReferencesDialog::performQuery()
397 QString queryString
= mQueryEdit
->text();
399 if (queryString
.isEmpty()) {
400 mResult
->setModel(NULL
);
404 SymbolReferenceRequest
* request
= new SymbolReferenceRequest(Main::scProcess(), this);
405 connect(request
, SIGNAL(response(QString
,QString
)), this, SLOT(onResposeFromLanguage(QString
,QString
)));
406 connect(request
, SIGNAL(requestCanceled()), this, SLOT(requestCanceled()));
407 request
->sendRequest(queryString
);
410 void ReferencesDialog::requestCanceled()
412 mResult
->setModel(NULL
);
415 void ReferencesDialog::onResposeFromLanguage(const QString
&, const QString
&responseData
)
417 QStandardItemModel
* model
= parse(responseData
);
418 mResult
->setModel(model
);
424 QStandardItemModel
* ReferencesDialog::parse(const QString
&responseData
)
426 using namespace ScLanguage
;
427 const Introspection
& introspection
= Main::scProcess()->introspection();
429 if (!introspection
.introspectionAvailable()) { // just required for short path name
430 MainWindow::instance()->showStatusMessage("Introspection data not yet available");
434 std::stringstream stream
;
435 stream
<< responseData
.toStdString();
436 YAML::Parser
parser(stream
);
439 if(!parser
.GetNextDocument(doc
)) {
440 qWarning("no YAML document");
444 assert (doc
.Type() == YAML::NodeType::Sequence
);
446 QString symbol
= doc
[0].to
<std::string
>().c_str();
448 QStandardItemModel
* model
= new QStandardItemModel(this);
449 QStandardItem
*parentItem
= model
->invisibleRootItem();
451 YAML::Node
const & references
= doc
[1];
453 for (YAML::Iterator refIt
= references
.begin(); refIt
!= references
.end(); ++refIt
) {
454 YAML::Node
const & reference
= *refIt
;
455 QString className
= reference
[0].to
<std::string
>().c_str();
456 QString methodName
= reference
[1].to
<std::string
>().c_str();
457 QString path
= reference
[2].to
<std::string
>().c_str();
458 int charPos
= reference
[3].to
<int>();
460 QString displayPath
= introspection
.compactLibraryPath(path
);
461 QString fullName
= ScLanguage::makeFullMethodName(className
, methodName
);
463 parentItem
->appendRow(makeDialogItem(fullName
, displayPath
, path
, charPos
, false));