Subversion Repositories Scribus

Rev

Rev 7152 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2503 subik 1
/*
4430 cbradney 2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
7
/*
2503 subik 8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
12
*/
13
 
82 Franz 14
#include "pconsole.h"
15
#include "pconsole.moc"
6462 subik 16
 
2503 subik 17
#include <qpixmap.h>
18
#include <qvariant.h>
19
#include <qpushbutton.h>
20
#include <qheader.h>
21
#include <qlistview.h>
22
#include <qtextedit.h>
23
#include <qlayout.h>
2543 subik 24
#include <qsplitter.h>
2503 subik 25
#include <qtooltip.h>
26
#include <qwhatsthis.h>
27
#include <qmenubar.h>
28
#include <qfiledialog.h>
6462 subik 29
#include <qstatusbar.h>
30
 
2503 subik 31
#include <qsyntaxhighlighter.h>
32
#include "scribus.h"
2834 cbradney 33
#include "prefsmanager.h"
3750 subik 34
#include "prefsfile.h"
35
#include "prefscontext.h"
3953 cbradney 36
#include "scmessagebox.h"
5497 subik 37
#include "commonstrings.h"
2503 subik 38
 
6462 subik 39
 
3819 subik 40
extern QPixmap SCRIBUS_API loadIcon(QString nam);
82 Franz 41
 
2503 subik 42
 
43
PythonConsole::PythonConsole( QWidget* parent)
44
        : QWidget( parent, "PythonConsole", WType_TopLevel )
