~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/kjssupport/kjssupport_part.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2006-05-23 18:39:42 UTC
  • Revision ID: james.westby@ubuntu.com-20060523183942-hucifbvh68k2bwz7
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Copyright (C) 2003 ian reinhart geiser <geiseri@kde.org> 
 
3
 
 
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.
 
7
 
 
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.
 
12
 
 
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.
 
17
*/
 
18
 
 
19
#include <qwhatsthis.h>
 
20
#include <qtimer.h>
 
21
#include <qfileinfo.h>
 
22
#include <qtextstream.h>
 
23
#include <qregexp.h>
 
24
#include <qpopupmenu.h>
 
25
 
 
26
#include <kiconloader.h>
 
27
#include <klocale.h>
 
28
#include <kgenericfactory.h>
 
29
#include <kdevcore.h>
 
30
#include <kdevpartcontroller.h>
 
31
#include <kdevmainwindow.h>
 
32
#include <domutil.h>
 
33
#include <codemodel.h>
 
34
#include <kparts/part.h>
 
35
 
 
36
 
 
37
#include <kdevproject.h>
 
38
#include <kaction.h>
 
39
#include <kdebug.h>
 
40
#include <kapplication.h>
 
41
 
 
42
#include <kjsembed/kjsembedpart.h>
 
43
#include <kjsembed/jsconsolewidget.h>
 
44
 
 
45
#include <kdevplugininfo.h>
 
46
 
 
47
#include "kjssupport_part.h"
 
48
#include "kjsproblems.h"
 
49
#include "jscodecompletion.h"
 
50
#include "subclassingdlg.h"
 
51
 
 
52
typedef KDevGenericFactory<kjsSupportPart> kjsSupportFactory;
 
53
static const KDevPluginInfo data("kdevkjssupport");
 
54
K_EXPORT_COMPONENT_FACTORY( libkdevkjssupport, kjsSupportFactory( data ) );
 
55
 
 
56
 
 
57
class typeProperty
 
58
{
 
59
        public:
 
60
                QString type;
 
61
                QString name;
 
62
                int depth;
 
63
};
 
64
 
 
65
kjsSupportPart::kjsSupportPart(QObject *parent, const char *name, const QStringList& )
 
66
: KDevLanguageSupport(&data, parent, name ? name : "kjsSupportPart" )
 
67
{
 
68
        setInstance(kjsSupportFactory::instance());
 
69
        setXMLFile("kdevkjssupport.rc");
 
70
 
 
71
 
 
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.") );
 
74
 
 
75
        kdDebug() << "Creating kjssupport Part" << endl;
 
76
 
 
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 *)));
 
86
 
 
87
 
 
88
     // Building kjs interpreter.
 
89
        m_js = new KJSEmbed::KJSEmbedPart();
 
90
        mainWindow()->embedOutputView( m_js->view() , i18n("KJS Console"),i18n("KJS Embed Console") );
 
91
 
 
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();
 
96
    }
 
97
 
 
98
 
 
99
kjsSupportPart::~kjsSupportPart()
 
100
{
 
101
        delete m_problemReporter;
 
102
        delete m_cc;
 
103
        delete m_build;
 
104
        delete m_js;
 
105
}
 
106
 
 
107
KDevLanguageSupport::Features kjsSupportPart::features()
 
108
{
 
109
        return Features(Classes | Variables | Functions);
 
110
}
 
111
 
 
112
KMimeType::List kjsSupportPart::mimeTypes()
 
113
{
 
114
        KMimeType::List list;
 
115
        
 
116
        KMimeType::Ptr mime = KMimeType::mimeType( "application/x-javascript" );
 
117
        if( mime )
 
118
                list << mime;
 
119
 
 
120
        return list;
 
121
}
 
122
void kjsSupportPart::slotRun()
 
123
{
 
124
        // Execute the application here.
 
125
 
 
126
        KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
 
127
        if ( ro_part ) 
 
128
        {
 
129
                m_js->runFile( ro_part->url().path() );
 
130
        }
 
131
        
 
132
}
 
