summaryrefslogtreecommitdiffstats
path: root/languages/kjssupport/kjssupport_part.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/kjssupport/kjssupport_part.cpp')
-rw-r--r--languages/kjssupport/kjssupport_part.cpp448
1 files changed, 448 insertions, 0 deletions
diff --git a/languages/kjssupport/kjssupport_part.cpp b/languages/kjssupport/kjssupport_part.cpp
new file mode 100644
index 00000000..c4907991
--- /dev/null
+++ b/languages/kjssupport/kjssupport_part.cpp
@@ -0,0 +1,448 @@
+/*
+ Copyright (C) 2003 ian reinhart geiser <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ version 2, License as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qwhatsthis.h>
+#include <qtimer.h>
+#include <qfileinfo.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qpopupmenu.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdevcore.h>
+#include <kdevpartcontroller.h>
+#include <kdevmainwindow.h>
+#include <domutil.h>
+#include <codemodel.h>
+#include <kparts/part.h>
+
+
+#include <kdevproject.h>
+#include <kaction.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include <kjsembed/kjsembedpart.h>
+#include <kjsembed/jsconsolewidget.h>
+
+#include <kdevplugininfo.h>
+
+#include "kjssupport_part.h"
+#include "kjsproblems.h"
+#include "jscodecompletion.h"
+#include "subclassingdlg.h"
+
+typedef KDevGenericFactory<kjsSupportPart> kjsSupportFactory;
+static const KDevPluginInfo data("kdevkjssupport");
+K_EXPORT_COMPONENT_FACTORY( libkdevkjssupport, kjsSupportFactory( data ) );
+
+
+class typeProperty
+{
+ public:
+ QString type;
+ QString name;
+ int depth;
+};
+
+kjsSupportPart::kjsSupportPart(QObject *parent, const char *name, const QStringList& )
+: KDevLanguageSupport(&data, parent, name ? name : "kjsSupportPart" )
+{
+ setInstance(kjsSupportFactory::instance());
+ setXMLFile("kdevkjssupport.rc");
+
+
+ m_build = new KAction( i18n("&Run"), "exec",Key_F9,this, SLOT(slotRun()),actionCollection(), "build_execute" );
+ m_build->setStatusText( i18n("Test the active script.") );
+
+ kdDebug() << "Creating kjssupport Part" << endl;
+
+ connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
+ this, SLOT(projectConfigWidget(KDialogBase*)) );
+ connect( core(), SIGNAL(projectOpened()), this, SLOT(projectOpened()) );
+ connect( core(), SIGNAL(projectClosed()), this, SLOT(projectClosed()) );
+ connect( partController(), SIGNAL(savedFile(const QString&)), this, SLOT(savedFile(const QString&)) );
+ connect(partController(), SIGNAL(activePartChanged(KParts::Part*)),
+ this, SLOT(slotActivePartChanged(KParts::Part *)));
+ connect(core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)));
+
+
+ // Building kjs interpreter.
+ m_js = new KJSEmbed::KJSEmbedPart();
+ mainWindow()->embedOutputView( m_js->view() , i18n("KJS Console"),i18n("KJS Embed Console") );
+
+ // get the problem reporter
+ m_problemReporter = new KJSProblems( this, 0, "problems" );
+ mainWindow( )->embedOutputView( m_problemReporter, i18n("Problems"), i18n("Problem reporter"));
+ m_cc = new JSCodeCompletion();
+ }
+
+
+kjsSupportPart::~kjsSupportPart()
+{
+ delete m_problemReporter;
+ delete m_cc;
+ delete m_build;
+ delete m_js;
+}
+
+KDevLanguageSupport::Features kjsSupportPart::features()
+{
+ return Features(Classes | Variables | Functions);
+}
+
+KMimeType::List kjsSupportPart::mimeTypes()
+{
+ KMimeType::List list;
+
+ KMimeType::Ptr mime = KMimeType::mimeType( "application/x-javascript" );
+ if( mime )
+ list << mime;
+
+ return list;
+}
+void kjsSupportPart::slotRun()
+{
+ // Execute the application here.
+
+ KParts::ReadOnlyPart * ro_part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
+ if ( ro_part )
+ {
+ m_js->runFile( ro_part->url().path() );
+ }
+
+}
+
+void kjsSupportPart::projectConfigWidget(KDialogBase *dlg)
+{
+ Q_UNUSED( dlg );
+ // Create your config dialog here.
+}
+void kjsSupportPart::projectOpened()
+{
+ kdDebug(9014) << "projectOpened()" << endl;
+
+ connect( project(), SIGNAL(addedFilesToProject(const QStringList &)),
+ this, SLOT(addedFilesToProject(const QStringList &)) );
+ connect( project(), SIGNAL(removedFilesFromProject(const QStringList &)),
+ this, SLOT(removedFilesFromProject(const QStringList &)) );
+
+ // We want to parse only after all components have been
+ // properly initialized
+ QTimer::singleShot(0, this, SLOT(parse()));
+}
+void kjsSupportPart::projectClosed()
+{
+
+}
+void kjsSupportPart::savedFile(const QString &fileName)
+{
+
+
+ if (project()->allFiles().contains(fileName.mid ( project()->projectDirectory().length() + 1 )))
+ {
+ kdDebug(9014) << "parse file " << fileName << endl;
+ parse( fileName );
+ emit addedSourceInfo( fileName );
+ }
+}
+void kjsSupportPart::addedFilesToProject(const QStringList &fileList)
+{
+ kdDebug(9014) << "addedFilesToProject()" << endl;
+
+ QStringList::ConstIterator it;
+
+ for ( it = fileList.begin(); it != fileList.end(); ++it )
+ {
+ kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + ( *it ) << endl;
+ parse( project()->projectDirectory() + "/" + (*it) );
+ }
+
+ emit updatedSourceInfo();
+}
+void kjsSupportPart::removedFilesFromProject(const QStringList &fileList)
+{
+
+
+ QStringList::ConstIterator it;
+
+ for ( it = fileList.begin(); it != fileList.end(); ++it )
+ {
+ QString fileName = project()->projectDirectory() + "/" + ( *it );
+ if( codeModel()->hasFile(fileName) )
+ {
+ kdDebug(9014) << "removed " << fileName << endl;
+ emit aboutToRemoveSourceInfo( fileName );
+ codeModel()->removeFile( codeModel()->fileByName(fileName) );
+ }
+ }
+
+}
+void kjsSupportPart::parse()
+{
+ kdDebug(9014) << "initialParse()" << endl;
+
+ if (project())
+ {
+ kapp->setOverrideCursor(waitCursor);
+ QStringList files = project()->allFiles();
+ m_problemReporter->clear();
+
+ for (QStringList::Iterator it = files.begin(); it != files.end() ;++it)
+ {
+ kdDebug(9014) << "maybe parse " << project()->projectDirectory() + "/" + (*it) << endl;
+
+ parse( project()->projectDirectory() + "/" + (*it) );
+
+ }
+ emit updatedSourceInfo();
+ kapp->restoreOverrideCursor();
+ } else {
+ kdDebug(9014) << "No project" << endl;
+ }
+}
+void kjsSupportPart::slotActivePartChanged(KParts::Part *part)
+{
+ kdDebug() << "Changeing active part..." << endl;
+ m_cc->setActiveEditorPart(part);
+}
+
+/*!
+ \fn kjsSupportPart::parse(const QString &fileName)
+ */
+void kjsSupportPart::parse(const QString &fileName)
+{
+ QFileInfo fi(fileName);
+ if (fi.extension() == "js")
+ {
+ if( codeModel()->hasFile(fileName) )
+ {
+ emit aboutToRemoveSourceInfo( fileName );
+ codeModel()->removeFile( codeModel()->fileByName(fileName) );
+ }
+
+ FileDom m_file = codeModel()->create<FileModel>();
+ m_file->setName( fileName );
+ m_file->setFileName( fileName );
+
+ QFile f(QFile::encodeName(fileName));
+ if (!f.open(IO_ReadOnly))
+ return;
+ QString rawline;
+ QString line;
+ uint lineNo = 0;
+ QTextStream stream(&f);
+ int depth = 0;
+ bool inFunction = false;
+ QString lastFunction = "";
+ int lastLineNo = 0;
+ ClassDom currentClass;
+
+ QRegExp varRx("var[\\s]([_a-zA-Z\\d]+)");
+ QRegExp classVarRx("this\\.([_a-zA-Z\\d]+)");
+ QRegExp classMethRx("this\\.([_a-zA-Z\\d]+)[\\s]*=[\\s]*function(\\([^){}\\n\\r]*\\))");
+ QRegExp methRx("function[\\s]+([_a-zA-Z\\d]+[\\s]*\\([^){}\\n\\r]*\\))");
+ QRegExp allocRx("([_\\d\\w]+)[\\s]*=[\\s]*new[\\s]*([_\\d\\w]+)");
+ QRegExp assnRx("var[\\s]+([_\\d\\w]+)[\\s]+[=][\\s]+([_\\d\\w]+)[;]");
+
+ while (!stream.atEnd())
+ {
+ rawline = stream.readLine();
+ line = rawline.stripWhiteSpace().local8Bit();
+ kdDebug() << "Trying line: " << line << endl;
+
+ if (methRx.search(line) != -1 && depth == 0)
+ {
+ if (lastFunction != "" )
+ addMethod(lastFunction, m_file, lastLineNo);
+ lastFunction = methRx.cap(1);
+ lastLineNo = lineNo;
+ }
+ else if(varRx.search(line) != -1 && depth == 0)
+ {
+ addAttribute(varRx.cap(1), m_file, lineNo);
+ }
+ else if(classMethRx.search(line) != -1 && depth > 0)
+ {
+ if ( lastFunction != "" )
+ {
+ currentClass = addClass(lastFunction, m_file, lastLineNo );
+ lastFunction = "";
+ }
+ addMethod(classMethRx.cap(1)+classMethRx.cap(2), currentClass, lineNo);
+ }
+ else if(classVarRx.search(line) != -1 && depth > 0)
+ {
+ if ( lastFunction != "" )
+ {
+ currentClass = addClass(lastFunction, m_file, lastLineNo );
+ lastFunction = "";
+ }
+ addAttribute(classVarRx.cap(1), currentClass, lineNo);
+ }
+
+ if( allocRx.search(line) != -1 )
+ {
+ QString varName = allocRx.cap(1);
+ QString varType = allocRx.cap(2);
+
+ typeProperty *type = new typeProperty();
+ type->depth = depth;
+ type->name = varName;
+ type->type = varType;
+
+ m_typeMap.insert(varName, type);
+ kdDebug() << "Adding " << varName << " of type " << varType << " at scope " << depth << endl;
+
+ }
+
+
+ kdDebug() << "Syntax check..." << endl;
+ KJS::UString jsLine( line.latin1() );
+ int lineNumber = 0;
+ KJS::UString errorMessage;
+
+ if ( !m_js->interpreter()->checkSyntax( jsLine, &lineNumber, &errorMessage ) )
+ {
+ kdDebug() << errorMessage.qstring() << " on line " << lineNo << endl;
+ m_problemReporter->addLine(m_file->fileName(), lineNo, errorMessage.qstring());
+ }
+
+ if( line.contains("{") )
+ ++depth;
+
+ if( line.contains("}") )
+ --depth;
+
+ ++lineNo;
+ }
+
+ if (lastFunction != "" )
+ addMethod(lastFunction, m_file, lastLineNo);
+
+ f.close();
+
+ kdDebug() << "Trying to add list..." << endl;
+
+ codeModel()->addFile( m_file );
+
+
+ }
+}
+
+ClassDom kjsSupportPart::addClass(const QString &name, FileDom file, uint lineNo)
+{
+ ClassDom clazz = codeModel()->create<ClassModel>();
+ clazz->setName(name);
+ clazz->setFileName(file->fileName());
+ clazz->setStartPosition(lineNo, 0);
+
+ if( !file->hasClass(clazz->name()) ){
+ kdDebug() << "Add global class " << clazz->name() << endl;
+ file->addClass( clazz );
+ }
+ return clazz;
+}
+
+void kjsSupportPart::addMethod(const QString &name, ClassDom clazz, uint lineNo)
+{
+ FunctionDom method = codeModel()->create<FunctionModel>();
+ method->setName(name);
+ method->setFileName(clazz->fileName());
+ method->setStartPosition(lineNo, 0);
+
+ if( !clazz->hasFunction(method->name()) ){
+ kdDebug() << "Add class method " << method->name() << endl;
+ clazz->addFunction( method );
+ }
+}
+
+void kjsSupportPart::addAttribute(const QString &name, ClassDom clazz, uint lineNo)
+{
+ VariableDom var = codeModel()->create<VariableModel>();
+ var->setName(name);
+ var->setFileName(clazz->fileName());
+ var->setStartPosition( lineNo, 0 );
+ var->setType(i18n("Variable"));
+
+ if( !clazz->hasVariable(var->name()) ){
+ kdDebug() << "Add class attribute " << var->name() << endl;
+ clazz->addVariable(var);
+ }
+}
+
+void kjsSupportPart::addMethod(const QString &name, FileDom file, uint lineNo)
+{
+ FunctionDom method = codeModel()->create<FunctionModel>();
+ method->setName(name);
+ method->setFileName(file->fileName());
+ method->setStartPosition(lineNo, 0);
+
+ if( !file->hasFunction(method->name()) ){
+ kdDebug() << "Add global method " << method->name() << endl;
+ file->addFunction( method );
+ }
+}
+
+void kjsSupportPart::addAttribute(const QString &name, FileDom file, uint lineNo)
+{
+ VariableDom var = codeModel()->create<VariableModel>();
+ var->setName(name);
+ var->setFileName(file->fileName());
+ var->setStartPosition( lineNo, 0 );
+ var->setType(i18n("Variable"));
+
+ if( !file->hasVariable(var->name()) ){
+ kdDebug() << "Add global attribute " << var->name() << endl;
+ file->addVariable(var);
+ }
+}
+
+void kjsSupportPart::contextMenu(QPopupMenu * popupMenu, const Context *context)
+{
+ kdDebug() << "1" << endl;
+ if (!context->hasType( Context::FileContext ))
+ return;
+
+ kdDebug() << "2" << endl;
+ const FileContext *fcontext = static_cast<const FileContext*>(context);
+ m_selectedUI = fcontext->fileName();
+ if (m_selectedUI.right(3).lower() == ".ui")
+ int id = popupMenu->insertItem(i18n("Implement Slots"),
+ this, SLOT(implementSlots()));
+ else
+ m_selectedUI = QString::null;
+}
+
+void kjsSupportPart::implementSlots()
+{
+ if (m_selectedUI.isEmpty())
+ return;
+
+ QStringList newFiles;
+ SubclassingDlg *sub = new SubclassingDlg(this, m_selectedUI, newFiles);
+ if (sub->exec())
+ project()->addFiles(newFiles);
+
+ delete sub;
+}
+
+#include "kjssupport_part.moc"