2
Copyright (C) 2003 ian reinhart geiser <geiseri@kde.org>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
version 2, License as published by the Free Software Foundation.
8
This library is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
Library General Public License for more details.
13
You should have received a copy of the GNU Library General Public License
14
along with this library; see the file COPYING.LIB. If not, write to
15
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
Boston, MA 02111-1307, USA.
19
#include <qwhatsthis.h>
21
#include <qfileinfo.h>
22
#include <qtextstream.h>
24
#include <qpopupmenu.h>
26
#include <kiconloader.h>
28
#include <kgenericfactory.h>
30
#include <kdevpartcontroller.h>
31
#include <kdevmainwindow.h>
33
#include <codemodel.h>
34
#include <kparts/part.h>
37
#include <kdevproject.h>
40
#include <kapplication.h>
42
#include <kjsembed/kjsembedpart.h>
43
#include <kjsembed/jsconsolewidget.h>
45
#include <kdevplugininfo.h>
47
#include "kjssupport_part.h"
48
#include "kjsproblems.h"
49
#include "jscodecompletion.h"
50
#include "subclassingdlg.h"
52
typedef KDevGenericFactory<kjsSupportPart> kjsSupportFactory;
53
static const KDevPluginInfo data("kdevkjssupport");
54
K_EXPORT_COMPONENT_FACTORY( libkdevkjssupport, kjsSupportFactory( data ) );
65
kjsSupportPart::kjsSupportPart(QObject *parent, const char *name, const QStringList& )
66
: KDevLanguageSupport(&data, parent, name ? name : "kjsSupportPart" )
68
setInstance(kjsSupportFactory::instance());
69
setXMLFile("kdevkjssupport.rc");
72
m_build = new KAction( i18n("&Run"), "exec",Key_F9,this, SLOT(slotRun()),actionCollection(), "build_execute" );
73
m_build->setStatusText( i18n("Test the active script.") );
75
kdDebug() << "Creating kjssupport Part" << endl;
77
connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
78
this, SLOT(projectConfigWidget(KDialogBase*)) );
79
connect( core(), SIGNAL(projectOpened()), this, SLOT(projectOpened()) );
80
connect( core(), SIGNAL(projectClosed()), this, SLOT(projectClosed()) );
81
connect( partController(), SIGNAL(savedFile(const QString&)), this, SLOT(savedFile(const QString&)) );
82
connect(partController(), SIGNAL(activePartChanged(KParts::Part*)),
83
this, SLOT(slotActivePartChanged(KParts::Part *)));
84
connect(core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
85
this, SLOT(contextMenu(QPopupMenu *, const Context *)));
88
// Building kjs interpreter.
89
m_js = new KJSEmbed::KJSEmbedPart();
90
mainWindow()->embedOutputView( m_js->view() , i18n("KJS Console"),i18n("KJS Embed Console") );
92
// get the problem reporter
93
m_problemReporter = new KJSProblems( this, 0, "problems" );
94
mainWindow( )->embedOutputView( m_problemReporter, i18n("Problems"), i18n("Problem reporter"));
95
m_cc = new JSCodeCompletion();
99
kjsSupportPart::~kjsSupportPart()
101
delete m_problemReporter;
107
KDevLanguageSupport::Features kjsSupportPart::features()
109
return Features(Classes | Variables | Functions);
112
KMimeType::List kjsSupportPart::mimeTypes()
114
KMimeType::List list;
116
KMimeType::Ptr mime = KMimeType::mimeType( "application/x-javascript" );
122
void kjsSupportPart::slotRun()
124
// Execute the application here.
126
KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
129
m_js->runFile( ro_part->url().path() );
134
void kjsSupportPart::projectConfigWidget(KDialogBase *dlg)
137
// Create your config dialog here.
139
void kjsSupportPart::projectOpened()
141
kdDebug(9014) << "projectOpened()" << endl;
143
connect( project(), SIGNAL(addedFilesToProject(const QStringList &)),
144
this, SLOT(addedFilesToProject(const QStringList &)) );
145
connect( project(), SIGNAL(removedFilesFromProject(const QStringList &)),
146
this, SLOT(removedFilesFromProject(const QStringList &)) );
148
// We want to parse only after all components have been
149
// properly initialized
150
QTimer::singleShot(0, this, SLOT(parse()));
152
void kjsSupportPart::projectClosed()
156
void kjsSupportPart::savedFile(const QString &fileName)
160
if (project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 )))
162
kdDebug(9014) << "parse file " << fileName << endl;
164
emit addedSourceInfo( fileName );
167
void kjsSupportPart::addedFilesToProject(const QStringList &fileList)
169
kdDebug(9014) << "addedFilesToProject()" << endl;
171
QStringList::ConstIterator it;
173
for ( it = fileList.begin(); it != fileList.end(); ++it )
175
kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + ( *it ) << endl;
176
parse( project()->projectDirectory() + "/" + (*it) );
179
emit updatedSourceInfo();
181
void kjsSupportPart::removedFilesFromProject(const QStringList &fileList)
185
QStringList::ConstIterator it;
187
for ( it = fileList.begin(); it != fileList.end(); ++it )
189
QString fileName = project()->projectDirectory() + "/" + ( *it );
190
if( codeModel()->hasFile(fileName) )
192
kdDebug(9014) << "removed " << fileName << endl;
193
emit aboutToRemoveSourceInfo( fileName );
194
codeModel()->removeFile( codeModel()->fileByName(fileName) );
199
void kjsSupportPart::parse()
201
kdDebug(9014) << "initialParse()" << endl;
205
kapp->setOverrideCursor(waitCursor);
206
QStringList files = project()->allFiles();
207
m_problemReporter->clear();
209
for (QStringList::Iterator it = files.begin(); it != files.end() ;++it)
211
kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + (*it) << endl;
213
parse( project()->projectDirectory() + "/" + (*it) );
216
emit updatedSourceInfo();
217
kapp->restoreOverrideCursor();
219
kdDebug(9014) << "No project" << endl;
222
void kjsSupportPart::slotActivePartChanged(KParts::Part *part)
224
kdDebug() << "Changeing active part..." << endl;
225
m_cc->setActiveEditorPart(part);
229
\fn kjsSupportPart::parse(const QString &fileName)
231
void kjsSupportPart::parse(const QString &fileName)
233
QFileInfo fi(fileName);
234
if (fi.extension() == "js")
236
if( codeModel()->hasFile(fileName) )
238
emit aboutToRemoveSourceInfo( fileName );
239
codeModel()->removeFile( codeModel()->fileByName(fileName) );
242
FileDom m_file = codeModel()->create<FileModel>();
243
m_file->setName( fileName );
244
m_file->setFileName( fileName );
246
QFile f(QFile::encodeName(fileName));
247
if (!f.open(IO_ReadOnly))
252
QTextStream stream(&f);
254
bool inFunction = false;
255
QString lastFunction = "";
257
ClassDom currentClass;
259
QRegExp varRx("var[\\s]([_a-zA-Z\\d]+)");
260
QRegExp classVarRx("this\\.([_a-zA-Z\\d]+)");
261
QRegExp classMethRx("this\\.([_a-zA-Z\\d]+)[\\s]*=[\\s]*function(\\([^){}\\n\\r]*\\))");
262
QRegExp methRx("function[\\s]+([_a-zA-Z\\d]+[\\s]*\\([^){}\\n\\r]*\\))");
263
QRegExp allocRx("([_\\d\\w]+)[\\s]*=[\\s]*new[\\s]*([_\\d\\w]+)");
264
QRegExp assnRx("var[\\s]+([_\\d\\w]+)[\\s]+[=][\\s]+([_\\d\\w]+)[;]");
266
while (!stream.atEnd())
268
rawline = stream.readLine();
269
line = rawline.stripWhiteSpace().local8Bit();
270
kdDebug() << "Trying line: " << line << endl;
272
if (methRx.search(line) != -1 && depth == 0)
274
if (lastFunction != "" )
275
addMethod(lastFunction, m_file, lastLineNo);
276
lastFunction = methRx.cap(1);
279
else if(varRx.search(line) != -1 && depth == 0)
281
addAttribute(varRx.cap(1), m_file, lineNo);
283
else if(classMethRx.search(line) != -1 && depth > 0)
285
if ( lastFunction != "" )
287
currentClass = addClass(lastFunction, m_file, lastLineNo );
290
addMethod(classMethRx.cap(1)+classMethRx.cap(2), currentClass, lineNo);
292
else if(classVarRx.search(line) != -1 && depth > 0)
294
if ( lastFunction != "" )
296
currentClass = addClass(lastFunction, m_file, lastLineNo );
299
addAttribute(classVarRx.cap(1), currentClass, lineNo);
302
if( allocRx.search(line) != -1 )
304
QString varName = allocRx.cap(1);
305
QString varType = allocRx.cap(2);
307
typeProperty *type = new typeProperty();
309
type->name = varName;
310
type->type = varType;
312
m_typeMap.insert(varName, type);
313
kdDebug() << "Adding " << varName << " of type " << varType << " at scope " << depth << endl;
318
kdDebug() << "Syntax check..." << endl;
319
KJS::UString jsLine( line.latin1() );
321
KJS::UString errorMessage;
323
if ( !m_js->interpreter()->checkSyntax( jsLine, &lineNumber, &errorMessage ) )
325
kdDebug() << errorMessage.qstring() << " on line " << lineNo << endl;
326
m_problemReporter->addLine(m_file->fileName(), lineNo, errorMessage.qstring());
329
if( line.contains("{") )
332
if( line.contains("}") )
338
if (lastFunction != "" )
339
addMethod(lastFunction, m_file, lastLineNo);
343
kdDebug() << "Trying to add list..." << endl;
345
codeModel()->addFile( m_file );
351
ClassDom kjsSupportPart::addClass(const QString &name, FileDom file, uint lineNo)
353
ClassDom clazz = codeModel()->create<ClassModel>();
354
clazz->setName(name);
355
clazz->setFileName(file->fileName());
356
clazz->setStartPosition(lineNo, 0);
358
if( !file->hasClass(clazz->name()) ){
359
kdDebug() << "Add global class " << clazz->name() << endl;
360
file->addClass( clazz );
365
void kjsSupportPart::addMethod(const QString &name, ClassDom clazz, uint lineNo)
367
FunctionDom method = codeModel()->create<FunctionModel>();
368
method->setName(name);
369
method->setFileName(clazz->fileName());
370
method->setStartPosition(lineNo, 0);
372
if( !clazz->hasFunction(method->name()) ){
373
kdDebug() << "Add class method " << method->name() << endl;
374
clazz->addFunction( method );
378
void kjsSupportPart::addAttribute(const QString &name, ClassDom clazz, uint lineNo)
380
VariableDom var = codeModel()->create<VariableModel>();
382
var->setFileName(clazz->fileName());
383
var->setStartPosition( lineNo, 0 );
384
var->setType(i18n("Variable"));
386
if( !clazz->hasVariable(var->name()) ){
387
kdDebug() << "Add class attribute " << var->name() << endl;
388
clazz->addVariable(var);
392
void kjsSupportPart::addMethod(const QString &name, FileDom file, uint lineNo)
394
FunctionDom method = codeModel()->create<FunctionModel>();
395
method->setName(name);
396
method->setFileName(file->fileName());
397
method->setStartPosition(lineNo, 0);
399
if( !file->hasFunction(method->name()) ){
400
kdDebug() << "Add global method " << method->name() << endl;
401
file->addFunction( method );
405
void kjsSupportPart::addAttribute(const QString &name, FileDom file, uint lineNo)
407
VariableDom var = codeModel()->create<VariableModel>();
409
var->setFileName(file->fileName());
410
var->setStartPosition( lineNo, 0 );
411
var->setType(i18n("Variable"));
413
if( !file->hasVariable(var->name()) ){
414
kdDebug() << "Add global attribute " << var->name() << endl;
415
file->addVariable(var);
419
void kjsSupportPart::contextMenu(QPopupMenu * popupMenu, const Context *context)
421
kdDebug() << "1" << endl;
422
if (!context->hasType( Context::FileContext ))
425
kdDebug() << "2" << endl;
426
const FileContext *fcontext = static_cast<const FileContext*>(context);
427
m_selectedUI = fcontext->fileName();
428
if (m_selectedUI.right(3).lower() == ".ui")
429
int id = popupMenu->insertItem(i18n("Implement Slots"),
430
this, SLOT(implementSlots()));
432
m_selectedUI = QString::null;
435
void kjsSupportPart::implementSlots()
437
if (m_selectedUI.isEmpty())
440
QStringList newFiles;
441
SubclassingDlg *sub = new SubclassingDlg(this, m_selectedUI, newFiles);
443
project()->addFiles(newFiles);
448
#include "kjssupport_part.moc"