133
 
 
134
void kjsSupportPart::projectConfigWidget(KDialogBase *dlg)
 
135
{
 
136
        Q_UNUSED( dlg );
 
137
        // Create your config dialog here.
 
138
}
 
139
void kjsSupportPart::projectOpened()
 
140
{
 
141
        kdDebug(9014) << "projectOpened()" << endl;
 
142
 
 
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 &)) );
 
147
 
 
148
        // We want to parse only after all components have been
 
149
        // properly initialized
 
150
        QTimer::singleShot(0, this, SLOT(parse()));
 
151
}
 
152
void kjsSupportPart::projectClosed()
 
153
{
 
154
 
 
155
}
 
156
void kjsSupportPart::savedFile(const QString &fileName)
 
157
{
 
158
 
 
159
 
 
160
        if (project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 )))
 
161
        {
 
162
                kdDebug(9014) << "parse file " << fileName << endl;
 
163
                parse( fileName );
 
164
                emit addedSourceInfo( fileName );
 
165
        }
 
166
}
 
167
void kjsSupportPart::addedFilesToProject(const QStringList &fileList)
 
168
{
 
169
        kdDebug(9014) << "addedFilesToProject()" << endl;
 
170
 
 
171
        QStringList::ConstIterator it;
 
172
 
 
173
        for ( it = fileList.begin(); it != fileList.end(); ++it )
 
174
        {
 
175
                kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + ( *it ) << endl;
 
176
                parse( project()->projectDirectory() + "/" + (*it) );
 
177
        }
 
178
 
 
179
        emit updatedSourceInfo();
 
180
}
 
181
void kjsSupportPart::removedFilesFromProject(const QStringList &fileList)
 
182
{
 
183
 
 
184
 
 
185
        QStringList::ConstIterator it;
 
186
 
 
187
        for ( it = fileList.begin(); it != fileList.end(); ++it )
 
188
        {
 
189
                QString fileName = project()->projectDirectory() + "/" + ( *it );
 
190
                if( codeModel()->hasFile(fileName) )
 
191
                {
 
192
                        kdDebug(9014) << "removed " << fileName << endl;
 
193
                        emit aboutToRemoveSourceInfo( fileName );
 
194
                        codeModel()->removeFile( codeModel()->fileByName(fileName) );
 
195
                }
 
196
        }
 
197
 
 
198
}
 
199
void kjsSupportPart::parse()
 
200
{
 
201
        kdDebug(9014) << "initialParse()" << endl;
 
202
 
 
203
        if (project())
 
204
        {
 
205
                kapp->setOverrideCursor(waitCursor);
 
206
                QStringList files = project()->allFiles();
 
207
                m_problemReporter->clear();
 
208
 
 
209
                for (QStringList::Iterator it = files.begin(); it != files.end() ;++it)
 
210
                {
 
211
                        kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + (*it) << endl;
 
212
                        
 
213
                        parse( project()->projectDirectory() + "/" + (*it) );
 
214
                        
 
215
                }
 
216
                emit updatedSourceInfo();
 
217
                kapp->restoreOverrideCursor();
 
218
        } else {
 
219
                kdDebug(9014) << "No project" << endl;
 
220
        }
 
221
}
 
222
void kjsSupportPart::slotActivePartChanged(KParts::Part *part)
 
223
{
 
224
        kdDebug() << "Changeing active part..." << endl;
 
225
        m_cc->setActiveEditorPart(part);
 
226
}
 
227
 
 
228
/*!
 
229
    \fn kjsSupportPart::parse(const QString &fileName)
 
230
 */
 
231
void kjsSupportPart::parse(const QString &fileName)
 