82 Franz 45
{
259 Franz 46
        setIcon(loadIcon("AppIcon.png"));
2503 subik 47
 
48
        // setup the menu
49
        menuBar = new QMenuBar(this, "menuBar");
50
        QPopupMenu *fileMenu = new QPopupMenu(this);
51
        fileMenu->insertItem(loadIcon("fileopen.png"), tr("&Open..."), this, SLOT(slot_open()), CTRL+Key_O);
52
        fileMenu->insertItem(loadIcon("DateiSave16.png"), tr("&Save"), this, SLOT(slot_save()), CTRL+Key_S);
6260 fschmid 53
        fileMenu->insertItem( tr("Save &As..."), this, SLOT(slot_saveAs()));
2503 subik 54
        fileMenu->insertSeparator();
55
        fileMenu->insertItem(loadIcon("exit.png"), tr("&Exit"), this, SLOT(slot_quit()));
6260 fschmid 56
        menuBar->insertItem( tr("&File"), fileMenu);
2503 subik 57
        QPopupMenu *scriptMenu = new QPopupMenu(this);
5049 subik 58
        scriptMenu->insertItem(loadIcon("ok.png"), tr("&Run"), this, SLOT(slot_runScript()), Key_F9);
6260 fschmid 59
        scriptMenu->insertItem( tr("Run As &Console"), this, SLOT(slot_runScriptAsConsole()), CTRL+Key_F9);
60
        scriptMenu->insertItem( tr("&Save Output..."), this, SLOT(slot_saveOutput()));
61
        menuBar->insertItem( tr("&Script"), scriptMenu);
2503 subik 62
 
6462 subik 63
        gridLayout = new QGridLayout( this, 0, 0, 1, 6, "gridLayout");
2503 subik 64
        gridLayout->setMenuBar(menuBar);
65
 
2543 subik 66
        editorsLayout = new QVBoxLayout( 0, 0, 6, "editorsLayout");
2503 subik 67
 
2543 subik 68
        QSplitter *splitter = new QSplitter(Qt::Vertical, this, "splitter");
69
        editorsLayout->addWidget(splitter);
2503 subik 70
 
2543 subik 71
        commandEdit = new QTextEdit(splitter, "commandEdit" );
2503 subik 72
        commandEdit->setTextFormat(Qt::PlainText);
73
        commandEdit->setFocus();
74
        commandEdit->setTabStopWidth(commandEdit->pointSize() * 4);
4101 craig 75
        QSizePolicy commandEditSize( commandEdit->sizePolicy() );
76
        commandEditSize.setVerStretch(4);
77
        commandEditSize.setVerData(QSizePolicy::Preferred);
78
        commandEdit->setSizePolicy(commandEditSize);
2503 subik 79
        // install syntax highlighter.
80
        SyntaxHighlighter *sxHigh = new SyntaxHighlighter(commandEdit);
7975 cbradney 81
        //remove that unused warning!
82
        sxHigh->currentParagraph();
2503 subik 83
 
2543 subik 84
        outputEdit = new QTextEdit(splitter, "outputEdit" );
2503 subik 85
        outputEdit->setTextFormat(Qt::PlainText);
2543 subik 86
        outputEdit->setReadOnly(true);
4101 craig 87
        QSizePolicy outputEditSize( outputEdit->sizePolicy() );
88
        outputEditSize.setVerStretch(10);
89
        outputEditSize.setVerData(QSizePolicy::Expanding);
90
        outputEdit->setSizePolicy(outputEditSize);
2503 subik 91
 
6462 subik 92
        statusBar = new QStatusBar(this, "statusBar");
93
        statusBar->setSizeGripEnabled(true);
94
        commandEdit_cursorPositionChanged(0, 0);
95
        editorsLayout->addWidget(statusBar);
96
 
2543 subik 97
        gridLayout->addLayout( editorsLayout, 0, 0 );
2226 cbradney 98
        languageChange();
3337 subik 99
        resize(QSize(640, 480).expandedTo(minimumSizeHint()));
2503 subik 100
        clearWState( WState_Polished );
2957 subik 101
 
102
        // welcome note
103
        QString welcomeText("\"\"\"");
104
        welcomeText += tr("Scribus Python Console");
105
        welcomeText += "\n\n";
106
        welcomeText += tr(
107
                        "This is derived from standard Python console "
108
                        "so it contains some limitations esp. in the "
109
                        "case of whitespaces. Please consult Scribus "
110
                        "manual for more informations.");
3337 subik 111
        welcomeText += "\"\"\"\n";
2957 subik 112
        commandEdit->setText(welcomeText);
3337 subik 113
        commandEdit->selectAll(true);
6462 subik 114
 
115
        connect(commandEdit, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(commandEdit_cursorPositionChanged(int, int)));
82 Franz 116
}
117
 
2503 subik 118
/*
119
 *  Destroys the object and frees any allocated resources
120
 */
121
PythonConsole::~PythonConsole()
82 Franz 122
{
7975 cbradney 123
        //delete the highlighter
124
        delete commandEdit->syntaxHighlighter();
82 Franz 125
}
126
 
5243 cbradney 127
void PythonConsole::setFonts()
128
{
129
        QFont font = QFont("Fixed");
130
        font.setStyleHint(QFont::TypeWriter);
131
        font.setPointSize(PrefsManager::instance()->appPrefs.AppFontSize);
132
        commandEdit->setFont(font);    
133
        outputEdit->setFont(font);
134
}
135
 
2600 cbradney 136
void PythonConsole::closeEvent(QCloseEvent *)
137
{
138
        emit paletteShown(false);
139
}
140
 
6462 subik 141
void PythonConsole::commandEdit_cursorPositionChanged(int para, int pos)
142
{
7123 fschmid 143
        statusBar->message( tr("Line: %1 Column: %2").arg(para+1).arg(pos+1));
6462 subik 144
}
145
 
2503 subik 146
void PythonConsole::languageChange()
2226 cbradney 147
{
6260 fschmid 148
        setCaption( tr("Script Console"));
2503 subik 149
        QToolTip::add(commandEdit, "<qt>" + tr("Write your commands here. A selection is processed as script") + "</qt>");
150
        QToolTip::add(outputEdit, "<qt>" + tr("Output of your script") + "</qt>");
2226 cbradney 151
}
2503 subik 152
 
