File indexing completed on 2025-01-05 04:26:46

0001 /****************************************************************************************
0002  * Copyright (c) 2013 Anmol Ahuja <darthcodus@gmail.com>                                *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #define DEBUG_PREFIX "ScriptConsoleItem"
0018 
0019 #include "ScriptConsoleItem.h"
0020 
0021 #include "amarokconfig.h"
0022 #include "core/support/Debug.h"
0023 #include "ScriptEditorDocument.h"
0024 
0025 #include <KMessageBox>
0026 #include <KTextEditor/View>
0027 
0028 #include <QFile>
0029 #include <QFileInfo>
0030 #include <QJSValue>
0031 #include <QTextStream>
0032 #include <QDir>
0033 #include <QPlainTextEdit>
0034 #include <QMessageLogContext>
0035 #include <QStringBuilder>
0036 
0037 
0038 using namespace ScriptConsoleNS;
0039 
0040 ScriptConsoleItem::ScriptConsoleItem( QObject *parent, const QString &name, const QString &category
0041                                     , const QString &path, ScriptEditorDocument *document )
0042 : ScriptItem( parent, name, QStringLiteral("%1/main.js").arg(path), createSpecFile( name, category, path ) )
0043 , m_clearOnDelete( false )
0044 , m_viewFactory( document )
0045 {
0046     document->setParent( this );
0047     document->save( url() );
0048     initializeScriptEngine();
0049 
0050     m_view = m_viewFactory->createView( nullptr );
0051     m_console= new QPlainTextEdit( nullptr );
0052     m_console->setReadOnly(true);
0053     m_output = new QPlainTextEdit( nullptr );
0054     m_output->setReadOnly(true);
0055     m_error = new QPlainTextEdit( nullptr );
0056     m_error->setReadOnly(true);
0057 
0058     connect( this, &ScriptConsoleItem::evaluated, this, &ScriptConsoleItem::updateOutputWidget);
0059     connect( this, &ScriptConsoleItem::signalHandlerException, this, &ScriptConsoleItem::updateErrorWidget);
0060 }
0061 
0062 ScriptConsoleItem::~ScriptConsoleItem()
0063 {
0064     if( running() )
0065         stop();
0066     if( m_clearOnDelete || !AmarokConfig::saveSession() ) // TODO: implement session restore + user config option, export button
0067     {
0068         QFileInfo info( url().path() );
0069         QDir dir( info.path() );
0070         if( !dir.exists() )
0071             return;
0072         dir.remove( QStringLiteral("main.js") );
0073         dir.remove( QStringLiteral("script.spec") );
0074         if( !dir.rmdir( dir.absolutePath() ) )
0075             debug() << "Directory %1 not removed, contains other files";
0076     }
0077     if( m_view )
0078         m_view->deleteLater();
0079     if (m_console)
0080         m_console->deleteLater();
0081     if (m_output)
0082         m_output->deleteLater();
0083     if (m_error)
0084         m_error->deleteLater();
0085 }
0086 
0087 KPluginInfo
0088 ScriptConsoleItem::createSpecFile( const QString &name, const QString &category, const QString &path )
0089 {
0090     QString specs = QString( "[Desktop Entry]"
0091                             "\nIcon=\"\""
0092                             "\nType=script"
0093                             "\nServiceTypes=KPluginInfo"
0094                             "\nName=%1"
0095                             "\nComment=Amarok console script"
0096                             "\nX-KDE-PluginInfo-Name=%1"
0097                             "\nX-KDE-PluginInfo-Version=1.0"
0098                             "\nX-KDE-PluginInfo-Category=%2"
0099                             "\nX-KDE-PluginInfo-Depends=Amarok2.0"
0100                             "\nX-KDE-PluginInfo-EnabledByDefault=false\n" ).arg( name, category );
0101     // TODO - Replace .desktop with new json format. Important: file extension matters
0102     QString specPath = QStringLiteral( "%1/script.desktop" ).arg( path );
0103     QFile file( specPath );
0104     if( !file.open( QIODevice::WriteOnly ) )
0105     {
0106         debug() << "Couldn't write to " + path;
0107         return KPluginInfo();
0108     }
0109     QTextStream stream( &file );
0110     stream << specs;
0111     file.close();
0112     return KPluginInfo( specPath );
0113 }
0114 
0115 bool
0116 ScriptConsoleItem::start( bool silent )
0117 {
0118     if( running() )
0119         return false;
0120     if( !info().isValid() )
0121     {
0122         debug() << "Invalid spec";
0123         return false;
0124     }
0125     m_viewFactory->save();
0126     Q_ASSERT( engine() );
0127     //engine()->pushContext();
0128     m_viewFactory->setReadWrite( false );
0129     bool result = ScriptItem::start( silent );
0130     m_viewFactory->setReadWrite( true );
0131     return result;
0132 }
0133 
0134 KTextEditor::View*
0135 ScriptConsoleItem::getEditorView( QWidget *parent )
0136 {
0137     m_view->setParent( parent );
0138     return m_view.data();
0139 }
0140 
0141 QWidget *
0142 ScriptConsoleItem::getConsoleWidget( QWidget *parent )
0143 {
0144     m_console->setParent( parent );
0145     return m_console.data();
0146 }
0147 
0148 void
0149 ScriptConsoleItem::appendToConsoleWidget( const QString &msg )
0150 {
0151     m_console->appendPlainText( msg );
0152 }
0153 
0154 QWidget *
0155 ScriptConsoleItem::getOutputWdiget( QWidget *parent )
0156 {
0157     m_output->setParent( parent );
0158     return m_output.data();
0159 }
0160 
0161 QWidget *
0162 ScriptConsoleItem::getErrorWidget( QWidget *parent )
0163 {
0164     m_error->setParent( parent );
0165     return m_error.data();
0166 }
0167 
0168 void
0169 ScriptConsoleItem::initializeScriptEngine()
0170 {
0171     ScriptItem::initializeScriptEngine();
0172 }
0173 
0174 void
0175 ScriptConsoleItem::timerEvent( QTimerEvent *event )
0176 {
0177     Q_UNUSED( event )
0178 }
0179 
0180 
0181 void
0182 ScriptConsoleItem::setClearOnDeletion( bool clearOnDelete )
0183 {
0184     m_clearOnDelete = clearOnDelete;
0185 }
0186 
0187 QString
0188 ScriptConsoleItem::handleError( QJSValue *result )
0189 {
0190     QString errorString = QStringLiteral( "Script Error: %1 (line: %2)" )
0191                         .arg( result->toString() )
0192                         .arg( result->property("lineNumber").toInt() );
0193 
0194     return errorString;
0195 }
0196 
0197 void
0198 ScriptConsoleItem::pause()
0199 {
0200     if( !running() )
0201         return;
0202     ///engine()->popContext();
0203     ScriptItem::pause();
0204 }
0205 
0206 void
0207 ScriptConsoleItem::updateOutputWidget( QString output )
0208 {
0209     m_output->appendPlainText( output );
0210 }
0211 
0212 void
0213 ScriptConsoleItem::updateErrorWidget( QJSValue error )
0214 {
0215     m_error->appendPlainText( handleError( &error ) );
0216 }