232
{
 
233
        QFileInfo fi(fileName);
 
234
        if (fi.extension() == "js")
 
235
        {
 
236
                if( codeModel()->hasFile(fileName) )
 
237
                {
 
238
                        emit aboutToRemoveSourceInfo( fileName );
 
239
                        codeModel()->removeFile( codeModel()->fileByName(fileName) );
 
240
                }
 
241
        
 
242
                FileDom m_file = codeModel()->create<FileModel>();
 
243
                m_file->setName( fileName );
 
244
                m_file->setFileName( fileName );
 
245
                
 
246
                QFile f(QFile::encodeName(fileName));
 
247
                if (!f.open(IO_ReadOnly))
 
248
                        return;
 
249
                QString rawline;
 
250
                QString line;
 
251
                uint lineNo = 0;
 
252
                QTextStream stream(&f);
 
253
                int depth = 0;
 
254
                bool inFunction = false;
 
255
                QString lastFunction = "";
 
256
                int lastLineNo = 0;
 
257
                ClassDom currentClass;
 
258
                
 
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]+)[;]");
 
265
                
 
266
                while (!stream.atEnd())
 
267
                {
 
268
                         rawline = stream.readLine();
 
269
                         line = rawline.stripWhiteSpace().local8Bit();
 
270
                         kdDebug() << "Trying line: " << line << endl;
 
271
                         
 
272
                        if (methRx.search(line) != -1 && depth == 0)
 
273
                        {
 
274
                                if (lastFunction != "" )
 
275
                                        addMethod(lastFunction, m_file, lastLineNo);
 
276
                                lastFunction = methRx.cap(1);
 
277
                                lastLineNo = lineNo;
 
278
                        }
 
279
                        else if(varRx.search(line) != -1 && depth == 0)
 
280
                        {
 
281
                                addAttribute(varRx.cap(1), m_file, lineNo);
 
282
                        }
 
283
                        else if(classMethRx.search(line) != -1 && depth > 0)
 
284
                        {
 
285
                                if ( lastFunction != "" )
 
286
                                {
 
287
                                        currentClass = addClass(lastFunction, m_file, lastLineNo );
 
288
                                        lastFunction = "";
 
289
                                }
 
290
                               addMethod(classMethRx.cap(1)+classMethRx.cap(2), currentClass, lineNo);
 
291
                        }
 
292
                        else if(classVarRx.search(line) != -1 && depth > 0)
 
293
                        {
 
294
                                if ( lastFunction != "" )
 
295
                                {
 
296
                                        currentClass = addClass(lastFunction, m_file, lastLineNo );
 
297
                                        lastFunction = "";
 
298
                                }
 
299
                                addAttribute(classVarRx.cap(1), currentClass, lineNo);
 
300
                        }
 
301
                        
 
302
                        if( allocRx.search(line) != -1 )
 
303
                        {
 
304
                                QString varName = allocRx.cap(1);
 
305
                                QString varType = allocRx.cap(2);
 
306
                                
 
307
                                typeProperty *type = new typeProperty();
 
308
                                type->depth = depth;
 
309
                                type->name = varName;
 
310
                                type->type = varType;
 
311
                                
 
312
                                m_typeMap.insert(varName, type);
 
313
                                kdDebug() << "Adding " << varName << " of type " << varType << " at scope " << depth << endl;
 
314
                                
 
315
                        }
 
316
                        
 
317
                                                
 
318
                        kdDebug() << "Syntax check..." << endl;
 
319
                        KJS::UString jsLine( line.latin1() );
 
320
                        int lineNumber = 0;
 
321
                        KJS::UString errorMessage;
 
322
        
 
323
                        if ( !m_js->interpreter()->checkSyntax( jsLine, &lineNumber, &errorMessage ) )
 
324
                        {
 
325
                                kdDebug() << errorMessage.qstring() << " on line " << lineNo << endl;
 
326
                                m_problemReporter->addLine(m_file->fileName(), lineNo, errorMessage.qstring());
 
327
                        }
 
328
 
 
329
                        if( line.contains("{") )
 
330
                                ++depth;
 
331
                                
 
332
                        if( line.contains("}") )
 
333
                                --depth;
 
334
 
 
335
                       ++lineNo;
 
336
                }
 
337
                
 
338
                if (lastFunction != "" )
 
339
                        addMethod(lastFunction, m_file, lastLineNo);
 
340
                                        
 
341
                f.close();
 
342
 
 
343
                kdDebug() << "Trying to add list..." << endl;
 