153
void PythonConsole::slot_runScript()
154
{
155
        outputEdit->clear();
2957 subik 156
        parsePythonString();
2503 subik 157
        emit runCommand();
4101 craig 158
        outputEdit->setCursorPosition(0, 0);
2503 subik 159
}
160
 
2614 subik 161
void PythonConsole::slot_runScriptAsConsole()
162
{
2957 subik 163
        parsePythonString();
164
        commandEdit->clear();
165
        // content is destroyed. This is to prevent overwritting
166
        filename = QString::null;
5051 subik 167
        outputEdit->append("\n>>> " + m_command);
2957 subik 168
        emit runCommand();
169
}
170
 
171
void PythonConsole::parsePythonString()
172
{
2614 subik 173
        if (commandEdit->hasSelectedText())
5051 subik 174
                m_command = commandEdit->selectedText();
2614 subik 175
        else
2957 subik 176
        {
177
                commandEdit->selectAll(true);
5051 subik 178
                m_command = commandEdit->selectedText();
2957 subik 179
                commandEdit->selectAll(false);
180
        }
2614 subik 181
        // prevent user's wrong selection
5051 subik 182
        m_command += '\n';
2614 subik 183
}
184
 
2503 subik 185
/*
186
 * supplementary slots. Saving etc.
187
 */
188
void PythonConsole::slot_open()
189
{
2957 subik 190
        filename = QFileDialog::getOpenFileName(".",
6235 fschmid 191
                        tr("Python Scripts (*.py *.PY)"),
2503 subik 192
                        this,
193
                        "ofdialog",
3822 cbradney 194
                        tr("Open Python Script File"));
2957 subik 195
        if (filename.isNull())
2503 subik 196
                return;
197
        QFile file(filename);
198
        if (file.open(IO_ReadOnly))
199
        {
200
                QTextStream stream(&file);
201
                commandEdit->setText(stream.read());
202
                file.close();
203
        }
204
}
205
 
206
void PythonConsole::slot_save()
207
{
2957 subik 208
        if (filename.isNull())
2503 subik 209
        {
210
                slot_saveAs();
211
                return;
212
        }
213
        QFile f(filename);
214
        if (f.open(IO_WriteOnly))
215
        {
216
                QTextStream stream(&f);
217
                stream << commandEdit->text();
218
                f.close();
219
        }
220
}
221
 