344
                
 
345
                codeModel()->addFile( m_file );
 
346
 
 
347
                
 
348
        }
 
349
}
 
350
 
 
351
ClassDom kjsSupportPart::addClass(const QString &name, FileDom file, uint lineNo)
 
352
{
 
353
        ClassDom clazz = codeModel()->create<ClassModel>();
 
354
        clazz->setName(name);
 
355
        clazz->setFileName(file->fileName());
 
356
        clazz->setStartPosition(lineNo, 0);
 
357
 
 
358
        if( !file->hasClass(clazz->name()) ){
 
359
                kdDebug() << "Add global class " << clazz->name() << endl;
 
360
                file->addClass( clazz );
 
361
        }
 
362
        return clazz;
 
363
}
 
364
 
 
365
void kjsSupportPart::addMethod(const QString &name, ClassDom clazz, uint lineNo)
 
366
{
 
367
        FunctionDom method = codeModel()->create<FunctionModel>();
 
368
        method->setName(name);
 
369
        method->setFileName(clazz->fileName());
 
370
        method->setStartPosition(lineNo, 0);
 
371
 
 
372
        if( !clazz->hasFunction(method->name()) ){
 
373
                kdDebug() << "Add class method " << method->name() << endl;
 
374
                clazz->addFunction( method );
 
375
        }
 
376
}
 
377
 
 
378
void kjsSupportPart::addAttribute(const QString &name, ClassDom clazz, uint lineNo)
 
379
{
 
380
        VariableDom var = codeModel()->create<VariableModel>();
 
381
        var->setName(name);
 
382
        var->setFileName(clazz->fileName());
 
383
        var->setStartPosition( lineNo, 0 );
 
384
        var->setType(i18n("Variable"));
 
385
 
 
386
        if( !clazz->hasVariable(var->name()) ){
 
387
                kdDebug() << "Add class attribute " << var->name() << endl;
 
388
                clazz->addVariable(var);
 
389
        }
 
390
}
 
391
 
 
392
void kjsSupportPart::addMethod(const QString &name, FileDom file, uint lineNo)
 
393
{
 
394
        FunctionDom method = codeModel()->create<FunctionModel>();
 
395
        method->setName(name);
 
396
        method->setFileName(file->fileName());
 
397
        method->setStartPosition(lineNo, 0);
 
398
 
 
399
        if( !file->hasFunction(method->name()) ){
 
400
                kdDebug() << "Add global method " << method->name() << endl;
 
401
                file->addFunction( method );
 
402
        }
 
403
}
 
404
 
 
405
void kjsSupportPart::addAttribute(const QString &name, FileDom file, uint lineNo)
 
406
{
 
407
        VariableDom var = codeModel()->create<VariableModel>();
 
408
        var->setName(name);
 
409
        var->setFileName(file->fileName());
 
410
        var->setStartPosition( lineNo, 0 );
 
411
        var->setType(i18n("Variable"));
 
412
 
 
413
        if( !file->hasVariable(var->name()) ){
 
414
                kdDebug() << "Add global attribute " << var->name() << endl;
 
415
                file->addVariable(var);
 
416
        }
 
417
}
 
418
 
 
419
void kjsSupportPart::contextMenu(QPopupMenu * popupMenu, const Context *context)
 
420
{
 
421
        kdDebug() << "1" << endl;
 
422
        if (!context->hasType( Context::FileContext ))
 
423
                return;
 
424
 
 
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()));
 
431
        else
 
432
                m_selectedUI = QString::null;
 
433
}
 
434
 
 
435
void kjsSupportPart::implementSlots()
 
436
{
 
437
        if (m_selectedUI.isEmpty())
 
438
                return;
 
439
        
 
440
        QStringList newFiles;
 
441
        SubclassingDlg *sub = new SubclassingDlg(this, m_selectedUI, newFiles);
 
442
        if (sub->exec())
 
443
                project()->addFiles(newFiles);
 
444
        
 
445
        delete sub;
 
446
}
 
447
 
 
448
#include "kjssupport_part.moc"