222
void PythonConsole::slot_saveAs()
223
{
224
        QString oldFname = filename;
225
        filename = QFileDialog::getSaveFileName(".",
6235 fschmid 226
                        tr("Python Scripts (*.py *.PY)"),
2503 subik 227
                        this,
228
                        "sfdialog",
229
                        tr("Save the Python Commands in File"));
2957 subik 230
        if (filename.isNull())
2503 subik 231
                return;
232
        QFile f(filename);
233
        if (f.exists())
7152 jghali 234
        {
235
                QString fn = QDir::convertSeparators(filename);
5497 subik 236
                if (ScMessageBox::warning(this, CommonStrings::trWarning,
7152 jghali 237
                        "<qt>" + tr(QString("File %1 already exists. Do you want to replace it?").arg(fn)) + "</qt>",
5497 subik 238
                        QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
2503 subik 239
                {
240
                        filename = oldFname;
241
                        return;
242
                }
7152 jghali 243
        }
2503 subik 244
        slot_save();
245
}
246
 
247
void PythonConsole::slot_saveOutput()
248
{
249
        QString fname = QFileDialog::getSaveFileName(".",
250
                        tr("Text Files (*.txt)"),
251
                        this,
252
                        "sfdialog",
253
                        tr("Save Current Output"));
254
        if (fname == QString::null)
255
                return;
256
        QFile f(fname);
257
        if (!f.exists())
258
        {
7152 jghali 259
                QString fn = QDir::convertSeparators(filename);
5497 subik 260
                if (QMessageBox::warning(this, CommonStrings::trWarning,
7152 jghali 261
                        "<qt>" + tr(QString("File %1 already exists. Do you want to replace it?").arg(fn)) + "</qt>",
5497 subik 262
                        QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
2503 subik 263
                        return;
264
        }
265
        // save
266
        if (f.open(IO_WriteOnly))
267
        {
268
                QTextStream stream(&f);
269
                stream << outputEdit->text();
270
                f.close();
271
        }
272
}
273
 
274
void PythonConsole::slot_quit()
275
{
276
        emit paletteShown(false);
277
}
278
 
279
/*
280
 * Syntax highlighting
281
 */
282
SyntaxHighlighter::SyntaxHighlighter(QTextEdit *textEdit) : QSyntaxHighlighter(textEdit)
283
{
284
        // Reserved keywords in Python 2.4
285
        keywords << "and" << "assert" << "break" << "class" << "continue" << "def"
286
                         << "del" << "elif" << "else" << "except" << "exec" << "finally"
287
                         << "for" << "from" << "global" << "if" << "import" << "in"
288
                         << "is" << "lambda" << "not" << "or" << "pass" << "print" << "raise"
289
                         << "return" << "try" << "while" << "yield";
290
}
291
 
292
int SyntaxHighlighter::highlightParagraph(const QString &text, int endStateOfLastPara)
293
{
294
        // position in the text
3819 subik 295
        unsigned int i = 0;
2503 subik 296
 
297
        /* ! ! signals error message, which we want in red */
298
        if (text.length() >= 3 && text[0] == '!' && text[1] == ' ' && text[2] == '!')
299
        {
300
                setFormat(0, 3, QColor(Qt::white));
3750 subik 301
                setFormat(3, text.length() - 2, colors.errorColor);
2503 subik 302
                return 0;
303
        }
304
 
305
        /* Turns of syntax highlighting for this line */
306
        if (text.length() >= 2 && text[0] == '!' && text[i + 1] == ' ')
307
        {
308
                setFormat(0, 2, QColor(Qt::white));
3750 subik 309
                setFormat(2, text.length() - 2, colors.textColor);
2503 subik 310
                return 0;
311
        }
312
 
313
        if (endStateOfLastPara == 1)
314
        {
315
                int docstrEnd = text.find("\"\"\"");
316
                if (docstrEnd == -1)
317
                        docstrEnd = text.length();
3750 subik 318
                setFormat(i, docstrEnd + 3, colors.commentColor);
2503 subik 319
                if (docstrEnd == (int)text.length())
320
                        return 1;
321
                i = docstrEnd + 3; // move back to """
322
        }
323
 
324
        while (i < text.length())
325
        {
326
                // HACK: remember the i is *the next* index!
327
                QChar ch = text[i++];
328
 
329
                if (ch.isLetter())
330
                {
331
                        // Read one word
332
                        unsigned long s = i - 1;
333
                        QString actualWord = ch;
334
                        while ((ch = text[i]).isLetterOrNumber() || ch == '_')
335
                        {
336
                                i++;
337
                                actualWord += ch;
338
                        }
339
 
340
                        // Check for reserved keywords
341
                        if (keywords.contains(actualWord) != 0)
3750 subik 342
                                setFormat(s, (i - s), colors.keywordColor);
2503 subik 343
                        else
3750 subik 344
                                setFormat(s, (i - s), colors.textColor);
2503 subik 345
                } // ch.isletter
346
                else if (ch == '+' && text[i] != '=')
3750 subik 347
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 348
                else if (ch == '-' && text[i] != '=')
3750 subik 349
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 350
                else if (ch == '*' && text[i] == '*' && text[i + 1] != '=')
3750 subik 351
                        setFormat(i - 1, 2, colors.signColor);
2503 subik 352
                else if (ch == '*' && (text[i] != '=' && text[i] != '*'))
3750 subik 353
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 354
                else if (ch == '/' && text[i] == '/' && text[i + 1] != '=')
3750 subik 355
                        setFormat(i - 1, 2, colors.signColor);
2503 subik 356
                else if (ch == '/' && (text[i] != '=' && text[i] != '/'))
3750 subik 357
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 358
                else if (ch == '%' && text[i] != '=')
3750 subik 359
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 360
                else if (ch == '&' && text[i] != '=')
3750 subik 361
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 362
                else if (ch == '|' && text[i] != '=')
3750 subik 363
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 364
                else if (ch == '^' && text[i] != '=')
3750 subik 365
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 366
                else if (ch == '=' && text[i] == '=')
367
                {
3750 subik 368
                        setFormat(i - 1, 2, colors.signColor);
2503 subik 369
                        i++;
370
                }
371
                else if (ch == '!' && text[i] == '=')
372
                {
3750 subik 373
                        setFormat(i - 1, 2, colors.signColor);
2503 subik 374
                        i++;
375
                }
376
                else if (ch == '~')
3750 subik 377
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 378
                else if (ch == '<')
379
                {
380
                        if (text[i] == '>')
381
                        {
3750 subik 382
                                setFormat(i -1, 2, colors.signColor);
2503 subik 383
                                i++;
384
                        }
385
                        else if (text[i] == '<' && text[i + 1] == '=')
386
                        {
3750 subik 387
                                setFormat(i - 1, 3, colors.textColor);
2503 subik 388
                                i += 2;
389
                        }
390
                        else if (text[i] == '=' || text[i] == '<')
391
                        {
3750 subik 392
                                setFormat(i - 1, 2, colors.signColor);
2503 subik 393
                                i++;
394
                        }
395
                        else
3750 subik 396
                                setFormat(i - 1, 1, colors.signColor);
2503 subik 397
                } // ch == '<'
398
                else if (ch == '>')
399
                {
400
                        if (text[i] == '>' && text[i + 1] == '=')
401
                        {
3750 subik 402
                                setFormat(i - 1, 3, colors.textColor);
2503 subik 403
                                i += 2;
404
                        }
405
                        else if (text[i] == '=' || text[i] == '>')
406
                        {
3750 subik 407
                                setFormat(i - 1, 2, colors.signColor);
2503 subik 408
                                i++;
409
                        }
410
                        else
3750 subik 411
                                setFormat(i - 1, 1, colors.signColor);
2503 subik 412
                } // ch == '>'
413
                else if (ch >= '0' && ch <= '9')
414
                {
415
                        unsigned long s = i - 1; /* Start of number */
416
                        if (text[i] == 'x' || text[i] == 'X')
417
                        {
418
                                i++;
419
                                while ((text[i] >= '0' && text[i] <= '9') || (text[i] >= 'a' && text[i] <= 'f') || (text[i] >= 'A' && text[i] <= 'F'))
420
                                        i++;
421
                                if (text[i] == 'L')
422
                                        i++;
3750 subik 423
                                setFormat(s, (i - s), colors.numberColor);
2503 subik 424
                        }
425
                        while (text[i] >= '0' && text[i] <= '9')
426
                                i++;
427
 
428
                        bool floating = false;
429
                        if (text[i] == '.')
430
                        {
431
                                i++;
432
                                floating = true;
433
                                while (text[i] >= '0' && text[i] <= '9')
434
                                        i++;
435
                        }
436
                        if (text[i] == 'e' || text[i] == 'E')
437
                        {
438
                                floating = true;
439
                                i++;
440
                                if (text[i] == '+' || text[i] == '-')
441
                                        i++;
442
                                while (text[i] >= '0' && text[i] <= '9')
443
                                        i++;
444
                        }
445
                        if (!floating && text[i] == 'L')
446
                                i++;
3750 subik 447
                        setFormat(s, (i - s), colors.numberColor);
2503 subik 448
                } // if number
449
                else if ( ch == '@')
3750 subik 450
                        setFormat(i - 1, 1, colors.signColor);
2503 subik 451
                else if (ch == '#')
452
                {
3750 subik 453
                        setFormat((i - 1), (text.length() - i), colors.commentColor);
2503 subik 454
                        i = text.length();
455
                }
456
                // docstrings etc. (""" blah """)
457
                else if (ch == '"' && text.at(i) == '"' && text.at(i+1) == '"')
458
                {
459
                        bool cont = false; // continue?
460
                        int docstrEnd = text.find("\"\"\"", i + 2);
461
                        if (docstrEnd == -1)
462
                        {
463
                                docstrEnd = text.length() - i;
464
                                cont = true;
465
                        }
3750 subik 466
                        setFormat(i - 1, docstrEnd + 2, colors.commentColor);
2503 subik 467
                        if (cont)
468
                                return 1; // comment """ is opened
469
                        i += docstrEnd + 2;
470
                } // docstrings
471
                else if ( ch == '\'' || ch == '"')
472
                {
473
                        unsigned long s = i - 1;
474
                        if (text[i] != ch)
475
                        {
476
                                while (text[i] != ch && i != text.length())
477
                                        i++;
478
                                if (text[i] == ch)
479
                                        i++;
3750 subik 480
                                setFormat(s, (i - s), colors.stringColor);
2503 subik 481
                        }
482
                        else if (text[i] == ch && text[i + 1] == ch)
483
                        {
484
                                i += 2;
3750 subik 485
                                setFormat(s, (i - s), colors.textColor);
2503 subik 486
 
487
                        }
488
                        else if (text[i] == ch)
489
                        {
490
                                i++;
3750 subik 491
                                setFormat(s, (i - s), colors.stringColor);
2503 subik 492
                        }
493
                }
494
                /* Default */
3750 subik 495
                else setFormat(i - 1, 1, colors.textColor);
2503 subik 496
        }       // End of while statement
497
 
498
        return 0;
499
}
3750 subik 500
 
501
SyntaxColors::SyntaxColors()
502
{
503
        PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin");
504
        errorColor.setNamedColor(prefs->get("syntaxerror", "#aa0000"));
505
        commentColor.setNamedColor(prefs->get("syntaxcomment", "#A0A0A0"));
506
        keywordColor.setNamedColor(prefs->get("syntaxkeyword", "#00007f"));
507
        signColor.setNamedColor(prefs->get("syntaxsign", "#aa00ff"));
508
        numberColor.setNamedColor(prefs->get("syntaxnumber", "#ffaa00"));
509
        stringColor.setNamedColor(prefs->get("syntaxstring", "#005500"));
510
        textColor.setNamedColor(prefs->get("syntaxtext", "#000000"));
511
}
512
 
513
SyntaxColors::~SyntaxColors()
514
{
515
        PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("scriptplugin");
516
        prefs->set("syntaxerror", qcolor2named(errorColor));
517
        prefs->set("syntaxcomment", qcolor2named(commentColor));
518
        prefs->set("syntaxkeyword", qcolor2named(keywordColor));
519
        prefs->set("syntaxsign", qcolor2named(signColor));
520
        prefs->set("syntaxnumber", qcolor2named(numberColor));
521
        prefs->set("syntaxstring", qcolor2named(stringColor));
522
        prefs->set("syntaxtext", qcolor2named(textColor));
523
}
524
 
525
QString SyntaxColors::qcolor2named(QColor color)
526
{
527
        int r, g, b;
528
        QString retval("#");
529
        QString oct;
530
        color.getRgb(&r, &g, &b);
531
        retval += oct.setNum(r, 16).rightJustify(2, '0');
532
        retval += oct.setNum(g, 16).rightJustify(2, '0');
533
        retval += oct.setNum(b, 16).rightJustify(2, '0');
534
        return retval;
535
}