diff options
Diffstat (limited to 'tools/designer/editor')
23 files changed, 5480 insertions, 0 deletions
diff --git a/tools/designer/editor/arghintwidget.cpp b/tools/designer/editor/arghintwidget.cpp new file mode 100644 index 000000000..b1721ff59 --- /dev/null +++ b/tools/designer/editor/arghintwidget.cpp @@ -0,0 +1,239 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "arghintwidget.h" +#include <qbutton.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qpixmap.h> + +static const char * left_xpm[] = { +"16 16 3 1", +" c None", +". c #FFFFFF", +"+ c #000000", +" ", +" ", +" + ", +" ++ ", +" +++ ", +" ++++ ", +" +++++ ", +" ++++++ ", +" ++++++ ", +" +++++ ", +" ++++ ", +" +++ ", +" ++ ", +" + ", +" ", +" "}; + +static const char * right_xpm[] = { +"16 16 3 1", +" c None", +". c #FFFFFF", +"+ c #000000", +" ", +" ", +" + ", +" ++ ", +" +++ ", +" ++++ ", +" +++++ ", +" ++++++ ", +" ++++++ ", +" +++++ ", +" ++++ ", +" +++ ", +" ++ ", +" + ", +" ", +" "}; + +static const char * left_disabled_xpm[] = { +"16 16 3 1", +" c None", +". c #FFFFFF", +"+ c darkgray", +" ", +" ", +" + ", +" ++ ", +" +++ ", +" ++++ ", +" +++++ ", +" ++++++ ", +" ++++++ ", +" +++++ ", +" ++++ ", +" +++ ", +" ++ ", +" + ", +" ", +" "}; + +static const char * right_disabled_xpm[] = { +"16 16 3 1", +" c None", +". c #FFFFFF", +"+ c darkgray", +" ", +" ", +" + ", +" ++ ", +" +++ ", +" ++++ ", +" +++++ ", +" ++++++ ", +" ++++++ ", +" +++++ ", +" ++++ ", +" +++ ", +" ++ ", +" + ", +" ", +" "}; + +class ArrowButton : public TQButton +{ + Q_OBJECT + +public: + enum Dir { Left, Right }; + + ArrowButton( TQWidget *parent, const char *name, Dir d ); + void drawButton( TQPainter *p ); + +private: + TQPixmap pix, pix_disabled; + +}; + +ArrowButton::ArrowButton( TQWidget *parent, const char *name, Dir d ) + : TQButton( parent, name ) +{ + setFixedSize( 16, 16 ); + if ( d == Left ) { + pix = TQPixmap( left_xpm ); + pix_disabled = TQPixmap( left_disabled_xpm ); + } else { + pix = TQPixmap( right_xpm ); + pix_disabled = TQPixmap( right_disabled_xpm ); + } +} + +void ArrowButton::drawButton( TQPainter *p ) +{ + if ( isDown() ) + p->fillRect( 0, 0, width(), height(), darkGray ); + else + p->fillRect( 0, 0, width(), height(), lightGray ); + if ( isEnabled() ) + p->drawPixmap( 0, 0, pix ); + else + p->drawPixmap( 0, 0, pix_disabled ); +} + + +ArgHintWidget::ArgHintWidget( TQWidget *parent, const char*name ) + : TQFrame( parent, name, WType_Popup ), curFunc( 0 ), numFuncs( 0 ) +{ + setFrameStyle( TQFrame::Box | TQFrame::Plain ); + setLineWidth( 1 ); + setBackgroundColor( white ); + TQHBoxLayout *hbox = new TQHBoxLayout( this ); + hbox->setMargin( 1 ); + hbox->addWidget( ( prev = new ArrowButton( this, "editor_left_btn", ArrowButton::Left ) ) ); + hbox->addWidget( ( funcLabel = new TQLabel( this, "editor_func_lbl" ) ) ); + hbox->addWidget( ( next = new ArrowButton( this, "editor_right_btn", ArrowButton::Right ) ) ); + funcLabel->setBackgroundColor( white ); + funcLabel->setAlignment( AlignCenter ); + connect( prev, SIGNAL( clicked() ), this, SLOT( gotoPrev() ) ); + connect( next, SIGNAL( clicked() ), this, SLOT( gotoNext() ) ); + updateState(); + setFocusPolicy( NoFocus ); + prev->setFocusPolicy( NoFocus ); + next->setFocusPolicy( NoFocus ); + funcLabel->setFocusPolicy( NoFocus ); +} + +void ArgHintWidget::setFunctionText( int func, const TQString &text ) +{ + funcs.replace( func, text ); + if ( func == curFunc ) { + funcLabel->clear(); + funcLabel->setText( text ); + } +} + +void ArgHintWidget::setNumFunctions( int num ) +{ + funcs.clear(); + numFuncs = num; + curFunc = 0; + updateState(); +} + +void ArgHintWidget::gotoPrev() +{ + if ( curFunc > 0 ) { + curFunc--; + funcLabel->setText( funcs[ curFunc ] ); + updateState(); + } +} + +void ArgHintWidget::gotoNext() +{ + if ( curFunc < numFuncs - 1 ) { + curFunc++; + funcLabel->setText( funcs[ curFunc ] ); + updateState(); + } +} + +void ArgHintWidget::updateState() +{ + prev->setEnabled( curFunc > 0 ); + next->setEnabled( curFunc < numFuncs - 1 ); +} + +void ArgHintWidget::relayout() +{ + funcLabel->setText( "" ); + funcLabel->setText( funcs[ curFunc ] ); +} + +#include "arghintwidget.moc" diff --git a/tools/designer/editor/arghintwidget.h b/tools/designer/editor/arghintwidget.h new file mode 100644 index 000000000..fd5bc78c6 --- /dev/null +++ b/tools/designer/editor/arghintwidget.h @@ -0,0 +1,69 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef ARGHINTWIDGET_H +#define ARGHINTWIDGET_H + +#include <qframe.h> + +class TQLabel; +class ArrowButton; + +class ArgHintWidget : public TQFrame +{ + Q_OBJECT + +public: + ArgHintWidget( TQWidget *parent, const char*name ); + + void setFunctionText( int func, const TQString &text ); + void setNumFunctions( int num ); + +public slots: + void relayout(); + void gotoPrev(); + void gotoNext(); + +private: + void updateState(); + +private: + int curFunc; + int numFuncs; + TQMap<int, TQString> funcs; + TQLabel *funcLabel; + ArrowButton *prev, *next; + +}; + +#endif diff --git a/tools/designer/editor/browser.cpp b/tools/designer/editor/browser.cpp new file mode 100644 index 000000000..3ec2c62cb --- /dev/null +++ b/tools/designer/editor/browser.cpp @@ -0,0 +1,149 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "browser.h" +#include "editor.h" +#include <private/qrichtext_p.h> + + +EditorBrowser::EditorBrowser( Editor *e ) + : curEditor( e ), oldHighlightedParag( 0 ) +{ + curEditor = e; + + // ### disabled for now +// curEditor->viewport()->installEventFilter( this ); +// curEditor->installEventFilter( this ); + + TQFont fn( curEditor->font() ); + fn.setUnderline( TRUE ); + highlightedFormat = new TQTextFormat( fn, blue ); +} + +EditorBrowser::~EditorBrowser() +{ + delete highlightedFormat; +} + +bool EditorBrowser::eventFilter( TQObject *o, TQEvent *e ) +{ + if ( ::qt_cast<Editor*>(o->parent()) || ::qt_cast<Editor*>(o) ) { + TQMouseEvent *me; + TQKeyEvent *ke; + switch ( e->type() ) { + case TQEvent::MouseMove: + me = (TQMouseEvent*)e; + if ( ( me->state() & ControlButton ) == ControlButton ) { + curEditor->viewport()->setCursor( pointingHandCursor ); + TQTextCursor c( curEditor->document() ); + curEditor->placeCursor( curEditor->viewportToContents( me->pos() ), &c ); + TQTextCursor from, to; + if ( oldHighlightedParag ) { + oldHighlightedParag->setEndState( -1 ); + oldHighlightedParag->format(); + oldHighlightedParag = 0; + } + if ( findCursor( c, from, to ) && from.paragraph() == to.paragraph() ) { + // avoid collision with other selections + for ( int i = 0; i < curEditor->document()->numSelections(); ++i ) + curEditor->document()->removeSelection( i ); + from.paragraph()->setFormat( from.index(), to.index() - from.index() + 1, highlightedFormat, FALSE ); + lastWord = from.paragraph()->string()->toString().mid( from.index(), to.index() - from.index() + 1 ); + oldHighlightedParag = from.paragraph(); + } else { + lastWord = ""; + } + curEditor->repaintChanged(); + return TRUE; + } + break; + case TQEvent::MouseButtonPress: { + bool killEvent = !lastWord.isEmpty(); + if ( !lastWord.isEmpty() ) + showHelp( lastWord ); + lastWord = ""; + curEditor->viewport()->setCursor( ibeamCursor ); + if ( oldHighlightedParag ) { + oldHighlightedParag->setEndState( -1 ); + oldHighlightedParag->format(); + curEditor->repaintChanged(); + oldHighlightedParag = 0; + } + if ( killEvent ) + return TRUE; + } break; + case TQEvent::KeyRelease: + lastWord = ""; + ke = (TQKeyEvent*)e; + if ( ke->key() == Key_Control ) { + curEditor->viewport()->setCursor( ibeamCursor ); + if ( oldHighlightedParag ) { + oldHighlightedParag->setEndState( -1 ); + oldHighlightedParag->format(); + curEditor->repaintChanged(); + oldHighlightedParag = 0; + } + } + default: + break; + } + } + return FALSE; +} + +void EditorBrowser::setCurrentEdior( Editor *e ) +{ + curEditor = e; + curEditor->installEventFilter( this ); +} + +void EditorBrowser::addEditor( Editor *e ) +{ + e->installEventFilter( this ); +} + +bool EditorBrowser::findCursor( const TQTextCursor &c, TQTextCursor &from, TQTextCursor &to ) +{ + from = c; + while ( from.paragraph()->at( from.index() )->c != ' ' && from.paragraph()->at( from.index() )->c != '\t' && from.index() > 0 ) + from.gotoLeft(); + if ( from.paragraph()->at( from.index() )->c == ' ' || from.paragraph()->at( from.index() )->c == '\t' ) + from.gotoRight(); + to = c; + while ( to.paragraph()->at( to.index() )->c != ' ' && to.paragraph()->at( to.index() )->c != '\t' && + to.index() < to.paragraph()->length() - 1 ) + to.gotoRight(); + if ( to.paragraph()->at( to.index() )->c == ' ' || to.paragraph()->at( to.index() )->c == '\t' ) + to.gotoLeft(); + return TRUE; +} diff --git a/tools/designer/editor/browser.h b/tools/designer/editor/browser.h new file mode 100644 index 000000000..52524a66e --- /dev/null +++ b/tools/designer/editor/browser.h @@ -0,0 +1,66 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef BROWSER_H +#define BROWSER_H + +#include <qobject.h> + +class Editor; +class TQTextCursor; +class TQTextParagraph; +class TQTextFormat; + +class EditorBrowser : public TQObject +{ + Q_OBJECT + +public: + EditorBrowser( Editor *e ); + ~EditorBrowser(); + + bool eventFilter( TQObject *o, TQEvent *e ); + virtual void setCurrentEdior( Editor *e ); + virtual void addEditor( Editor *e ); + virtual bool findCursor( const TQTextCursor &c, TQTextCursor &from, TQTextCursor &to ); + virtual void showHelp( const TQString & ) {} + +protected: + Editor *curEditor; + TQTextParagraph *oldHighlightedParag; + TQString lastWord; + TQTextFormat *highlightedFormat; + +}; + +#endif diff --git a/tools/designer/editor/cindent.cpp b/tools/designer/editor/cindent.cpp new file mode 100644 index 000000000..50d7bb00a --- /dev/null +++ b/tools/designer/editor/cindent.cpp @@ -0,0 +1,163 @@ +/********************************************************************** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "cindent.h" +#include "qregexp.h" + +extern int indentForBottomLine( const TQStringList& program, TQChar typedIn ); +extern void setTabSize( int s ); +extern void setIndentSize( int s ); + +CIndent::CIndent() + : TQTextIndent(), tabSize( 8 ), indentSize( 4 ), + autoIndent( TRUE ), keepTabs( TRUE ), lastDoc( 0 ) +{ +} + +static int indentation( const TQString &s ) +{ + if ( s.simplifyWhiteSpace().length() == 0 ) + return 0; + int i = 0; + int ind = 0; + while ( i < (int)s.length() ) { + TQChar c = s.at( i ); + if ( c == ' ' ) + ind++; + else if ( c == '\t' ) + ind += 8; + else + break; + ++i; + } + return ind; +} + +void CIndent::tabify( TQString &s ) +{ + if ( !keepTabs ) + return; + int i = 0; + for ( ;; ) { + for ( int j = i; j < (int)s.length(); ++j ) { + if ( s[ j ] != ' ' && s[ j ] != '\t' ) { + if ( j > i ) { + TQString t = s.mid( i, j - i ); + int spaces = 0; + for ( int k = 0; k < (int)t.length(); ++k ) + spaces += ( t[ k ] == ' ' ? 1 : tabSize ); + s.remove( i, t.length() ); + int tabs = spaces / tabSize; + spaces = spaces - ( tabSize * tabs ); + TQString tmp; + tmp.fill( ' ', spaces ); + if ( spaces > 0 ) + s.insert( i, tmp ); + tmp.fill( '\t', tabs ); + if ( tabs > 0 ) + s.insert( i, tmp ); + } + break; + } + } + i = s.find( '\n', i ); + if ( i == -1 ) + break; + ++i; + } +} + +void CIndent::indentLine( TQTextParagraph *p, int &oldIndent, int &newIndent ) +{ + TQString indentString; + indentString.fill( ' ', newIndent ); + indentString.append( "a" ); + tabify( indentString ); + indentString.remove( indentString.length() - 1, 1 ); + newIndent = indentString.length(); + oldIndent = 0; + while ( p->length() > 0 && ( p->at( 0 )->c == ' ' || p->at( 0 )->c == '\t' ) ) { + ++oldIndent; + p->remove( 0, 1 ); + } + if ( p->string()->length() == 0 ) + p->append( " " ); + if ( !indentString.isEmpty() ) + p->insert( 0, indentString ); +} + + +void CIndent::indent( TQTextDocument *doc, TQTextParagraph *p, int *oldIndent, int *newIndent ) +{ + lastDoc = doc; + int oi = indentation( p->string()->toString() ); + TQStringList code; + TQTextParagraph *parag = doc->firstParagraph(); + while ( parag ) { + code << parag->string()->toString(); + if ( parag == p ) + break; + parag = parag->next(); + } + + int ind = indentForBottomLine( code, TQChar::null ); + indentLine( p, oi, ind ); + if ( oldIndent ) + *oldIndent = oi; + if ( newIndent ) + *newIndent = ind; +} + +void CIndent::reindent() +{ + if ( !lastDoc ) + return; + // #### this is sloooooooow (O(n^2)) + TQTextParagraph *parag = lastDoc->firstParagraph(); + while ( parag ) { + indent( lastDoc, parag, 0, 0 ); + parag = parag->next(); + } +} + +void CIndent::setTabSize( int ts ) +{ + tabSize = ts; + ::setTabSize( ts ); +} + +void CIndent::setIndentSize( int is ) +{ + indentSize = is; + ::setIndentSize( is ); +} diff --git a/tools/designer/editor/cindent.h b/tools/designer/editor/cindent.h new file mode 100644 index 000000000..06107dd38 --- /dev/null +++ b/tools/designer/editor/cindent.h @@ -0,0 +1,63 @@ +/********************************************************************** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef CINDENT_H +#define CINDENT_H + +#include <private/qrichtext_p.h> + +class CIndent : public TQTextIndent +{ +public: + CIndent(); + virtual ~CIndent() {} + void indent( TQTextDocument *doc, TQTextParagraph *parag, int *oldIndent, int *newIndent ); + + void setTabSize( int ts ); + void setIndentSize( int is ); + void setAutoIndent( bool ai ) { autoIndent = ai; reindent(); } + void setKeepTabs( bool kt ) { keepTabs = kt; } + +private: + void reindent(); + void indentLine( TQTextParagraph *p, int &oldIndent, int &newIndent ); + void tabify( TQString &s ); + +public: + int tabSize, indentSize; + bool autoIndent, keepTabs; + TQTextDocument *lastDoc; + +}; + +#endif diff --git a/tools/designer/editor/completion.cpp b/tools/designer/editor/completion.cpp new file mode 100644 index 000000000..1f9d0aa29 --- /dev/null +++ b/tools/designer/editor/completion.cpp @@ -0,0 +1,714 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "completion.h" +#include "paragdata.h" +#include "editor.h" +#include <qlistbox.h> +#include <qvbox.h> +#include <qmap.h> +#include <private/qrichtext_p.h> +#include <qapplication.h> +#include <qregexp.h> +#include "arghintwidget.h" +#include <qsizegrip.h> +#include <qtimer.h> + +static TQColor getColor( const TQString &type ) +{ + if ( type == "function" || type == "slot" || type == "package" ) + return TQt::blue; + else if ( type == "variable" || type == "widget" || type == "dir" ) + return TQt::darkRed; + else if ( type == "object" || type == "class" ) + return TQt::darkBlue; + else if ( type == "property" ) + return TQt::darkGreen; + else if ( type == "enum" ) + return TQt::darkYellow; + return TQt::black; +} + +class CompletionItem : public TQListBoxItem +{ +public: + CompletionItem( TQListBox *lb, const TQString &txt, const TQString &t, const TQString &p, + const TQString &pre, const TQString &p2 ) + : TQListBoxItem( lb ), type( t ), postfix( p ), prefix( pre ), postfix2( p2 ), + parag( 0 ), lastState( FALSE ) { setText( txt ); } + ~CompletionItem() { delete parag; } + void paint( TQPainter *painter ) { + if ( lastState != isSelected() ) { + delete parag; + parag = 0; + } + lastState = isSelected(); + if ( !parag ) + setupParagraph(); + parag->paint( *painter, listBox()->colorGroup() ); + } + + int height( const TQListBox * ) const { + if ( !parag ) + ( (CompletionItem*)this )->setupParagraph(); + return parag->rect().height(); + } + int width( const TQListBox * ) const { + if ( !parag ) + ( (CompletionItem*)this )->setupParagraph(); + return parag->rect().width() - 2; + } + TQString text() const { return TQListBoxItem::text() + postfix; } + +private: + void setupParagraph(); + TQString type, postfix, prefix, postfix2; + TQTextParagraph *parag; + bool lastState; + +}; + +void CompletionItem::setupParagraph() { + if ( !parag ) { + TQTextFormatter *formatter; + formatter = new TQTextFormatterBreakWords; + formatter->setWrapEnabled( FALSE ); + parag = new TQTextParagraph( 0 ); + parag->setTabStops( listBox()->fontMetrics().width( "propertyXXXX" ) ); + parag->pseudoDocument()->pFormatter = formatter; + parag->insert( 0, " " + type + ( type.isEmpty() ? " " : "\t" ) + prefix + + TQListBoxItem::text() + postfix + postfix2 ); + bool selCol = isSelected() && listBox()->colorGroup().highlightedText() != listBox()->colorGroup().text(); + TQColor sc = selCol ? listBox()->colorGroup().highlightedText() : getColor( type ); + TQTextFormat *f1 = parag->formatCollection()->format( listBox()->font(), sc ); + TQTextFormat *f3 = parag->formatCollection()->format( listBox()->font(), isSelected() ? + listBox()->colorGroup().highlightedText() : + listBox()->colorGroup().text() ); + TQFont f( listBox()->font() ); + f.setBold( TRUE ); + TQTextFormat *f2 = + parag->formatCollection()->format( f, isSelected() ? listBox()->colorGroup().highlightedText() : + listBox()->colorGroup().text() ); + parag->setFormat( 1, type.length() + 1, f1 ); + parag->setFormat( type.length() + 2, prefix.length() + TQListBoxItem::text().length(), f2 ); + if ( !postfix.isEmpty() ) + parag->setFormat( type.length() + 2 + prefix.length() + TQListBoxItem::text().length(), + postfix.length(), f3 ); + parag->setFormat( type.length() + 2 + prefix.length() + TQListBoxItem::text().length() + postfix.length(), + postfix2.length(), f3 ); + f1->removeRef(); + f2->removeRef(); + f3->removeRef(); + parag->format(); + } +} + + +EditorCompletion::EditorCompletion( Editor *e ) +{ + enabled = TRUE; + lastDoc = 0; + completionPopup = new TQVBox( e->topLevelWidget(), 0, WType_Popup ); + completionPopup->setFrameStyle( TQFrame::Box | TQFrame::Plain ); + completionPopup->setLineWidth( 1 ); + functionLabel = new ArgHintWidget( e->topLevelWidget(), "editor_function_lbl" ); + functionLabel->hide(); + completionListBox = new TQListBox( completionPopup, "editor_completion_lb" ); + completionListBox->setFrameStyle( TQFrame::NoFrame ); + completionListBox->installEventFilter( this ); + completionListBox->setHScrollBarMode( TQScrollView::AlwaysOn ); + completionListBox->setVScrollBarMode( TQScrollView::AlwaysOn ); + completionListBox->setCornerWidget( new TQSizeGrip( completionListBox, "editor_cornerwidget" ) ); + completionPopup->installEventFilter( this ); + functionLabel->installEventFilter( this ); + completionPopup->setFocusProxy( completionListBox ); + completionOffset = 0; + curEditor = e; + curEditor->installEventFilter( this ); +} + +EditorCompletion::~EditorCompletion() +{ + delete completionPopup; + delete functionLabel; +} + +void EditorCompletion::addCompletionEntry( const TQString &s, TQTextDocument *, bool strict ) +{ + TQChar key( s[ 0 ] ); + TQMap<TQChar, TQStringList>::Iterator it = completionMap.find( key ); + if ( it == completionMap.end() ) { + completionMap.insert( key, TQStringList( s ) ); + } else { + if ( strict ) { + TQStringList::Iterator sit; + for ( sit = (*it).begin(); sit != (*it).end(); ) { + TQStringList::Iterator it2 = sit; + ++sit; + if ( (*it2).length() > s.length() && (*it2).left( s.length() ) == s ) { + if ( (*it2)[ (int)s.length() ].isLetter() && (*it2)[ (int)s.length() ].upper() != (*it2)[ (int)s.length() ] ) + return; + } else if ( s.length() > (*it2).length() && s.left( (*it2).length() ) == *it2 ) { + if ( s[ (int)(*it2).length() ].isLetter() && s[ (int)(*it2).length() ].upper() != s[ (int)(*it2).length() ] ) + (*it).remove( it2 ); + } + } + } + (*it).append( s ); + } +} + +TQValueList<CompletionEntry> EditorCompletion::completionList( const TQString &s, TQTextDocument *doc ) const +{ + if ( doc ) + ( (EditorCompletion*)this )->updateCompletionMap( doc ); + + TQChar key( s[ 0 ] ); + TQMap<TQChar, TQStringList>::ConstIterator it = completionMap.find( key ); + if ( it == completionMap.end() ) + return TQValueList<CompletionEntry>(); + TQStringList::ConstIterator it2 = (*it).begin(); + TQValueList<CompletionEntry> lst; + int len = s.length(); + for ( ; it2 != (*it).end(); ++it2 ) { + CompletionEntry c; + c.type = ""; + c.text = *it2; + c.postfix = ""; + c.prefix = ""; + c.postfix2 = ""; + if ( (int)(*it2).length() > len && (*it2).left( len ) == s && lst.find( c ) == lst.end() ) + lst << c; + } + + return lst; +} + +void EditorCompletion::updateCompletionMap( TQTextDocument *doc ) +{ + bool strict = TRUE; + if ( doc != lastDoc ) + strict = FALSE; + lastDoc = doc; + TQTextParagraph *s = doc->firstParagraph(); + if ( !s->extraData() ) + s->setExtraData( new ParagData ); + while ( s ) { + if ( s->length() == ( (ParagData*)s->extraData() )->lastLengthForCompletion ) { + s = s->next(); + continue; + } + + TQChar c; + TQString buffer; + for ( int i = 0; i < s->length(); ++i ) { + c = s->at( i )->c; + if ( c.isLetter() || c.isNumber() || c == '_' || c == '#' ) { + buffer += c; + } else { + addCompletionEntry( buffer, doc, strict ); + buffer = TQString::null; + } + } + if ( !buffer.isEmpty() ) + addCompletionEntry( buffer, doc, strict ); + + ( (ParagData*)s->extraData() )->lastLengthForCompletion = s->length(); + s = s->next(); + } +} + +bool EditorCompletion::doCompletion() +{ + searchString = ""; + if ( !curEditor ) + return FALSE; + + TQTextCursor *cursor = curEditor->textCursor(); + TQTextDocument *doc = curEditor->document(); + + if ( cursor->index() > 0 && cursor->paragraph()->at( cursor->index() - 1 )->c == '.' && + ( cursor->index() == 1 || cursor->paragraph()->at( cursor->index() - 2 )->c != '.' ) ) + return doObjectCompletion(); + + int idx = cursor->index(); + if ( idx == 0 ) + return FALSE; + TQChar c = cursor->paragraph()->at( idx - 1 )->c; + if ( !c.isLetter() && !c.isNumber() && c != '_' && c != '#' ) + return FALSE; + + TQString s; + idx--; + completionOffset = 1; + for (;;) { + s.prepend( TQString( cursor->paragraph()->at( idx )->c ) ); + idx--; + if ( idx < 0 ) + break; + if ( !cursor->paragraph()->at( idx )->c.isLetter() && + !cursor->paragraph()->at( idx )->c.isNumber() && + cursor->paragraph()->at( idx )->c != '_' && + cursor->paragraph()->at( idx )->c != '#' ) + break; + completionOffset++; + } + + searchString = s; + + TQValueList<CompletionEntry> lst( completionList( s, doc ) ); + if ( lst.count() > 1 ) { + TQTextStringChar *chr = cursor->paragraph()->at( cursor->index() ); + int h = cursor->paragraph()->lineHeightOfChar( cursor->index() ); + int x = cursor->paragraph()->rect().x() + chr->x; + int y, dummy; + cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y ); + y += cursor->paragraph()->rect().y(); + completionListBox->clear(); + for ( TQValueList<CompletionEntry>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) + (void)new CompletionItem( completionListBox, (*it).text, (*it).type, (*it).postfix, + (*it).prefix, (*it).postfix2 ); + cList = lst; + completionPopup->resize( completionListBox->sizeHint() + + TQSize( completionListBox->verticalScrollBar()->width() + 4, + completionListBox->horizontalScrollBar()->height() + 4 ) ); + completionListBox->setCurrentItem( 0 ); + completionListBox->setFocus(); + if ( curEditor->mapToGlobal( TQPoint( 0, y ) ).y() + h + completionPopup->height() < TQApplication::desktop()->height() ) + completionPopup->move( curEditor->mapToGlobal( curEditor-> + contentsToViewport( TQPoint( x, y + h ) ) ) ); + else + completionPopup->move( curEditor->mapToGlobal( curEditor-> + contentsToViewport( TQPoint( x, y - completionPopup->height() ) ) ) ); + completionPopup->show(); + } else if ( lst.count() == 1 ) { + curEditor->insert( lst.first().text.mid( completionOffset, 0xFFFFFF ), + (uint) ( TQTextEdit::RedoIndentation | + TQTextEdit::CheckNewLines | + TQTextEdit::RemoveSelected ) ); + } else { + return FALSE; + } + + return TRUE; +} + +bool EditorCompletion::eventFilter( TQObject *o, TQEvent *e ) +{ + if ( !enabled ) + return FALSE; + if ( e->type() == TQEvent::KeyPress && ::qt_cast<Editor*>(o)) { + curEditor = (Editor*)o; + TQKeyEvent *ke = (TQKeyEvent*)e; + if ( ke->key() == Key_Tab ) { + TQString s = curEditor->textCursor()->paragraph()->string()->toString(). + left( curEditor->textCursor()->index() ); + if ( curEditor->document()->hasSelection( TQTextDocument::Standard ) || + s.simplifyWhiteSpace().isEmpty() ) { + if ( curEditor->document()->indent() ) { + curEditor->indent(); + int i = 0; + for ( ; i < curEditor->textCursor()->paragraph()->length() - 1; ++i ) { + if ( curEditor->textCursor()->paragraph()->at( i )->c != ' ' && + curEditor->textCursor()->paragraph()->at( i )->c != '\t' ) + break; + } + curEditor->drawCursor( FALSE ); + curEditor->textCursor()->setIndex( i ); + curEditor->drawCursor( TRUE ); + } else { + curEditor->insert( "\t" ); + } + return TRUE; + } + } + + if ( functionLabel->isVisible() ) { + if ( ke->key() == Key_Up && ( ke->state() & ControlButton ) == ControlButton ) { + functionLabel->gotoPrev(); + return TRUE; + } else if ( ke->key() == Key_Down && ( ke->state() & ControlButton ) == ControlButton ) { + functionLabel->gotoNext(); + return TRUE; + } + } + + if ( ke->text().length() && !( ke->state() & AltButton ) && + ( !ke->ascii() || ke->ascii() >= 32 ) || + ( ke->text() == "\t" && !( ke->state() & ControlButton ) ) ) { + if ( ke->key() == Key_Tab ) { + if ( curEditor->textCursor()->index() == 0 && + curEditor->textCursor()->paragraph()->isListItem() ) + return FALSE; + if ( doCompletion() ) + return TRUE; + } else if ( ke->key() == Key_Period && + ( curEditor->textCursor()->index() == 0 || + curEditor->textCursor()->paragraph()->at( curEditor->textCursor()->index() - 1 )->c != '.' ) + || + ke->key() == Key_Greater && + curEditor->textCursor()->index() > 0 && + curEditor->textCursor()->paragraph()->at( curEditor->textCursor()->index() - 1 )->c == '-' ) { + doObjectCompletion(); + } else { + if ( !doArgumentHint( ke->text() == "(" ) ) + functionLabel->hide(); + } + } + } else if ( o == completionPopup || o == completionListBox || + o == completionListBox->viewport() ) { + if ( e->type() == TQEvent::KeyPress ) { + TQKeyEvent *ke = (TQKeyEvent*)e; + if ( ke->key() == Key_Enter || ke->key() == Key_Return || ke->key() == Key_Tab ) { + if ( ke->key() == Key_Tab && completionListBox->count() > 1 && + completionListBox->currentItem() < (int)completionListBox->count() - 1 ) { + completionListBox->setCurrentItem( completionListBox->currentItem() + 1 ); + return TRUE; + } + completeCompletion(); + return TRUE; + } else if ( ke->key() == Key_Left || ke->key() == Key_Right || + ke->key() == Key_Up || ke->key() == Key_Down || + ke->key() == Key_Home || ke->key() == Key_End || + ke->key() == Key_Prior || ke->key() == Key_Next ) { + return FALSE; + } else if ( ke->key() != Key_Shift && ke->key() != Key_Control && + ke->key() != Key_Alt ) { + int l = searchString.length(); + if ( ke->key() == Key_Backspace ) { + searchString.remove( searchString.length() - 1, 1 ); + } else { + searchString += ke->text(); + l = 1; + } + if ( !l || !continueComplete() ) { + completionPopup->close(); + curEditor->setFocus(); + } + TQApplication::sendEvent( curEditor, e ); + return TRUE; + } + } else if ( e->type() == TQEvent::MouseButtonDblClick ) { + completeCompletion(); + return TRUE; + } + } + if ( o == functionLabel || ::qt_cast<Editor*>(o) && functionLabel->isVisible() ) { + if ( e->type() == TQEvent::KeyPress ) { + TQKeyEvent *ke = (TQKeyEvent*)e; + if ( ke->key() == Key_Escape ) { + functionLabel->hide(); + } else { + if ( !doArgumentHint( ke->text() == "(" ) ) + functionLabel->hide(); + if ( o == functionLabel ) { + TQApplication::sendEvent( curEditor, e ); + return TRUE; + } + } + } + } + return FALSE; +} + +void EditorCompletion::completeCompletion() +{ + int idx = curEditor->textCursor()->index(); + TQString s = completionListBox->currentText().mid( searchString.length() ); + curEditor->insert( s, (uint) ( TQTextEdit::RedoIndentation | + TQTextEdit::CheckNewLines | + TQTextEdit::RemoveSelected ) ); + int i = s.find( '(' ); + completionPopup->close(); + curEditor->setFocus(); + if ( i != -1 && i < (int)s.length() ) { + curEditor->setCursorPosition( curEditor->textCursor()->paragraph()->paragId(), idx + i + 1 ); + doArgumentHint( FALSE ); + } +} + +void EditorCompletion::setCurrentEdior( Editor *e ) +{ + curEditor = e; + curEditor->installEventFilter( this ); +} + +void EditorCompletion::addEditor( Editor *e ) +{ + e->installEventFilter( this ); +} + +bool EditorCompletion::doObjectCompletion() +{ + searchString = ""; + TQString object; + int i = curEditor->textCursor()->index(); + i--; + TQTextParagraph *p = curEditor->textCursor()->paragraph(); + for (;;) { + if ( i < 0 ) + break; + if ( p->at( i )->c == ' ' || p->at( i )->c == '\t' ) + break; + object.prepend( p->at( i )->c ); + i--; + } + + if ( object[ (int)object.length() - 1 ] == '-' ) + object.remove( object.length() - 1, 1 ); + + if ( object.isEmpty() ) + return FALSE; + return doObjectCompletion( object ); +} + +bool EditorCompletion::doObjectCompletion( const TQString & ) +{ + return FALSE; +} + +static void strip( TQString &txt ) +{ + int i = txt.find( "(" ); + if ( i == -1 ) + return; + txt = txt.left( i ); +} + +bool EditorCompletion::continueComplete() +{ + if ( searchString.isEmpty() ) { + completionListBox->clear(); + for ( TQValueList<CompletionEntry>::ConstIterator it = cList.begin(); it != cList.end(); ++it ) + (void)new CompletionItem( completionListBox, (*it).text, (*it).type, + (*it).postfix, (*it).prefix, (*it).postfix2 ); + completionListBox->setCurrentItem( 0 ); + completionListBox->setSelected( completionListBox->currentItem(), TRUE ); + return TRUE; + } + + TQListBoxItem *i = completionListBox->findItem( searchString ); + if ( !i ) + return FALSE; + + TQString txt1 = i->text(); + TQString txt2 = searchString; + strip( txt1 ); + strip( txt2 ); + if ( txt1 == txt2 && !i->next() ) + return FALSE; + + TQValueList<CompletionEntry> res; + for ( TQValueList<CompletionEntry>::ConstIterator it = cList.begin(); it != cList.end(); ++it ) { + if ( (*it).text.left( searchString.length() ) == searchString ) + res << *it; + } + if ( res.isEmpty() ) + return FALSE; + completionListBox->clear(); + for ( TQValueList<CompletionEntry>::ConstIterator it2 = res.begin(); it2 != res.end(); ++it2 ) + (void)new CompletionItem( completionListBox, (*it2).text, (*it2).type, + (*it2).postfix, (*it2).prefix, (*it2).postfix2 ); + completionListBox->setCurrentItem( 0 ); + completionListBox->setSelected( completionListBox->currentItem(), TRUE ); + return TRUE; +} + +bool EditorCompletion::doArgumentHint( bool useIndex ) +{ + TQTextCursor *cursor = curEditor->textCursor(); + int i = cursor->index() ; + if ( !useIndex ) { + bool foundParen = FALSE; + int closeParens = 0; + while ( i >= 0 ) { + if ( cursor->paragraph()->at( i )->c == ')' && i != cursor->index() ) + closeParens++; + if ( cursor->paragraph()->at( i )->c == '(' ) { + closeParens--; + if ( closeParens == -1 ) { + foundParen = TRUE; + break; + } + } + --i; + } + + if ( !foundParen ) + return FALSE; + } + int j = i - 1; + bool foundSpace = FALSE; + bool foundNonSpace = FALSE; + while ( j >= 0 ) { + if ( foundNonSpace && ( cursor->paragraph()->at( j )->c == ' ' || cursor->paragraph()->at( j )->c == ',' ) ) { + foundSpace = TRUE; + break; + } + if ( !foundNonSpace && ( cursor->paragraph()->at( j )->c != ' ' || cursor->paragraph()->at( j )->c != ',' ) ) + foundNonSpace = TRUE; + --j; + } + if ( foundSpace ) + ++j; + j = TQMAX( j, 0 ); + TQString function( cursor->paragraph()->string()->toString().mid( j, i - j + 1 ) ); + TQString part = cursor->paragraph()->string()->toString().mid( j, cursor->index() - j + 1 ); + function = function.simplifyWhiteSpace(); + for (;;) { + if ( function[ (int)function.length() - 1 ] == '(' ) { + function.remove( function.length() - 1, 1 ); + function = function.simplifyWhiteSpace(); + } else if ( function[ (int)function.length() - 1 ] == ')' ) { + function.remove( function.length() - 1, 1 ); + function = function.simplifyWhiteSpace(); + } else { + break; + } + } + + TQChar sep; + TQString pre, post; + TQValueList<TQStringList> argl = functionParameters( function, sep, pre, post ); + if ( argl.isEmpty() ) + return FALSE; + + TQString label; + int w = 0; + int num = 0; + if ( !functionLabel->isVisible() ) + functionLabel->setNumFunctions( (int)argl.count() ); + for ( TQValueList<TQStringList>::Iterator vit = argl.begin(); vit != argl.end(); ++vit, ++num ) { + TQStringList args = *vit; + int argNum = 0; + int inParen = 0; + for ( int k = 0; k < (int)part.length(); ++k ) { + if ( part[ k ] == sep && inParen < 2 ) + argNum++; + if ( part[ k ] == '(' ) + inParen++; + if ( part[ k ] == ')' ) + inParen--; + } + + TQString func = function; + int pnt = -1; + pnt = func.findRev( '.' ); + if ( pnt == -1 ) + func.findRev( '>' ); + if ( pnt != -1 ) + func = func.mid( pnt + 1 ); + + TQString s = func + "( "; + if ( s[ 0 ] == '\"' ) + s.remove( (uint)0, 1 ); + i = 0; + for ( TQStringList::Iterator it = args.begin(); it != args.end(); ++it, ++i ) { + if ( i == argNum ) + s += "<b>" + *it + "</b>"; + else + s += *it; + if ( i < (int)args.count() - 1 ) + s += ", "; + else + s += " "; + } + s += ")"; + s.prepend( pre ); + s.append( post ); + label += "<p>" + s + "</p>"; + functionLabel->setFunctionText( num, s ); + w = TQMAX( w, functionLabel->fontMetrics().width( s ) + 10 ); + } + w += 16; + if ( label.isEmpty() ) + return FALSE; + if ( functionLabel->isVisible() ) { + functionLabel->resize( w + 50, TQMAX( functionLabel->fontMetrics().height(), 16 ) ); + } else { + TQTextStringChar *chr = cursor->paragraph()->at( cursor->index() ); + int h = cursor->paragraph()->lineHeightOfChar( cursor->index() ); + int x = cursor->paragraph()->rect().x() + chr->x; + int y, dummy; + cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y ); + y += cursor->paragraph()->rect().y(); + functionLabel->resize( w + 50, TQMAX( functionLabel->fontMetrics().height(), 16 ) ); + functionLabel->move( curEditor->mapToGlobal( curEditor->contentsToViewport( TQPoint( x, y + h ) ) ) ); + if ( functionLabel->x() + functionLabel->width() > TQApplication::desktop()->width() ) + functionLabel->move( TQMAX( 0, TQApplication::desktop()->width() - functionLabel->width() ), + functionLabel->y() ); + functionLabel->show(); + curEditor->setFocus(); + } + TQTimer::singleShot( 0, functionLabel, SLOT( relayout() ) ); + + return TRUE; +} + +TQValueList<TQStringList> EditorCompletion::functionParameters( const TQString &, TQChar &, TQString &, TQString & ) +{ + return TQValueList<TQStringList>(); +} + +void EditorCompletion::setContext( TQObject * ) +{ +} + +void EditorCompletion::showCompletion( const TQValueList<CompletionEntry> &lst ) +{ + TQTextCursor *cursor = curEditor->textCursor(); + TQTextStringChar *chr = cursor->paragraph()->at( cursor->index() ); + int h = cursor->paragraph()->lineHeightOfChar( cursor->index() ); + int x = cursor->paragraph()->rect().x() + chr->x; + int y, dummy; + cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y ); + y += cursor->paragraph()->rect().y(); + completionListBox->clear(); + for ( TQValueList<CompletionEntry>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) + (void)new CompletionItem( completionListBox, (*it).text, (*it).type, + (*it).postfix, (*it).prefix, (*it).postfix2 ); + cList = lst; + completionPopup->resize( completionListBox->sizeHint() + + TQSize( completionListBox->verticalScrollBar()->width() + 4, + completionListBox->horizontalScrollBar()->height() + 4 ) ); + completionListBox->setCurrentItem( 0 ); + completionListBox->setFocus(); + if ( curEditor->mapToGlobal( TQPoint( 0, y ) ).y() + h + completionPopup->height() < TQApplication::desktop()->height() ) + completionPopup->move( curEditor->mapToGlobal( curEditor-> + contentsToViewport( TQPoint( x, y + h ) ) ) ); + else + completionPopup->move( curEditor->mapToGlobal( curEditor-> + contentsToViewport( TQPoint( x, y - completionPopup->height() ) ) ) ); + + completionPopup->show(); +} diff --git a/tools/designer/editor/completion.h b/tools/designer/editor/completion.h new file mode 100644 index 000000000..b53893436 --- /dev/null +++ b/tools/designer/editor/completion.h @@ -0,0 +1,110 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef COMPLETION_H +#define COMPLETION_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qobject.h> +#include <qmap.h> + +class TQTextDocument; +class Editor; +class TQVBox; +class TQListBox; +class ArgHintWidget; + +struct CompletionEntry +{ + TQString type; + TQString text; + TQString postfix; + TQString prefix; + TQString postfix2; + + bool operator==( const CompletionEntry &c ) const { + return ( c.type == type && + c.text == text && + c.postfix == postfix && + c.prefix == prefix && + c.postfix2 == postfix2 ); + } +}; + +class EditorCompletion : public TQObject +{ + Q_OBJECT + +public: + EditorCompletion( Editor *e ); + ~EditorCompletion(); + + virtual void addCompletionEntry( const TQString &s, TQTextDocument *doc, bool strict ); + virtual TQValueList<CompletionEntry> completionList( const TQString &s, TQTextDocument *doc ) const; + virtual void updateCompletionMap( TQTextDocument *doc ); + + bool eventFilter( TQObject *o, TQEvent *e ); + virtual void setCurrentEdior( Editor *e ); + virtual bool doCompletion(); + virtual bool doObjectCompletion(); + virtual bool doObjectCompletion( const TQString &object ); + virtual bool doArgumentHint( bool useIndex ); + + virtual void addEditor( Editor *e ); + virtual TQValueList<TQStringList> functionParameters( const TQString &func, TQChar &, TQString &prefix, TQString &postfix ); + + virtual void setContext( TQObject *this_ ); + + void setEnabled( bool b ) { enabled = b; } + +protected: + virtual bool continueComplete(); + virtual void showCompletion( const TQValueList<CompletionEntry> &lst ); + virtual void completeCompletion(); + +protected: + TQVBox *completionPopup; + TQListBox *completionListBox; + ArgHintWidget *functionLabel; + int completionOffset; + Editor *curEditor; + TQString searchString; + TQValueList<CompletionEntry> cList; + TQMap<TQChar, TQStringList> completionMap; + bool enabled; + TQTextDocument *lastDoc; + +}; + +#endif diff --git a/tools/designer/editor/conf.cpp b/tools/designer/editor/conf.cpp new file mode 100644 index 000000000..d654d334e --- /dev/null +++ b/tools/designer/editor/conf.cpp @@ -0,0 +1,269 @@ +/********************************************************************** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "conf.h" +#include <qapplication.h> +#include <qfont.h> +#include <qcolor.h> +#include <qsettings.h> + +TQMap<TQString, ConfigStyle> Config::defaultStyles() +{ + ConfigStyle s; + TQMap<TQString, ConfigStyle> styles; + int normalSize = qApp->font().pointSize(); + TQString normalFamily = qApp->font().family(); + TQString commentFamily = "times"; + int normalWeight = qApp->font().weight(); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::black; + styles.insert( "Standard", s ); + + s.font = TQFont( commentFamily, normalSize, normalWeight, TRUE ); + s.color = TQt::red; + styles.insert( "Comment", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::blue; + styles.insert( "Number", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::darkGreen; + styles.insert( "String", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::darkMagenta; + styles.insert( "Type", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::darkYellow; + styles.insert( "Keyword", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::darkBlue; + styles.insert( "Preprocessor", s ); + + s.font = TQFont( normalFamily, normalSize, normalWeight ); + s.color = TQt::darkRed; + styles.insert( "Label", s ); + + return styles; +} + +TQMap<TQString, ConfigStyle> Config::readStyles( const TQString &path ) +{ + TQMap<TQString, ConfigStyle> styles; + styles = defaultStyles(); + + TQString family; + int size = 10; + bool bold = FALSE, italic = FALSE, underline = FALSE; + int red = 0, green = 0, blue = 0; + + TQString elements[] = { + "Comment", + "Number", + "String", + "Type", + "Keyword", + "Preprocessor", + "Label", + "Standard", + TQString::null + }; + + for ( int i = 0; elements[ i ] != TQString::null; ++i ) { + TQSettings settings; + bool ok = TRUE; + for (;;) { + family = settings.readEntry( path + elements[ i ] + "/family", TQString::null, &ok ); + if ( !ok ) + break; + size = settings.readNumEntry( path + elements[ i ] + "/size", 10, &ok ); + if ( !ok ) + break; + bold = settings.readBoolEntry( path + elements[ i ] + "/bold", FALSE, &ok ); + if ( !ok ) + break; + italic = settings.readBoolEntry( path + elements[ i ] + "/italic", FALSE, &ok ); + if ( !ok ) + break; + underline = settings.readBoolEntry( path + elements[ i ] + "/underline", FALSE, &ok ); + if ( !ok ) + break; + red = settings.readNumEntry( path + elements[ i ] + "/red", 0, &ok ); + if ( !ok ) + break; + green = settings.readNumEntry( path + elements[ i ] + "/green", 0, &ok ); + if ( !ok ) + break; + blue = settings.readNumEntry( path + elements[ i ] + "/blue", 0, &ok ); + if ( !ok ) + break; + break; + } + if ( !ok ) + continue; + TQFont f( family ); + f.setPointSize( size ); + f.setBold( bold ); + f.setItalic( italic ); + f.setUnderline( underline ); + TQColor c( red, green, blue ); + ConfigStyle s; + s.font = f; + s.color = c; + styles.remove( elements[ i ] ); + styles.insert( elements[ i ], s ); + } + return styles; +} + +void Config::saveStyles( const TQMap<TQString, ConfigStyle> &styles, const TQString &path ) +{ + TQString elements[] = { + "Comment", + "Number", + "String", + "Type", + "Keyword", + "Preprocessor", + "Label", + "Standard", + TQString::null + }; + + TQSettings settings; + for ( int i = 0; elements[ i ] != TQString::null; ++i ) { + settings.writeEntry( path + "/" + elements[ i ] + "/family", styles[ elements[ i ] ].font.family() ); + settings.writeEntry( path + "/" + elements[ i ] + "/size", styles[ elements[ i ] ].font.pointSize() ); + settings.writeEntry( path + "/" + elements[ i ] + "/bold", styles[ elements[ i ] ].font.bold() ); + settings.writeEntry( path + "/" + elements[ i ] + "/italic", styles[ elements[ i ] ].font.italic() ); + settings.writeEntry( path + "/" + elements[ i ] + "/underline", styles[ elements[ i ] ].font.underline() ); + settings.writeEntry( path + "/" + elements[ i ] + "/red", styles[ elements[ i ] ].color.red() ); + settings.writeEntry( path + "/" + elements[ i ] + "/green", styles[ elements[ i ] ].color.green() ); + settings.writeEntry( path + "/" + elements[ i ] + "/blue", styles[ elements[ i ] ].color.blue() ); + } +} + +bool Config::completion( const TQString &path ) +{ + TQSettings settings; + bool ret = settings.readBoolEntry( path + "/completion", TRUE ); + return ret; +} + +bool Config::wordWrap( const TQString &path ) +{ + TQSettings settings; + bool ret = settings.readBoolEntry( path + "/wordWrap", TRUE ); + return ret; +} + +bool Config::parenMatching( const TQString &path ) +{ + TQSettings settings; + bool ret = settings.readBoolEntry( path + "/parenMatching", TRUE ); + return ret; +} + +int Config::indentTabSize( const TQString &path ) +{ + TQSettings settings; + int ret = settings.readNumEntry( path + "/indentTabSize", 8 ); + return ret; +} + +int Config::indentIndentSize( const TQString &path ) +{ + TQSettings settings; + int ret = settings.readNumEntry( path + "/indentIndentSize", 4 ); + return ret; +} + +bool Config::indentKeepTabs( const TQString &path ) +{ + TQSettings settings; + bool ret = settings.readBoolEntry( path + "/indentKeepTabs", TRUE ); + return ret; +} + +bool Config::indentAutoIndent( const TQString &path ) +{ + TQSettings settings; + bool ret = settings.readBoolEntry( path + "/indentAutoIndent", TRUE ); + return ret; +} + +void Config::setCompletion( bool b, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/completion", b ); +} + +void Config::setWordWrap( bool b, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/wordWrap", b ); +} + +void Config::setParenMatching( bool b,const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/parenMatching", b ); +} + +void Config::setIndentTabSize( int s, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/indentTabSize", s ); +} + +void Config::setIndentIndentSize( int s, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/indentIndentSize", s ); +} + +void Config::setIndentKeepTabs( bool b, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/indentKeepTabs", b ); +} + +void Config::setIndentAutoIndent( bool b, const TQString &path ) +{ + TQSettings settings; + settings.writeEntry( path + "/indentAutoIndent", b ); +} diff --git a/tools/designer/editor/conf.h b/tools/designer/editor/conf.h new file mode 100644 index 000000000..6d9a216f8 --- /dev/null +++ b/tools/designer/editor/conf.h @@ -0,0 +1,75 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef CONF_H +#define CONF_H + +#include <qfont.h> +#include <qcolor.h> +#include <qmap.h> + +struct ConfigStyle +{ + TQFont font; + TQColor color; + + Q_DUMMY_COMPARISON_OPERATOR( ConfigStyle ) +}; + +struct Config +{ + TQMap<TQString, ConfigStyle> styles; + bool hasCompletion, hasParenMatching, hasWordWrap; + + static TQMap<TQString, ConfigStyle> defaultStyles(); + static TQMap<TQString, ConfigStyle> readStyles( const TQString &path ); + static void saveStyles( const TQMap<TQString, ConfigStyle> &styles, const TQString &path ); + static bool completion( const TQString &path ); + static bool wordWrap( const TQString &path ); + static bool parenMatching( const TQString &path ); + static int indentTabSize( const TQString &path ); + static int indentIndentSize( const TQString &path ); + static bool indentKeepTabs( const TQString &path ); + static bool indentAutoIndent( const TQString &path ); + + static void setCompletion( bool b, const TQString &path ); + static void setWordWrap( bool b, const TQString &path ); + static void setParenMatching( bool b,const TQString &path ); + static void setIndentTabSize( int s, const TQString &path ); + static void setIndentIndentSize( int s, const TQString &path ); + static void setIndentKeepTabs( bool b, const TQString &path ); + static void setIndentAutoIndent( bool b, const TQString &path ); + +}; + +#endif diff --git a/tools/designer/editor/editor.cpp b/tools/designer/editor/editor.cpp new file mode 100644 index 000000000..9bea87da5 --- /dev/null +++ b/tools/designer/editor/editor.cpp @@ -0,0 +1,251 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "editor.h" +#include "parenmatcher.h" +#include <qfile.h> +#include <private/qrichtext_p.h> +#include "conf.h" +#include <qapplication.h> +#include <qpopupmenu.h> +#include <qaccel.h> + +Editor::Editor( const TQString &fn, TQWidget *parent, const char *name ) + : TQTextEdit( parent, name ), hasError( FALSE ) +{ + document()->setFormatter( new TQTextFormatterBreakInWords ); + if ( !fn.isEmpty() ) + load( fn ); + setHScrollBarMode( TQScrollView::AlwaysOff ); + setVScrollBarMode( TQScrollView::AlwaysOn ); + document()->setUseFormatCollection( FALSE ); + parenMatcher = new ParenMatcher; + connect( this, SIGNAL( cursorPositionChanged( TQTextCursor * ) ), + this, SLOT( cursorPosChanged( TQTextCursor * ) ) ); + cfg = new Config; + document()->addSelection( Error ); + document()->addSelection( Step ); + document()->setSelectionColor( Error, red ); + document()->setSelectionColor( Step, yellow ); + document()->setInvertSelectionText( Error, FALSE ); + document()->setInvertSelectionText( Step, FALSE ); + document()->addSelection( ParenMatcher::Match ); + document()->addSelection( ParenMatcher::Mismatch ); + document()->setSelectionColor( ParenMatcher::Match, TQColor( 204, 232, 195 ) ); + document()->setSelectionColor( ParenMatcher::Mismatch, TQt::magenta ); + document()->setInvertSelectionText( ParenMatcher::Match, FALSE ); + document()->setInvertSelectionText( ParenMatcher::Mismatch, FALSE ); + + accelComment = new TQAccel( this ); + accelComment->connectItem( accelComment->insertItem( ALT + Key_C ), + this, SLOT( commentSelection() ) ); + accelUncomment = new TQAccel( this ); + accelUncomment->connectItem( accelUncomment->insertItem( ALT + Key_U ), + this, SLOT( uncommentSelection() ) ); + editable = TRUE; +} + +Editor::~Editor() +{ + delete cfg; + delete parenMatcher; +} + +void Editor::cursorPosChanged( TQTextCursor *c ) +{ + if ( parenMatcher->match( c ) ) + repaintChanged(); + if ( hasError ) { + emit clearErrorMarker(); + hasError = FALSE; + } +} + +void Editor::load( const TQString &fn ) +{ + filename = fn; + TQFile f( filename ); + if ( !f.open( IO_ReadOnly ) ) + return; + TQCString txt; + txt.resize( f.size() ); + f.readBlock( txt.data(), f.size() ); + TQString s( TQString::fromLatin1( txt ) ); + setText( s ); +} + +void Editor::save( const TQString &fn ) +{ + if ( !filename.isEmpty() ) + filename = fn; +} + +void Editor::configChanged() +{ + document()->invalidate(); + viewport()->repaint( FALSE ); +} + +void Editor::setErrorSelection( int line ) +{ + TQTextParagraph *p = document()->paragAt( line ); + if ( !p ) + return; + TQTextCursor c( document() ); + c.setParagraph( p ); + c.setIndex( 0 ); + document()->removeSelection( Error ); + document()->setSelectionStart( Error, c ); + c.gotoLineEnd(); + document()->setSelectionEnd( Error, c ); + hasError = TRUE; + viewport()->repaint( FALSE ); +} + +void Editor::setStepSelection( int line ) +{ + TQTextParagraph *p = document()->paragAt( line ); + if ( !p ) + return; + TQTextCursor c( document() ); + c.setParagraph( p ); + c.setIndex( 0 ); + document()->removeSelection( Step ); + document()->setSelectionStart( Step, c ); + c.gotoLineEnd(); + document()->setSelectionEnd( Step, c ); + viewport()->repaint( FALSE ); +} + +void Editor::clearStepSelection() +{ + document()->removeSelection( Step ); + viewport()->repaint( FALSE ); +} + +void Editor::doChangeInterval() +{ + emit intervalChanged(); + TQTextEdit::doChangeInterval(); +} + +void Editor::commentSelection() +{ + TQTextParagraph *start = document()->selectionStartCursor( TQTextDocument::Standard ).paragraph(); + TQTextParagraph *end = document()->selectionEndCursor( TQTextDocument::Standard ).paragraph(); + if ( !start || !end ) + start = end = textCursor()->paragraph(); + while ( start ) { + if ( start == end && textCursor()->index() == 0 ) + break; + start->insert( 0, "//" ); + if ( start == end ) + break; + start = start->next(); + } + document()->removeSelection( TQTextDocument::Standard ); + repaintChanged(); + setModified( TRUE ); +} + +void Editor::uncommentSelection() +{ + TQTextParagraph *start = document()->selectionStartCursor( TQTextDocument::Standard ).paragraph(); + TQTextParagraph *end = document()->selectionEndCursor( TQTextDocument::Standard ).paragraph(); + if ( !start || !end ) + start = end = textCursor()->paragraph(); + while ( start ) { + if ( start == end && textCursor()->index() == 0 ) + break; + while ( start->at( 0 )->c == '/' ) + start->remove( 0, 1 ); + if ( start == end ) + break; + start = start->next(); + } + document()->removeSelection( TQTextDocument::Standard ); + repaintChanged(); + setModified( TRUE ); +} + +TQPopupMenu *Editor::createPopupMenu( const TQPoint &p ) +{ + TQPopupMenu *menu = TQTextEdit::createPopupMenu( p ); + menu->insertSeparator(); + menu->insertItem( tr( "C&omment Code\tAlt+C" ), this, SLOT( commentSelection() ) ); + menu->insertItem( tr( "Unco&mment Code\tAlt+U" ), this, SLOT( uncommentSelection() ) ); + return menu; +} + +bool Editor::eventFilter( TQObject *o, TQEvent *e ) +{ + if ( ( e->type() == TQEvent::FocusIn || e->type() == TQEvent::FocusOut ) && + ( o == this || o == viewport() ) ) { + accelUncomment->setEnabled( e->type() == TQEvent::FocusIn ); + accelComment->setEnabled( e->type() == TQEvent::FocusIn ); + } + return TQTextEdit::eventFilter( o, e ); +} + +void Editor::doKeyboardAction( KeyboardAction action ) +{ + if ( !editable ) + return; + TQTextEdit::doKeyboardAction( action ); +} + +void Editor::keyPressEvent( TQKeyEvent *e ) +{ + if ( editable ) { + TQTextEdit::keyPressEvent( e ); + return; + } + + switch ( e->key() ) { + case Key_Left: + case Key_Right: + case Key_Up: + case Key_Down: + case Key_Home: + case Key_End: + case Key_Prior: + case Key_Next: + case Key_Direction_L: + case Key_Direction_R: + TQTextEdit::keyPressEvent( e ); + break; + default: + e->accept(); + break; + } +} diff --git a/tools/designer/editor/editor.h b/tools/designer/editor/editor.h new file mode 100644 index 000000000..6037803cc --- /dev/null +++ b/tools/designer/editor/editor.h @@ -0,0 +1,111 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef EDITOR_H +#define EDITOR_H + +#include <qtextedit.h> + +struct Config; +class ParenMatcher; +class EditorCompletion; +class EditorBrowser; +class TQAccel; + +class Editor : public TQTextEdit +{ + Q_OBJECT + +public: + enum Selection { + Error = 3, + Step = 4 + }; + + Editor( const TQString &fn, TQWidget *parent, const char *name ); + ~Editor(); + virtual void load( const TQString &fn ); + virtual void save( const TQString &fn ); + TQTextDocument *document() const { return TQTextEdit::document(); } + void placeCursor( const TQPoint &p, TQTextCursor *c ) { TQTextEdit::placeCursor( p, c ); } + void setDocument( TQTextDocument *doc ) { TQTextEdit::setDocument( doc ); } + TQTextCursor *textCursor() const { return TQTextEdit::textCursor(); } + void repaintChanged() { TQTextEdit::repaintChanged(); } + + virtual EditorCompletion *completionManager() { return 0; } + virtual EditorBrowser *browserManager() { return 0; } + virtual void configChanged(); + + Config *config() { return cfg; } + + void setErrorSelection( int line ); + void setStepSelection( int line ); + void clearStepSelection(); + void clearSelections(); + + virtual bool supportsErrors() const { return TRUE; } + virtual bool supportsBreakPoints() const { return TRUE; } + virtual void makeFunctionVisible( TQTextParagraph * ) {} + + void drawCursor( bool b ) { TQTextEdit::drawCursor( b ); } + + TQPopupMenu *createPopupMenu( const TQPoint &p ); + bool eventFilter( TQObject *o, TQEvent *e ); + + void setEditable( bool b ) { editable = b; } + +protected: + void doKeyboardAction( KeyboardAction action ); + void keyPressEvent( TQKeyEvent *e ); + +signals: + void clearErrorMarker(); + void intervalChanged(); + +private slots: + void cursorPosChanged( TQTextCursor *c ); + void doChangeInterval(); + void commentSelection(); + void uncommentSelection(); + +protected: + ParenMatcher *parenMatcher; + TQString filename; + Config *cfg; + bool hasError; + TQAccel *accelComment, *accelUncomment; + bool editable; + +}; + +#endif diff --git a/tools/designer/editor/editor.pro b/tools/designer/editor/editor.pro new file mode 100644 index 000000000..dc9235f5e --- /dev/null +++ b/tools/designer/editor/editor.pro @@ -0,0 +1,40 @@ +TEMPLATE = lib +CONFIG += qt warn_on staticlib +CONFIG -= dll +HEADERS = editor.h \ + parenmatcher.h \ + completion.h \ + viewmanager.h \ + markerwidget.h\ + conf.h \ + browser.h \ + arghintwidget.h \ + cindent.h + +SOURCES = editor.cpp \ + parenmatcher.cpp \ + completion.cpp \ + viewmanager.cpp \ + markerwidget.cpp \ + conf.cpp \ + browser.cpp \ + arghintwidget.cpp \ + cindent.cpp \ + yyindent.cpp + +FORMS = preferences.ui + +TARGET = editor +DESTDIR = ../../../lib +VERSION = 1.0.0 + +INCLUDEPATH += $$QT_SOURCE_TREE/tools/designer/interfaces + +target.path=$$libs.path + +INSTALLS += target + +unix { + QMAKE_CFLAGS += $$QMAKE_CFLAGS_SHLIB + QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS_SHLIB +} diff --git a/tools/designer/editor/markerwidget.cpp b/tools/designer/editor/markerwidget.cpp new file mode 100644 index 000000000..da3daa42b --- /dev/null +++ b/tools/designer/editor/markerwidget.cpp @@ -0,0 +1,491 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "markerwidget.h" +#include "viewmanager.h" +#include <private/qrichtext_p.h> +#include "editor.h" +#include <qpainter.h> +#include <qpopupmenu.h> +#include "paragdata.h" + +static const char * error_xpm[] = { +"15 15 35 1", +" c None", +". c #FF0000", +"+ c #F50F0F", +"@ c #BF5F5F", +"# c #FF1010", +"$ c #FF7878", +"% c #FF0A0A", +"& c #FF0606", +"* c #FF1414", +"= c #FFFFFF", +"- c #FFA3A3", +"; c #FF0707", +"> c #FF0202", +", c #FF9898", +"' c #FF8888", +") c #D04747", +"! c #FFA7A7", +"~ c #FF9D9D", +"{ c #FFB1B1", +"] c #FF0C0C", +"^ c #F90A0A", +"/ c #FFB5B5", +"( c #FF0909", +"_ c #A08F8F", +": c #FFACAC", +"< c #FF0303", +"[ c #9F8F8F", +"} c #FB0606", +"| c #9F9090", +"1 c #CE4949", +"2 c #999999", +"3 c #FF1919", +"4 c #F70C0C", +"5 c #A38A8A", +"6 c #B37272", +" .... ", +" ........ ", +" .........+@ ", +" ..#$%..&$*.+ ", +" ..$=-;>,='..) ", +"...%-=!~={]..^ ", +"....;!==/(...._", +"....>~==:<....[", +"...&,=/:=!;..}|", +" ..$={(<!='..12", +" ..*']..;'3.45 ", +" +........462 ", +" @+......462 ", +" )^..}152 ", +" _[|2 "}; + +static const char * breakpoint_xpm[] = { +"15 15 3 1", +" c None", +". c #8B0000", +"+ c #FFFFFF", +" ....... ", +" ......... ", +" ........... ", +" ............. ", +"..+.+++.+..++..", +".+.+.+.+.+.+.+.", +".+...+.+.+.+.+.", +"..+..+.+.+.++..", +"...+.+.+.+.+...", +".+.+.+.+.+.+...", +"..+..+..+..+...", +" ............. ", +" ........... ", +" ......... ", +" ....... " }; + +static const char * step_xpm[] = { +"16 16 128 2", +" c None", +". c #B4B6BF", +"+ c #7893D8", +"@ c #8D95BF", +"# c #B8BFC1", +"$ c #B6D1E6", +"% c #7193E6", +"& c #8893C2", +"* c #B3BDC4", +"= c #AAD2EC", +"- c #9AD0FF", +"; c #6690EF", +"> c #8894C8", +", c #AFBAC4", +"' c #95BFEC", +") c #99CBFF", +"! c #8EC3FF", +"~ c #6D95F0", +"{ c #8792CA", +"] c #9DA7C3", +"^ c #8BA2E3", +"/ c #809AE0", +"( c #8398D1", +"_ c #93A0CC", +": c #ACB3CB", +"< c #B4B9C4", +"[ c #B6BAC4", +"} c #93A4CC", +"| c #82B0F5", +"1 c #8BBCFF", +"2 c #8EC0FF", +"3 c #8FC1FF", +"4 c #6594F4", +"5 c #7381CC", +"6 c #81A7E9", +"7 c #D0F5FF", +"8 c #C1EBFF", +"9 c #AEDAFF", +"0 c #A2D1FC", +"a c #A3C8F3", +"b c #AACAE6", +"c c #B4CFE9", +"d c #ADCCF9", +"e c #84B2FF", +"f c #82B4FF", +"g c #86B7FF", +"h c #88B7FF", +"i c #83B4FF", +"j c #5F8AF3", +"k c #7585C8", +"l c #77A4F3", +"m c #ABDFFF", +"n c #9CCAFF", +"o c #96C7FF", +"p c #97C8FF", +"q c #95C5FF", +"r c #9DCCFF", +"s c #A0CDFF", +"t c #90C0FF", +"u c #82AFFF", +"v c #7FAFFF", +"w c #7DAEFF", +"x c #79AAFF", +"y c #6C9EFF", +"z c #4366EB", +"A c #6894F2", +"B c #93C6FF", +"C c #82B3FF", +"D c #7AABFF", +"E c #73A5FF", +"F c #71A3FF", +"G c #6C9DFF", +"H c #699BFF", +"I c #76A8FF", +"J c #7EB0FF", +"K c #7BADFF", +"L c #74A5FF", +"M c #608BFF", +"N c #3462FF", +"O c #2444E5", +"P c #577AE0", +"Q c #5D90FF", +"R c #4C7AFF", +"S c #3B66FF", +"T c #335CF9", +"U c #365AF1", +"V c #3858E5", +"W c #3959E0", +"X c #416CF9", +"Y c #75A5FF", +"Z c #78A9FF", +"` c #74A4FF", +" . c #6191FF", +".. c #3059FF", +"+. c #1B37F1", +"@. c #6A75C7", +"#. c #828BC1", +"$. c #4358D8", +"%. c #374BDA", +"&. c #4759CA", +"*. c #636CC4", +"=. c #8489C0", +"-. c #9DA1C1", +";. c #A3A6BF", +">. c #7486CB", +",. c #6E98F5", +"'. c #719EFF", +"). c #608DFF", +"!. c #315EFF", +"~. c #1432F4", +"{. c #5C63C8", +"]. c #B1B4B9", +"^. c #B3BABB", +"/. c #ABB4C3", +"(. c #7299E9", +"_. c #5486FF", +":. c #224EFF", +"<. c #1733F2", +"[. c #7079C5", +"}. c #5C7DE9", +"|. c #2450FF", +"1. c #1B39EC", +"2. c #7077C5", +"3. c #3A54E1", +"4. c #1E36EA", +"5. c #858CBF", +"6. c #525FCB", +"7. c #727CBC", +" ", +" . + @ ", +" # $ % & ", +" * = - ; > ", +" , ' ) ! ~ { ", +"] ^ / ( _ : < [ } | 1 2 3 4 5 ", +"6 7 8 9 0 a b c d e f g h i j k ", +"l m n o p q r s t u v u w x y z ", +"A B C D E F G H I J K D L M N O ", +"P Q R S T U V W X Y Z ` ...+.@.", +"#.$.%.&.*.=.-.;.>.,.'.).!.~.{. ", +" ].^. /.(._.:.<.[. ", +" }.|.1.2. ", +" 3.4.5. ", +" 6.7. ", +" "}; + +static const char *stack_frame_xpm[]={ +"16 16 2 1", +". c None", +"# c #00c000", +"................", +".###............", +".#####..........", +".#######........", +".#########......", +".###########....", +".#############..", +".##############.", +".##############.", +".#############..", +".###########....", +".#########......", +".#######........", +".#####..........", +".###............", +"................"}; + +static TQPixmap *errorPixmap = 0; +static TQPixmap *breakpointPixmap = 0; +static TQPixmap *stepPixmap = 0; +static TQPixmap *stackFrame = 0; + +MarkerWidget::MarkerWidget( ViewManager *parent, const char*name ) + : TQWidget( parent, name, WRepaintNoErase | WStaticContents | WResizeNoErase ), viewManager( parent ) +{ + if ( !errorPixmap ) { + errorPixmap = new TQPixmap( error_xpm ); + breakpointPixmap = new TQPixmap( breakpoint_xpm ); + stepPixmap = new TQPixmap( step_xpm ); + stackFrame = new TQPixmap( stack_frame_xpm ); + } +} + +void MarkerWidget::paintEvent( TQPaintEvent * ) +{ + buffer.fill( backgroundColor() ); + + TQTextParagraph *p = ( (Editor*)viewManager->currentView() )->document()->firstParagraph(); + TQPainter painter( &buffer ); + int yOffset = ( (Editor*)viewManager->currentView() )->contentsY(); + while ( p ) { + if ( !p->isVisible() ) { + p = p->next(); + continue; + } + if ( p->rect().y() + p->rect().height() - yOffset < 0 ) { + p = p->next(); + continue; + } + if ( p->rect().y() - yOffset > height() ) + break; + if ( !((p->paragId() + 1) % 10) ) { + painter.save(); + painter.setPen( colorGroup().dark() ); + painter.drawText( 0, p->rect().y() - yOffset, width() - 20, p->rect().height(), + TQt::AlignRight | TQt::AlignTop, TQString::number( p->paragId() + 1 ) ); + painter.restore(); + } + ParagData *paragData = (ParagData*)p->extraData(); + if ( paragData ) { + switch ( paragData->marker ) { + case ParagData::Error: + painter.drawPixmap( 3, p->rect().y() + + ( p->rect().height() - errorPixmap->height() ) / 2 - + yOffset, *errorPixmap ); + break; + case ParagData::Breakpoint: + painter.drawPixmap( 3, p->rect().y() + + ( p->rect().height() - breakpointPixmap->height() ) / 2 - + yOffset, *breakpointPixmap ); + break; + default: + break; + } + switch ( paragData->lineState ) { + case ParagData::FunctionStart: + painter.setPen( colorGroup().foreground() ); + painter.setBrush( colorGroup().base() ); + painter.drawLine( width() - 11, p->rect().y() - yOffset, + width() - 11, p->rect().y() + p->rect().height() - yOffset ); + painter.drawRect( width() - 15, p->rect().y() + ( p->rect().height() - 9 ) / 2 - yOffset, 9, 9 ); + painter.drawLine( width() - 13, p->rect().y() + ( p->rect().height() - 9 ) / 2 - yOffset + 4, + width() - 9, p->rect().y() + + ( p->rect().height() - 9 ) / 2 - yOffset + 4 ); + if ( !paragData->functionOpen ) + painter.drawLine( width() - 11, + p->rect().y() + ( p->rect().height() - 9 ) / 2 - yOffset + 2, + width() - 11, + p->rect().y() + + ( p->rect().height() - 9 ) / 2 - yOffset + 6 ); + break; + case ParagData::InFunction: + painter.setPen( colorGroup().foreground() ); + painter.drawLine( width() - 11, p->rect().y() - yOffset, + width() - 11, p->rect().y() + p->rect().height() - yOffset ); + break; + case ParagData::FunctionEnd: + painter.setPen( colorGroup().foreground() ); + painter.drawLine( width() - 11, p->rect().y() - yOffset, + width() - 11, p->rect().y() + p->rect().height() - yOffset ); + painter.drawLine( width() - 11, p->rect().y() + p->rect().height() - yOffset, + width() - 7, p->rect().y() + p->rect().height() - yOffset ); + break; + default: + break; + } + if ( paragData->step ) + painter.drawPixmap( 3, p->rect().y() + + ( p->rect().height() - stepPixmap->height() ) / 2 - + yOffset, *stepPixmap ); + if ( paragData->stackFrame ) + painter.drawPixmap( 3, p->rect().y() + + ( p->rect().height() - stackFrame->height() ) / 2 - + yOffset, *stackFrame ); + } + p = p->next(); + } + painter.end(); + + bitBlt( this, 0, 0, &buffer ); +} + +void MarkerWidget::resizeEvent( TQResizeEvent *e ) +{ + buffer.resize( e->size() ); + TQWidget::resizeEvent( e ); +} + +void MarkerWidget::mousePressEvent( TQMouseEvent *e ) +{ + if ( e->button() != LeftButton ) + return; + bool supports = ( (Editor*)viewManager->currentView() )->supportsBreakPoints(); + TQTextParagraph *p = ( (Editor*)viewManager->currentView() )->document()->firstParagraph(); + int yOffset = ( (Editor*)viewManager->currentView() )->contentsY(); + while ( p ) { + if ( e->y() >= p->rect().y() - yOffset && e->y() <= p->rect().y() + p->rect().height() - yOffset ) { + TQTextParagraphData *d = p->extraData(); + if ( !d ) + return; + ParagData *data = (ParagData*)d; + if ( supports && ( e->x() < width() - 15 ) ) { + if ( data->marker == ParagData::Breakpoint ) { + data->marker = ParagData::NoMarker; + } else { + bool ok = TRUE; + isBreakpointPossible( ok, ( (Editor*)viewManager->currentView() )->text(), p->paragId() ); + if ( ok ) + data->marker = ParagData::Breakpoint; + else + emit showMessage( tr( "<font color=red>Can't set breakpoint here!</font>" ) ); + } + } else { + if ( data->lineState == ParagData::FunctionStart ) { + if ( data->functionOpen ) + emit collapseFunction( p ); + else + emit expandFunction( p ); + } + } + break; + } + p = p->next(); + } + doRepaint(); + emit markersChanged(); +} + +void MarkerWidget::contextMenuEvent( TQContextMenuEvent *e ) +{ + TQPopupMenu m( 0, "editor_breakpointsmenu" ); + + int toggleBreakPoint = 0; +// int editBreakpoints = 0; + + TQTextParagraph *p = ( (Editor*)viewManager->currentView() )->document()->firstParagraph(); + int yOffset = ( (Editor*)viewManager->currentView() )->contentsY(); + bool supports = ( (Editor*)viewManager->currentView() )->supportsBreakPoints(); + while ( p && supports ) { + if ( e->y() >= p->rect().y() - yOffset && e->y() <= p->rect().y() + p->rect().height() - yOffset ) { + if ( ( (ParagData*)p->extraData() )->marker == ParagData::Breakpoint ) + toggleBreakPoint = m.insertItem( tr( "Clear Breakpoint\tF9" ) ); + else + toggleBreakPoint = m.insertItem( tr( "Set Breakpoint\tF9" ) ); +// editBreakpoints = m.insertItem( tr( "Edit Breakpoints..." ) ); + m.insertSeparator(); + break; + } + p = p->next(); + } + + const int collapseAll = m.insertItem( tr( "Collapse All" ) ); + const int expandAll = m.insertItem( tr( "Expand All" ) ); + const int collapseFunctions = m.insertItem( tr( "Collapse all Functions" ) ); + const int expandFunctions = m.insertItem( tr( "Expand all Functions" ) ); + + int res = m.exec( e->globalPos() ); + if ( res == -1) + return; + + if ( res == collapseAll ) { + emit collapse( TRUE ); + } else if ( res == collapseFunctions ) { + emit collapse( FALSE ); + } else if ( res == expandAll ) { + emit expand( TRUE ); + } else if ( res == expandFunctions ) { + emit expand( FALSE ); + } else if ( res == toggleBreakPoint ) { + if ( ( (ParagData*)p->extraData() )->marker == ParagData::Breakpoint ) { + ( (ParagData*)p->extraData() )->marker = ParagData::NoMarker; + } else { + bool ok; + isBreakpointPossible( ok, ( (Editor*)viewManager->currentView() )->text(), p->paragId() ); + if ( ok ) + ( (ParagData*)p->extraData() )->marker = ParagData::Breakpoint; + else + emit showMessage( tr( "<font color=red>Can't set breakpoint here!</font>" ) ); + } +// } else if ( res == editBreakpoints ) { +// emit editBreakPoints(); + } + doRepaint(); + emit markersChanged(); +} diff --git a/tools/designer/editor/markerwidget.h b/tools/designer/editor/markerwidget.h new file mode 100644 index 000000000..2c94ff813 --- /dev/null +++ b/tools/designer/editor/markerwidget.h @@ -0,0 +1,75 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef MARKERWIDGET_H +#define MARKERWIDGET_H + +#include <qwidget.h> +#include <qpixmap.h> + +class ViewManager; +class TQTextParagraph; + +class MarkerWidget : public TQWidget +{ + Q_OBJECT + +public: + MarkerWidget( ViewManager *parent, const char*name ); + +signals: + void markersChanged(); + void expandFunction( TQTextParagraph *p ); + void collapseFunction( TQTextParagraph *p ); + void collapse( bool all /*else only functions*/ ); + void expand( bool all /*else only functions*/ ); + void editBreakPoints(); + void isBreakpointPossible( bool &possible, const TQString &code, int line ); + void showMessage( const TQString &msg ); + +public slots: + void doRepaint() { repaint( FALSE ); } + +protected: + void paintEvent( TQPaintEvent *e ); + void resizeEvent( TQResizeEvent *e ); + void mousePressEvent( TQMouseEvent *e ); + void contextMenuEvent( TQContextMenuEvent *e ); + +private: + TQPixmap buffer; + ViewManager *viewManager; + +}; + +#endif diff --git a/tools/designer/editor/paragdata.h b/tools/designer/editor/paragdata.h new file mode 100644 index 000000000..90dabd3ce --- /dev/null +++ b/tools/designer/editor/paragdata.h @@ -0,0 +1,65 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef PARAGDATA_H +#define PARAGDATA_H + +#include "parenmatcher.h" +#include <private/qrichtext_p.h> + +struct ParagData : public TQTextParagraphData +{ +public: + enum MarkerType { NoMarker, Error, Breakpoint }; + enum LineState { FunctionStart, InFunction, FunctionEnd, Invalid }; + + ParagData() : lastLengthForCompletion( -1 ), marker( NoMarker ), + lineState( Invalid ), functionOpen( TRUE ), step( FALSE ), stackFrame( FALSE ) {} + ~ParagData() {} + void join( TQTextParagraphData *data ) { + ParagData *d = (ParagData*)data; + if ( marker == NoMarker ) + marker = d->marker; + lineState = d->lineState; + } + ParenList parenList; + int lastLengthForCompletion; + MarkerType marker; + LineState lineState; + bool functionOpen; + bool step; + bool stackFrame; + +}; + +#endif diff --git a/tools/designer/editor/parenmatcher.cpp b/tools/designer/editor/parenmatcher.cpp new file mode 100644 index 000000000..5b16658db --- /dev/null +++ b/tools/designer/editor/parenmatcher.cpp @@ -0,0 +1,215 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "parenmatcher.h" +#include "paragdata.h" + +#include "qtextedit.h" +#include <private/qrichtext_p.h> +#include <qapplication.h> + +ParenMatcher::ParenMatcher() +{ + enabled = TRUE; +} + +bool ParenMatcher::match( TQTextCursor *cursor ) +{ + if ( !enabled ) + return FALSE; + bool ret = FALSE; + + TQChar c( cursor->paragraph()->at( cursor->index() )->c ); + bool ok1 = FALSE; + bool ok2 = FALSE; + if ( c == '{' || c == '(' || c == '[' ) { + ok1 = checkOpenParen( cursor ); + ret = ok1 || ret; + } else if ( cursor->index() > 0 ) { + c = cursor->paragraph()->at( cursor->index() - 1 )->c; + if ( c == '}' || c == ')' || c == ']' ) { + ok2 = checkClosedParen( cursor ); + ret = ok2 || ret; + } + } + + return ret; +} + +bool ParenMatcher::checkOpenParen( TQTextCursor *cursor ) +{ + if ( !cursor->paragraph()->extraData() ) + return FALSE; + ParenList parenList = ( (ParagData*)cursor->paragraph()->extraData() )->parenList; + + Paren openParen, closedParen; + TQTextParagraph *closedParenParag = cursor->paragraph(); + + int i = 0; + int ignore = 0; + bool foundOpen = FALSE; + TQChar c = cursor->paragraph()->at( cursor->index() )->c; + for (;;) { + if ( !foundOpen ) { + if ( i >= (int)parenList.count() ) + goto bye; + openParen = parenList[ i ]; + if ( openParen.pos != cursor->index() ) { + ++i; + continue; + } else { + foundOpen = TRUE; + ++i; + } + } + + if ( i >= (int)parenList.count() ) { + for (;;) { + closedParenParag = closedParenParag->next(); + if ( !closedParenParag ) + goto bye; + if ( closedParenParag->extraData() && + ( (ParagData*)closedParenParag->extraData() )->parenList.count() > 0 ) { + parenList = ( (ParagData*)closedParenParag->extraData() )->parenList; + break; + } + } + i = 0; + } + + closedParen = parenList[ i ]; + if ( closedParen.type == Paren::Open ) { + ignore++; + ++i; + continue; + } else { + if ( ignore > 0 ) { + ignore--; + ++i; + continue; + } + + int id = Match; + if ( c == '{' && closedParen.chr != '}' || + c == '(' && closedParen.chr != ')' || + c == '[' && closedParen.chr != ']' ) + id = Mismatch; + cursor->document()->setSelectionStart( id, *cursor ); + int tidx = cursor->index(); + TQTextParagraph *tstring = cursor->paragraph(); + cursor->setParagraph( closedParenParag ); + cursor->setIndex( closedParen.pos + 1 ); + cursor->document()->setSelectionEnd( id, *cursor ); + cursor->setParagraph( tstring ); + cursor->setIndex( tidx ); + return TRUE; + } + } + + bye: + return FALSE; +} + +bool ParenMatcher::checkClosedParen( TQTextCursor *cursor ) +{ + if ( !cursor->paragraph()->extraData() ) + return FALSE; + ParenList parenList = ( (ParagData*)cursor->paragraph()->extraData() )->parenList; + + Paren openParen, closedParen; + TQTextParagraph *openParenParag = cursor->paragraph(); + + int i = (int)parenList.count() - 1; + int ignore = 0; + bool foundClosed = FALSE; + TQChar c = cursor->paragraph()->at( cursor->index() - 1 )->c; + for (;;) { + if ( !foundClosed ) { + if ( i < 0 ) + goto bye; + closedParen = parenList[ i ]; + if ( closedParen.pos != cursor->index() - 1 ) { + --i; + continue; + } else { + foundClosed = TRUE; + --i; + } + } + + if ( i < 0 ) { + for (;;) { + openParenParag = openParenParag->prev(); + if ( !openParenParag ) + goto bye; + if ( openParenParag->extraData() && + ( (ParagData*)openParenParag->extraData() )->parenList.count() > 0 ) { + parenList = ( (ParagData*)openParenParag->extraData() )->parenList; + break; + } + } + i = (int)parenList.count() - 1; + } + + openParen = parenList[ i ]; + if ( openParen.type == Paren::Closed ) { + ignore++; + --i; + continue; + } else { + if ( ignore > 0 ) { + ignore--; + --i; + continue; + } + + int id = Match; + if ( c == '}' && openParen.chr != '{' || + c == ')' && openParen.chr != '(' || + c == ']' && openParen.chr != '[' ) + id = Mismatch; + cursor->document()->setSelectionStart( id, *cursor ); + int tidx = cursor->index(); + TQTextParagraph *tstring = cursor->paragraph(); + cursor->setParagraph( openParenParag ); + cursor->setIndex( openParen.pos ); + cursor->document()->setSelectionEnd( id, *cursor ); + cursor->setParagraph( tstring ); + cursor->setIndex( tidx ); + return TRUE; + } + } + + bye: + return FALSE; +} diff --git a/tools/designer/editor/parenmatcher.h b/tools/designer/editor/parenmatcher.h new file mode 100644 index 000000000..db5aff86f --- /dev/null +++ b/tools/designer/editor/parenmatcher.h @@ -0,0 +1,78 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef PARENMATCHER_H +#define PARENMATCHER_H + +#include <qstring.h> +#include <qvaluelist.h> + +class TQTextCursor; + +struct Paren +{ + Paren() : type( Open ), chr( ' ' ), pos( -1 ) {} + Paren( int t, const TQChar &c, int p ) : type( (Type)t ), chr( c ), pos( p ) {} + enum Type { Open, Closed }; + Type type; + TQChar chr; + int pos; + + Q_DUMMY_COMPARISON_OPERATOR( Paren ) +}; + +typedef TQValueList<Paren> ParenList; + +class ParenMatcher +{ +public: + enum Selection { + Match = 1, + Mismatch + }; + + ParenMatcher(); + + virtual bool match( TQTextCursor *c ); + + void setEnabled( bool b ) { enabled = b; } + +private: + bool checkOpenParen( TQTextCursor *c ); + bool checkClosedParen( TQTextCursor *c ); + + bool enabled; + +}; + +#endif diff --git a/tools/designer/editor/preferences.ui b/tools/designer/editor/preferences.ui new file mode 100644 index 000000000..dbba3d155 --- /dev/null +++ b/tools/designer/editor/preferences.ui @@ -0,0 +1,510 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>PreferencesBase</class> +<comment>********************************************************************* +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +*********************************************************************</comment> +<widget class="TQWidget"> + <property name="name"> + <cstring>PreferencesBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>362</width> + <height>396</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>6</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQGroupBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>GroupBox2</cstring> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>S&yntax Highlighting</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>&Element:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>listElements</cstring> + </property> + </widget> + <widget class="TQLayoutWidget" row="1" column="1" rowspan="3" colspan="1"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkBold</cstring> + </property> + <property name="text"> + <string>&Bold</string> + </property> + </widget> + <widget class="TQToolButton" row="5" column="1"> + <property name="name"> + <cstring>buttonColor</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="TQComboBox" row="0" column="1"> + <property name="name"> + <cstring>comboFamily</cstring> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>&Family:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>comboFamily</cstring> + </property> + </widget> + <widget class="TQCheckBox" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkUnderline</cstring> + </property> + <property name="text"> + <string>&Underline</string> + </property> + </widget> + <widget class="TQSpinBox" row="1" column="1"> + <property name="name"> + <cstring>spinSize</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + </widget> + <widget class="TQCheckBox" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkItalic</cstring> + </property> + <property name="text"> + <string>&Italic</string> + </property> + </widget> + <widget class="TQLabel" row="5" column="0"> + <property name="name"> + <cstring>TextLabel4</cstring> + </property> + <property name="text"> + <string>Change co&lor:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>buttonColor</cstring> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel3</cstring> + </property> + <property name="text"> + <string>&Size:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>spinSize</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="TQListBox" row="1" column="0"> + <item> + <property name="text"> + <string>Comment</string> + </property> + </item> + <item> + <property name="text"> + <string>Number</string> + </property> + </item> + <item> + <property name="text"> + <string>String</string> + </property> + </item> + <item> + <property name="text"> + <string>Type</string> + </property> + </item> + <item> + <property name="text"> + <string>Keyword</string> + </property> + </item> + <item> + <property name="text"> + <string>Preprocessor</string> + </property> + </item> + <item> + <property name="text"> + <string>Label</string> + </property> + </item> + <item> + <property name="text"> + <string>Standard</string> + </property> + </item> + <property name="name"> + <cstring>listElements</cstring> + </property> + </widget> + <widget class="TQLabel" row="2" column="0"> + <property name="name"> + <cstring>TextLabel2_2</cstring> + </property> + <property name="text"> + <string>&Preview:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>editPreview</cstring> + </property> + </widget> + <widget class="TQLineEdit" row="3" column="0"> + <property name="name"> + <cstring>editPreview</cstring> + </property> + <property name="text"> + <string>Some Text</string> + </property> + </widget> + <spacer row="4" column="1"> + <property name="name"> + <cstring>Spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="TQGroupBox" row="1" column="0"> + <property name="name"> + <cstring>GroupBox3</cstring> + </property> + <property name="title"> + <string>Optio&ns</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>checkWordWrap</cstring> + </property> + <property name="text"> + <string>&Word Wrap</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>checkCompletion</cstring> + </property> + <property name="text"> + <string>Comple&tion</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>checkParenMatching</cstring> + </property> + <property name="text"> + <string>Parentheses &Matching</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQGroupBox" row="1" column="1"> + <property name="name"> + <cstring>GroupBox3_2</cstring> + </property> + <property name="title"> + <string>Indentation</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>Layout2</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQSpinBox" row="0" column="1"> + <property name="name"> + <cstring>spinTabSize</cstring> + </property> + <property name="value"> + <number>8</number> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1_2</cstring> + </property> + <property name="text"> + <string>Tab Size:</string> + </property> + </widget> + <widget class="TQSpinBox" row="1" column="1"> + <property name="name"> + <cstring>spinIndentSize</cstring> + </property> + <property name="value"> + <number>4</number> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel2_3</cstring> + </property> + <property name="text"> + <string>Indent Size:</string> + </property> + </widget> + </grid> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>checkKeepTabs</cstring> + </property> + <property name="text"> + <string>Keep Tabs</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>checkAutoIndent</cstring> + </property> + <property name="text"> + <string>Auto Indent</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>spinSize</sender> + <signal>valueChanged(int)</signal> + <receiver>PreferencesBase</receiver> + <slot>sizeChanged(int)</slot> + </connection> + <connection> + <sender>checkBold</sender> + <signal>toggled(bool)</signal> + <receiver>PreferencesBase</receiver> + <slot>boldChanged(bool)</slot> + </connection> + <connection> + <sender>checkItalic</sender> + <signal>toggled(bool)</signal> + <receiver>PreferencesBase</receiver> + <slot>italicChanged(bool)</slot> + </connection> + <connection> + <sender>checkUnderline</sender> + <signal>toggled(bool)</signal> + <receiver>PreferencesBase</receiver> + <slot>underlineChanged(bool)</slot> + </connection> + <connection> + <sender>buttonColor</sender> + <signal>clicked()</signal> + <receiver>PreferencesBase</receiver> + <slot>colorClicked()</slot> + </connection> + <connection> + <sender>comboFamily</sender> + <signal>activated(const TQString&)</signal> + <receiver>PreferencesBase</receiver> + <slot>familyChanged(const TQString&)</slot> + </connection> + <connection> + <sender>listElements</sender> + <signal>highlighted(const TQString&)</signal> + <receiver>PreferencesBase</receiver> + <slot>elementChanged(const TQString&)</slot> + </connection> +</connections> +<tabstops> + <tabstop>listElements</tabstop> + <tabstop>editPreview</tabstop> + <tabstop>comboFamily</tabstop> + <tabstop>spinSize</tabstop> + <tabstop>checkBold</tabstop> + <tabstop>checkItalic</tabstop> + <tabstop>checkUnderline</tabstop> + <tabstop>checkWordWrap</tabstop> + <tabstop>checkCompletion</tabstop> + <tabstop>checkParenMatching</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">qmap.h</include> + <include location="local" impldecl="in declaration">conf.h</include> + <include location="global" impldecl="in implementation">qpalette.h</include> + <include location="global" impldecl="in implementation">qlineedit.h</include> + <include location="global" impldecl="in implementation">qpixmap.h</include> + <include location="global" impldecl="in implementation">qcombobox.h</include> + <include location="global" impldecl="in implementation">qfontdatabase.h</include> + <include location="local" impldecl="in implementation">editor.h</include> + <include location="global" impldecl="in implementation">qpushbutton.h</include> + <include location="global" impldecl="in implementation">qcheckbox.h</include> + <include location="global" impldecl="in implementation">qcolordialog.h</include> + <include location="global" impldecl="in implementation">qsettings.h</include> + <include location="local" impldecl="in implementation">preferences.ui.h</include> +</includes> +<variables> + <variable>TQString path;</variable> + <variable>TQMap<TQString, ConfigStyle> styles;</variable> + <variable>ConfigStyle currentStyle;</variable> + <variable>TQString currentElement;</variable> +</variables> +<slots> + <slot>init()</slot> + <slot>destroy()</slot> + <slot>colorClicked()</slot> + <slot>reInit()</slot> + <slot>save()</slot> + <slot>updatePreview()</slot> + <slot>boldChanged( bool b )</slot> + <slot>elementChanged( const TQString & element )</slot> + <slot>familyChanged( const TQString & f )</slot> + <slot>italicChanged( bool b )</slot> + <slot>setColorPixmap( const TQColor & c )</slot> + <slot>setPath( const TQString & p )</slot> + <slot>sizeChanged( int s )</slot> + <slot>underlineChanged( bool b )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/tools/designer/editor/preferences.ui.h b/tools/designer/editor/preferences.ui.h new file mode 100644 index 000000000..7f2426dc9 --- /dev/null +++ b/tools/designer/editor/preferences.ui.h @@ -0,0 +1,181 @@ +/********************************************************************** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +void PreferencesBase::init() +{ + TQFontDatabase fdb; + comboFamily->insertStringList( fdb.families() ); + listElements->setCurrentItem( listElements->firstItem() ); + currentElement = ""; +} + +void PreferencesBase::destroy() +{ + +} + +void PreferencesBase::colorClicked() +{ + TQColor c = TQColorDialog::getColor( currentStyle.color, this, "editor_getcolor_dlg" ); + if ( c.isValid() ) { + currentStyle.color = c; + setColorPixmap( c ); + } +} + +void PreferencesBase::reInit() +{ + styles = Config::readStyles( path ); + currentElement = ""; + elementChanged( "Comment" ); + for ( int i = 0; i < comboFamily->count(); ++i ) { + if ( listElements->text( i ) == "Comment" ) { + listElements->setCurrentItem( i ); + break; + } + } + checkWordWrap->setChecked( Config::wordWrap( path ) ); + checkCompletion->setChecked( Config::completion( path ) ); + checkParenMatching->setChecked( Config::parenMatching( path ) ); + spinTabSize->setValue( Config::indentTabSize( path ) ); + spinIndentSize->setValue( Config::indentIndentSize( path ) ); + checkKeepTabs->setChecked( Config::indentKeepTabs( path ) ); + checkAutoIndent->setChecked( Config::indentAutoIndent( path ) ); +} + +void PreferencesBase::save() +{ + if ( !currentElement.isEmpty() ) { + styles.remove( currentElement ); + styles.insert( currentElement, currentStyle ); + currentElement = ""; + } + + TQSettings settings; + Config::saveStyles( styles, path ); + Config::setWordWrap( checkWordWrap->isChecked(), path ); + Config::setCompletion( checkCompletion->isChecked(), path ); + Config::setParenMatching( checkParenMatching->isChecked(), path ); + Config::setIndentTabSize( spinTabSize->value(), path ); + Config::setIndentIndentSize( spinIndentSize->value(), path ); + Config::setIndentKeepTabs( checkKeepTabs->isChecked(), path ); + Config::setIndentAutoIndent( checkAutoIndent->isChecked(), path ); +} + +void PreferencesBase::updatePreview() +{ + editPreview->setFont( currentStyle.font ); + TQPalette pal = editPreview->palette(); + pal.setColor( TQPalette::Active, TQColorGroup::Text, currentStyle.color ); + pal.setColor( TQPalette::Active, TQColorGroup::Foreground, currentStyle.color ); + editPreview->setPalette( pal ); +} + +void PreferencesBase::boldChanged( bool b ) +{ + currentStyle.font.setBold( b ); + updatePreview(); +} + +void PreferencesBase::elementChanged( const TQString &element ) +{ + if ( !currentElement.isEmpty() ) { + styles.remove( currentElement ); + styles.insert( currentElement, currentStyle ); + currentElement = ""; + } + TQMap<TQString, ConfigStyle>::Iterator it = styles.find( element ); + if ( it == styles.end() ) + return; + ConfigStyle s = *it; + currentStyle = s; + comboFamily->lineEdit()->setText( s.font.family() ); + spinSize->setValue( s.font.pointSize() ); + checkBold->setChecked( s.font.bold() ); + checkItalic->setChecked( s.font.italic() ); + checkUnderline->setChecked( s.font.underline() ); + setColorPixmap( s.color ); + currentElement = element; + updatePreview(); +} + +void PreferencesBase::familyChanged( const TQString &f ) +{ + TQString oldFamily = currentStyle.font.family(); + currentStyle.font.setFamily( f ); + if ( currentElement == "Standard" ) { + for ( TQMap<TQString, ConfigStyle>::Iterator it = styles.begin(); it != styles.end(); ++it ) { + if ( (*it).font.family() == oldFamily ) + (*it).font.setFamily( f ); + } + } + updatePreview(); +} + +void PreferencesBase::italicChanged( bool b ) +{ + currentStyle.font.setItalic( b ); + updatePreview(); +} + +void PreferencesBase::setColorPixmap( const TQColor &c ) +{ + TQPixmap pm( 20, 20 ); + pm.fill( c ); + buttonColor->setPixmap( pm ); + updatePreview(); +} + +void PreferencesBase::setPath( const TQString &p ) +{ + path = p; +} + +void PreferencesBase::sizeChanged( int s ) +{ + int oldSize = currentStyle.font.pointSize(); + currentStyle.font.setPointSize( s ); + if ( currentElement == "Standard" ) { + for ( TQMap<TQString, ConfigStyle>::Iterator it = styles.begin(); it != styles.end(); ++it ) { + if ( (*it).font.pointSize() == oldSize ) + (*it).font.setPointSize( s ); + } + } + updatePreview(); +} + +void PreferencesBase::underlineChanged( bool b ) +{ + currentStyle.font.setUnderline( b ); + updatePreview(); +} diff --git a/tools/designer/editor/viewmanager.cpp b/tools/designer/editor/viewmanager.cpp new file mode 100644 index 000000000..0e1028665 --- /dev/null +++ b/tools/designer/editor/viewmanager.cpp @@ -0,0 +1,276 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "viewmanager.h" +#include "editor.h" +#include "markerwidget.h" +#include <qlayout.h> +#include <private/qrichtext_p.h> +#include "paragdata.h" +#include <qobjectlist.h> +#include <qlabel.h> +#include <qtimer.h> + +ViewManager::ViewManager( TQWidget *parent, const char *name ) + : TQWidget( parent, name ), curView( 0 ) +{ + TQHBoxLayout *l = new TQHBoxLayout( this ); + markerWidget = new MarkerWidget( this, "editor_markerwidget" ); + connect( markerWidget, SIGNAL( markersChanged() ), + this, SIGNAL( markersChanged() ) ); + connect( markerWidget, SIGNAL( collapseFunction( TQTextParagraph * ) ), + this, SIGNAL( collapseFunction( TQTextParagraph * ) ) ); + connect( markerWidget, SIGNAL( expandFunction( TQTextParagraph * ) ), + this, SIGNAL( expandFunction( TQTextParagraph * ) ) ); + connect( markerWidget, SIGNAL( collapse( bool ) ), + this, SIGNAL( collapse( bool ) ) ); + connect( markerWidget, SIGNAL( expand( bool ) ), + this, SIGNAL( expand( bool ) ) ); + connect( markerWidget, SIGNAL( editBreakPoints() ), + this, SIGNAL( editBreakPoints() ) ); + connect( markerWidget, SIGNAL( isBreakpointPossible( bool&, const TQString &, int ) ), + this, SIGNAL( isBreakpointPossible( bool&, const TQString &, int ) ) ); + connect( markerWidget, SIGNAL( showMessage( const TQString & ) ), + this, SLOT( showMessage( const TQString & ) ) ); + messageTimer = new TQTimer( this ); + connect( messageTimer, SIGNAL( timeout() ), this, SLOT( clearStatusBar() ) ); + markerWidget->setFixedWidth( fontMetrics().width( "0000" ) + 20 ); + l->addWidget( markerWidget ); + layout = new TQVBoxLayout( l ); +} + +void ViewManager::addView( TQWidget *view ) +{ + layout->addWidget( view ); + curView = view; + connect( ( (Editor*)curView )->verticalScrollBar(), SIGNAL( valueChanged( int ) ), + markerWidget, SLOT( doRepaint() ) ); + connect( (Editor*)curView, SIGNAL( textChanged() ), + markerWidget, SLOT( doRepaint() ) ); + connect( (Editor*)curView, SIGNAL( clearErrorMarker() ), + this, SLOT( clearErrorMarker() ) ); + posLabel = new TQLabel( this, "editor_poslabel" ); + posLabel->setAlignment( TQt::AlignVCenter | TQt::AlignRight ); + posLabel->setText( " Line: 1 Col: 1" ); + posLabel->setFrameStyle( TQFrame::Sunken | TQFrame::Panel ); + posLabel->setLineWidth( 1 ); + posLabel->setFixedHeight( posLabel->fontMetrics().height() ); + layout->addWidget( posLabel ); + connect( curView, SIGNAL( cursorPositionChanged( int, int ) ), + this, SLOT( cursorPositionChanged( int, int ) ) ); +} + +TQWidget *ViewManager::currentView() const +{ + return curView; +} + +void ViewManager::childEvent( TQChildEvent *e ) +{ + if ( e->type() == TQEvent::ChildInserted && ::qt_cast<Editor*>(e->child()) ) + addView( (TQWidget*)e->child() ); + TQWidget::childEvent( e ); +} + +void ViewManager::setError( int line ) +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->paragAt( line ); + if ( p ) { + ( (Editor*)curView )->setErrorSelection( line ); + ( (Editor*)curView )->setCursorPosition( line, 0 ); + ( (Editor*)curView )->viewport()->setFocus(); + ( (Editor*)curView )->makeFunctionVisible( p ); + ParagData *paragData = (ParagData*)p->extraData(); + if ( !paragData ) + paragData = new ParagData; + paragData->marker = ParagData::Error; + p->setExtraData( paragData ); + markerWidget->doRepaint(); + } +} + +void ViewManager::setStep( int line ) +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + while ( p ) { + if ( p->extraData() ) + ( (ParagData*)p->extraData() )->step = FALSE; + p = p->next(); + } + p = ( (Editor*)curView )->document()->paragAt( line ); + if ( p ) { + ( (Editor*)curView )->setStepSelection( line ); + ( (Editor*)curView )->setCursorPosition( line, 0 ); + ( (Editor*)curView )->viewport()->setFocus(); + ( (Editor*)curView )->makeFunctionVisible( p ); + ParagData *paragData = (ParagData*)p->extraData(); + if ( !paragData ) + paragData = new ParagData; + paragData->step = TRUE; + p->setExtraData( paragData ); + markerWidget->doRepaint(); + } +} + +void ViewManager::clearStep() +{ + ( (Editor*)curView )->clearStepSelection(); + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + while ( p ) { + if ( p->extraData() ) + ( (ParagData*)p->extraData() )->step = FALSE; + p = p->next(); + } + markerWidget->doRepaint(); +} + +void ViewManager::setStackFrame( int line ) +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->paragAt( line ); + if ( p ) { + ( (Editor*)curView )->sync(); + ( (Editor*)curView )->setCursorPosition( line, 0 ); + ( (Editor*)curView )->ensureCursorVisible(); + ( (Editor*)curView )->viewport()->setFocus(); + ( (Editor*)curView )->makeFunctionVisible( p ); + ParagData *paragData = (ParagData*)p->extraData(); + if ( !paragData ) + paragData = new ParagData; + paragData->stackFrame = TRUE; + p->setExtraData( paragData ); + markerWidget->doRepaint(); + } +} + +void ViewManager::clearStackFrame() +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + while ( p ) { + if ( p->extraData() ) { + ( (ParagData*)p->extraData() )->stackFrame = FALSE; + if ( ( (ParagData*)p->extraData() )->marker == ParagData::Error ) + ( (ParagData*)p->extraData() )->marker = ParagData::NoMarker; + } + p = p->next(); + } + markerWidget->doRepaint(); +} + +void ViewManager::resizeEvent( TQResizeEvent *e ) +{ + TQWidget::resizeEvent( e ); + markerWidget->doRepaint(); +} + +void ViewManager::clearErrorMarker() +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + while ( p ) { + if ( p->extraData() ) + ( (ParagData*)p->extraData() )->marker = ParagData::NoMarker; + p = p->next(); + } + markerWidget->doRepaint(); +} + +void ViewManager::setBreakPoints( const TQValueList<uint> &l ) +{ + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + int i = 0; + while ( p ) { + if ( l.find( i ) != l.end() ) { + if ( !p->extraData() ) { + ParagData *data = new ParagData; + p->setExtraData( data ); + } + ParagData *data = (ParagData*)p->extraData(); + data->marker = ParagData::Breakpoint; + } else if ( p->extraData() ) { + ParagData *data = (ParagData*)p->extraData(); + data->marker = ParagData::NoMarker; + } + p = p->next(); + ++i; + } + markerWidget->doRepaint(); +} + +TQValueList<uint> ViewManager::breakPoints() const +{ + TQValueList<uint> l; + int i = 0; + TQTextParagraph *p = ( (Editor*)curView )->document()->firstParagraph(); + while ( p ) { + if ( p->extraData() && + ( (ParagData*)p->extraData() )->marker == ParagData::Breakpoint ) + l << i; + p = p->next(); + ++i; + } + return l; +} + +void ViewManager::showMarkerWidget( bool b ) +{ + if ( b ) + markerWidget->show(); + else + markerWidget->hide(); +} + +void ViewManager::emitMarkersChanged() +{ + emit markersChanged(); +} + +void ViewManager::cursorPositionChanged( int row, int col ) +{ + posLabel->setText( TQString( " Line: %1 Col: %2" ).arg( row + 1 ).arg( col + 1 ) ); +} + +void ViewManager::showMessage( const TQString &msg ) +{ + int row; + int col; + ( (TQTextEdit*)currentView() )->getCursorPosition( &row, &col ); + posLabel->setText( msg ); + messageTimer->start( 1000, TRUE ); +} + +void ViewManager::clearStatusBar() +{ + int row; + int col; + ( (TQTextEdit*)currentView() )->getCursorPosition( &row, &col ); + posLabel->setText( TQString( " Line: %1 Col: %2" ).arg( row + 1 ).arg( col + 1 ) ); +} diff --git a/tools/designer/editor/viewmanager.h b/tools/designer/editor/viewmanager.h new file mode 100644 index 000000000..cb2ebaa27 --- /dev/null +++ b/tools/designer/editor/viewmanager.h @@ -0,0 +1,100 @@ + /********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef VIEWMANAGER_H +#define VIEWMANAGER_H + +#include <qwidget.h> +#include <qvaluelist.h> + +class TQChildEvent; +class MarkerWidget; +class TQVBoxLayout; +class TQDockArea; +class TQTextParagraph; +class TQLabel; +class TQTimer; + +class ViewManager : public TQWidget +{ + Q_OBJECT + +public: + ViewManager( TQWidget *parent, const char *name ); + + void addView( TQWidget *view ); + TQWidget *currentView() const; + void showMarkerWidget( bool ); + + void setError( int line ); + void setStep( int line ); + void setStackFrame( int line ); + void clearStep(); + void clearStackFrame(); + void setBreakPoints( const TQValueList<uint> &l ); + TQValueList<uint> breakPoints() const; + + void emitMarkersChanged(); + MarkerWidget *marker_widget() const { return markerWidget; } + +signals: + void markersChanged(); + void expandFunction( TQTextParagraph *p ); + void collapseFunction( TQTextParagraph *p ); + void collapse( bool all /*else only functions*/ ); + void expand( bool all /*else only functions*/ ); + void editBreakPoints(); + void isBreakpointPossible( bool &possible, const TQString &code, int line ); + +protected slots: + void clearErrorMarker(); + void cursorPositionChanged( int row, int col ); + void showMessage( const TQString &msg ); + void clearStatusBar(); + +protected: + void childEvent( TQChildEvent *e ); + void resizeEvent( TQResizeEvent *e ); + +private: + TQWidget *curView; + MarkerWidget *markerWidget; + TQVBoxLayout *layout; + TQDockArea *dockArea; + TQLabel *posLabel; + TQString extraText; + TQTimer *messageTimer; + +}; + +#endif diff --git a/tools/designer/editor/yyindent.cpp b/tools/designer/editor/yyindent.cpp new file mode 100644 index 000000000..832e58b29 --- /dev/null +++ b/tools/designer/editor/yyindent.cpp @@ -0,0 +1,1170 @@ +/********************************************************************** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of TQt Designer. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +/* + This file is a self-contained interactive indenter for C++ and TQt + Script. + + The general problem of indenting a C++ program is ill posed. On the + one hand, an indenter has to analyze programs written in a + free-form formal language that is best described in terms of + tokens, not characters, not lines. On the other hand, indentation + applies to lines and white space characters matter, and otherwise + the programs to indent are formally invalid in general, as they are + begin edited. + + The approach taken here works line by line. We receive a program + consisting of N lines or more, and we want to compute the + indentation appropriate for the Nth line. Lines beyond the Nth + lines are of no concern to us, so for simplicity we pretend the + program has exactly N lines and we call the Nth line the "bottom + line". Typically, we have to indent the bottom line when it's still + empty, so we concentrate our analysis on the N - 1 lines that + precede. + + By inspecting the (N - 1)-th line, the (N - 2)-th line, ... + backwards, we determine the kind of the bottom line and indent it + accordingly. + + * The bottom line is a comment line. See + bottomLineStartsInCComment() and + indentWhenBottomLineStartsInCComment(). + * The bottom line is a continuation line. See isContinuationLine() + and indentForContinuationLine(). + * The bottom line is a standalone line. See + indentForStandaloneLine(). + + Certain tokens that influence the indentation, notably braces, are + looked for in the lines. This is done by simple string comparison, + without a real tokenizer. Confusing constructs such as comments and + string literals are removed beforehand. +*/ + +#include <qregexp.h> + +/* qmake ignore Q_OBJECT */ + +/* + The indenter avoids getting stuck in almost infinite loops by + imposing arbitrary limits on the number of lines it analyzes when + looking for a construct. + + For example, the indenter never considers more than BigRoof lines + backwards when looking for the start of a C-style comment. +*/ +static const int SmallRoof = 40; +static const int BigRoof = 400; + +/* + The indenter supports a few parameters: + + * ppHardwareTabSize is the size of a '\t' in your favorite editor. + * ppIndentSize is the size of an indentation, or software tab + size. + * ppContinuationIndentSize is the extra indent for a continuation + line, when there is nothing to align against on the previous + line. + * ppCommentOffset is the indentation within a C-style comment, + when it cannot be picked up. +*/ + +static int ppHardwareTabSize = 8; +static int ppIndentSize = 4; +static int ppContinuationIndentSize = 8; + +static const int ppCommentOffset = 2; + +void setTabSize( int size ) +{ + ppHardwareTabSize = size; +} + +void setIndentSize( int size ) +{ + ppIndentSize = size; + ppContinuationIndentSize = 2 * size; +} + +static TQRegExp *literal = 0; +static TQRegExp *label = 0; +static TQRegExp *inlineCComment = 0; +static TQRegExp *braceX = 0; +static TQRegExp *iflikeKeyword = 0; + +/* + Returns the first non-space character in the string t, or + TQChar::null if the string is made only of white space. +*/ +static TQChar firstNonWhiteSpace( const TQString& t ) +{ + int i = 0; + while ( i < (int) t.length() ) { + if ( !t[i].isSpace() ) + return t[i]; + i++; + } + return TQChar::null; +} + +/* + Returns TRUE if string t is made only of white space; otherwise + returns FALSE. +*/ +static bool isOnlyWhiteSpace( const TQString& t ) +{ + return firstNonWhiteSpace( t ).isNull(); +} + +/* + Assuming string t is a line, returns the column number of a given + index. Column numbers and index are identical for strings that don't + contain '\t's. +*/ +int columnForIndex( const TQString& t, int index ) +{ + int col = 0; + if ( index > (int) t.length() ) + index = t.length(); + + for ( int i = 0; i < index; i++ ) { + if ( t[i] == TQChar('\t') ) { + col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize; + } else { + col++; + } + } + return col; +} + +/* + Returns the indentation size of string t. +*/ +int indentOfLine( const TQString& t ) +{ + return columnForIndex( t, t.find(firstNonWhiteSpace(t)) ); +} + +/* + Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better + left alone since they break the "index equals column" rule. No + provisions are taken against '\n' or '\r', which shouldn't occur in + t anyway. +*/ +static inline void eraseChar( TQString& t, int k, TQChar ch ) +{ + if ( t[k] != '\t' ) + t[k] = ch; +} + +/* + Removes some nefast constructs from a code line and returns the + resulting line. +*/ +static TQString trimmedCodeLine( const TQString& t ) +{ + TQString trimmed = t; + int k; + + /* + Replace character and string literals by X's, since they may + contain confusing characters (such as '{' and ';'). "Hello!" is + replaced by XXXXXXXX. The literals are rigourously of the same + length before and after; otherwise, we would break alignment of + continuation lines. + */ + k = 0; + while ( (k = trimmed.find(*literal, k)) != -1 ) { + for ( int i = 0; i < literal->matchedLength(); i++ ) + eraseChar( trimmed, k + i, 'X' ); + k += literal->matchedLength(); + } + + /* + Replace inline C-style comments by spaces. Other comments are + handled elsewhere. + */ + k = 0; + while ( (k = trimmed.find(*inlineCComment, k)) != -1 ) { + for ( int i = 0; i < inlineCComment->matchedLength(); i++ ) + eraseChar( trimmed, k + i, ' ' ); + k += inlineCComment->matchedLength(); + } + + /* + Replace goto and switch labels by whitespace, but be careful + with this case: + + foo1: bar1; + bar2; + */ + while ( trimmed.findRev(':') != -1 && trimmed.find(*label) != -1 ) { + TQString cap1 = label->cap( 1 ); + int pos1 = label->pos( 1 ); + int stop = cap1.length(); + + if ( pos1 + stop < (int) trimmed.length() && ppIndentSize < stop ) + stop = ppIndentSize; + + int i = 0; + while ( i < stop ) { + eraseChar( trimmed, pos1 + i, ' ' ); + i++; + } + while ( i < (int) cap1.length() ) { + eraseChar( trimmed, pos1 + i, ';' ); + i++; + } + } + + /* + Remove C++-style comments. + */ + k = trimmed.find( "//" ); + if ( k != -1 ) + trimmed.truncate( k ); + + return trimmed; +} + +/* + Returns '(' if the last parenthesis is opening, ')' if it is + closing, and TQChar::null if there are no parentheses in t. +*/ +static inline TQChar lastParen( const TQString& t ) +{ + int i = t.length(); + while ( i > 0 ) { + i--; + if ( t[i] == TQChar('(') || t[i] == TQChar(')') ) + return t[i]; + } + return TQChar::null; +} + +/* + Returns TRUE if typedIn the same as okayCh or is null; otherwise + returns FALSE. +*/ +static inline bool okay( TQChar typedIn, TQChar okayCh ) +{ + return typedIn == TQChar::null || typedIn == okayCh; +} + +/* + The "linizer" is a group of functions and variables to iterate + through the source code of the program to indent. The program is + given as a list of strings, with the bottom line being the line to + indent. The actual program might contain extra lines, but those are + uninteresting and not passed over to us. +*/ + +struct LinizerState +{ + TQString line; + int braceDepth; + bool leftBraceFollows; + + TQStringList::ConstIterator iter; + bool inCComment; + bool pendingRightBrace; +}; + +static TQStringList *yyProgram = 0; +static LinizerState *yyLinizerState = 0; + +// shorthands +static const TQString *yyLine = 0; +static const int *yyBraceDepth = 0; +static const bool *yyLeftBraceFollows = 0; + +/* + Saves and restores the state of the global linizer. This enables + backtracking. +*/ +#define YY_SAVE() \ + LinizerState savedState = *yyLinizerState +#define YY_RESTORE() \ + *yyLinizerState = savedState + +/* + Advances to the previous line in yyProgram and update yyLine + accordingly. yyLine is cleaned from comments and other damageable + constructs. Empty lines are skipped. +*/ +static bool readLine() +{ + int k; + + yyLinizerState->leftBraceFollows = + ( firstNonWhiteSpace(yyLinizerState->line) == TQChar('{') ); + + do { + if ( yyLinizerState->iter == yyProgram->begin() ) { + yyLinizerState->line = TQString::null; + return FALSE; + } + + --yyLinizerState->iter; + yyLinizerState->line = *yyLinizerState->iter; + + yyLinizerState->line = trimmedCodeLine( yyLinizerState->line ); + + /* + Remove C-style comments that span multiple lines. If the + bottom line starts in a C-style comment, we are not aware + of that and eventually yyLine will contain a slash-aster. + + Notice that both if's can be executed, since + yyLinizerState->inCComment is potentially set to FALSE in + the first if. The order of the if's is also important. + */ + + if ( yyLinizerState->inCComment ) { + TQString slashAster( "/*" ); + + k = yyLinizerState->line.find( slashAster ); + if ( k == -1 ) { + yyLinizerState->line = TQString::null; + } else { + yyLinizerState->line.truncate( k ); + yyLinizerState->inCComment = FALSE; + } + } + + if ( !yyLinizerState->inCComment ) { + TQString asterSlash( "*/" ); + + k = yyLinizerState->line.find( asterSlash ); + if ( k != -1 ) { + for ( int i = 0; i < k + 2; i++ ) + eraseChar( yyLinizerState->line, i, ' ' ); + yyLinizerState->inCComment = TRUE; + } + } + + /* + Remove preprocessor directives. + */ + k = 0; + while ( k < (int) yyLinizerState->line.length() ) { + TQChar ch = yyLinizerState->line[k]; + if ( ch == TQChar('#') ) { + yyLinizerState->line = TQString::null; + } else if ( !ch.isSpace() ) { + break; + } + k++; + } + + /* + Remove trailing spaces. + */ + k = yyLinizerState->line.length(); + while ( k > 0 && yyLinizerState->line[k - 1].isSpace() ) + k--; + yyLinizerState->line.truncate( k ); + + /* + '}' increment the brace depth and '{' decrements it and not + the other way around, as we are parsing backwards. + */ + yyLinizerState->braceDepth += + yyLinizerState->line.contains( '}' ) - + yyLinizerState->line.contains( '{' ); + + /* + We use a dirty trick for + + } else ... + + We don't count the '}' yet, so that it's more or less + equivalent to the friendly construct + + } + else ... + */ + if ( yyLinizerState->pendingRightBrace ) + yyLinizerState->braceDepth++; + yyLinizerState->pendingRightBrace = + ( yyLinizerState->line.find(*braceX) == 0 ); + if ( yyLinizerState->pendingRightBrace ) + yyLinizerState->braceDepth--; + } while ( yyLinizerState->line.isEmpty() ); + + return TRUE; +} + +/* + Resets the linizer to its initial state, with yyLine containing the + line above the bottom line of the program. +*/ +static void startLinizer() +{ + yyLinizerState->braceDepth = 0; + yyLinizerState->inCComment = FALSE; + yyLinizerState->pendingRightBrace = FALSE; + + yyLine = &yyLinizerState->line; + yyBraceDepth = &yyLinizerState->braceDepth; + yyLeftBraceFollows = &yyLinizerState->leftBraceFollows; + + yyLinizerState->iter = yyProgram->end(); + --yyLinizerState->iter; + yyLinizerState->line = *yyLinizerState->iter; + readLine(); +} + +/* + Returns TRUE if the start of the bottom line of yyProgram (and + potentially the whole line) is part of a C-style comment; otherwise + returns FALSE. +*/ +static bool bottomLineStartsInCComment() +{ + TQString slashAster( "/*" ); + TQString asterSlash( "*/" ); + + /* + We could use the linizer here, but that would slow us down + terribly. We are better to trim only the code lines we need. + */ + TQStringList::ConstIterator p = yyProgram->end(); + --p; // skip bottom line + + for ( int i = 0; i < BigRoof; i++ ) { + if ( p == yyProgram->begin() ) + return FALSE; + --p; + + if ( (*p).find(slashAster) != -1 || (*p).find(asterSlash) != -1 ) { + TQString trimmed = trimmedCodeLine( *p ); + + if ( trimmed.find(slashAster) != -1 ) { + return TRUE; + } else if ( trimmed.find(asterSlash) != -1 ) { + return FALSE; + } + } + } + return FALSE; +} + +/* + Returns the recommended indent for the bottom line of yyProgram + assuming that it starts in a C-style comment, a condition that is + tested elsewhere. + + Essentially, we're trying to align against some text on the previous + line. +*/ +static int indentWhenBottomLineStartsInCComment() +{ + int k = yyLine->findRev( "/*" ); + if ( k == -1 ) { + /* + We found a normal text line in a comment. Align the + bottom line with the text on this line. + */ + return indentOfLine( *yyLine ); + } else { + /* + The C-style comment starts on this line. If there is + text on the same line, align with it. Otherwise, align + with the slash-aster plus a given offset. + */ + int indent = columnForIndex( *yyLine, k ); + k += 2; + while ( k < (int) yyLine->length() ) { + if ( !(*yyLine)[k].isSpace() ) + return columnForIndex( *yyLine, k ); + k++; + } + return indent + ppCommentOffset; + } +} + +/* + A function called match...() modifies the linizer state. If it + returns TRUE, yyLine is the top line of the matched construct; + otherwise, the linizer is left in an unknown state. + + A function called is...() keeps the linizer state intact. +*/ + +/* + Returns TRUE if the current line (and upwards) forms a braceless + control statement; otherwise returns FALSE. + + The first line of the following example is a "braceless control + statement": + + if ( x ) + y; +*/ +static bool matchBracelessControlStatement() +{ + int delimDepth = 0; + + if ( yyLine->endsWith("else") ) + return TRUE; + + if ( !yyLine->endsWith(")") ) + return FALSE; + + for ( int i = 0; i < SmallRoof; i++ ) { + int j = yyLine->length(); + while ( j > 0 ) { + j--; + TQChar ch = (*yyLine)[j]; + + switch ( ch.unicode() ) { + case ')': + delimDepth++; + break; + case '(': + delimDepth--; + if ( delimDepth == 0 ) { + if ( yyLine->find(*iflikeKeyword) != -1 ) { + /* + We have + + if ( x ) + y + + "if ( x )" is not part of the statement + "y". + */ + return TRUE; + } + } + if ( delimDepth == -1 ) { + /* + We have + + if ( (1 + + 2) + + and not + + if ( 1 + + 2 ) + */ + return FALSE; + } + break; + case '{': + case '}': + case ';': + /* + We met a statement separator, but not where we + expected it. What follows is probably a weird + continuation line. Be careful with ';' in for, + though. + */ + if ( ch != TQChar(';') || delimDepth == 0 ) + return FALSE; + } + } + + if ( !readLine() ) + break; + } + return FALSE; +} + +/* + Returns TRUE if yyLine is an unfinished line; otherwise returns + FALSE. + + In many places we'll use the terms "standalone line", "unfinished + line" and "continuation line". The meaning of these should be + evident from this code example: + + a = b; // standalone line + c = d + // unfinished line + e + // unfinished continuation line + f + // unfinished continuation line + g; // continuation line +*/ +static bool isUnfinishedLine() +{ + bool unf = FALSE; + + YY_SAVE(); + + if ( yyLine->isEmpty() ) + return FALSE; + + TQChar lastCh = (*yyLine)[(int) yyLine->length() - 1]; + if ( TQString("{};").find(lastCh) == -1 && !yyLine->endsWith("...") ) { + /* + It doesn't end with ';' or similar. If it's neither + "Q_OBJECT" nor "if ( x )", it must be an unfinished line. + */ + unf = ( yyLine->contains("Q_OBJECT") == 0 && + !matchBracelessControlStatement() ); + } else if ( lastCh == TQChar(';') ) { + if ( lastParen(*yyLine) == TQChar('(') ) { + /* + Exception: + + for ( int i = 1; i < 10; + */ + unf = TRUE; + } else if ( readLine() && yyLine->endsWith(";") && + lastParen(*yyLine) == TQChar('(') ) { + /* + Exception: + + for ( int i = 1; + i < 10; + */ + unf = TRUE; + } + } + + YY_RESTORE(); + return unf; +} + +/* + Returns TRUE if yyLine is a continuation line; otherwise returns + FALSE. +*/ +static bool isContinuationLine() +{ + bool cont = FALSE; + + YY_SAVE(); + if ( readLine() ) + cont = isUnfinishedLine(); + YY_RESTORE(); + return cont; +} + +/* + Returns the recommended indent for the bottom line of yyProgram, + assuming it's a continuation line. + + We're trying to align the continuation line against some parenthesis + or other bracked left opened on a previous line, or some interesting + operator such as '='. +*/ +static int indentForContinuationLine() +{ + int braceDepth = 0; + int delimDepth = 0; + + bool leftBraceFollowed = *yyLeftBraceFollows; + + for ( int i = 0; i < SmallRoof; i++ ) { + int hook = -1; + + int j = yyLine->length(); + while ( j > 0 && hook < 0 ) { + j--; + TQChar ch = (*yyLine)[j]; + + switch ( ch.unicode() ) { + case ')': + case ']': + delimDepth++; + break; + case '}': + braceDepth++; + break; + case '(': + case '[': + delimDepth--; + /* + An unclosed delimiter is a good place to align at, + at least for some styles (including Trolltech's). + */ + if ( delimDepth == -1 ) + hook = j; + break; + case '{': + braceDepth--; + /* + A left brace followed by other stuff on the same + line is typically for an enum or an initializer. + Such a brace must be treated just like the other + delimiters. + */ + if ( braceDepth == -1 ) { + if ( j < (int) yyLine->length() - 1 ) { + hook = j; + } else { + return 0; // shouldn't happen + } + } + break; + case '=': + /* + An equal sign is a very natural alignment hook + because it's usually the operator with the lowest + precedence in statements it appears in. Case in + point: + + int x = 1 + + 2; + + However, we have to beware of constructs such as + default arguments and explicit enum constant + values: + + void foo( int x = 0, + int y = 0 ); + + And not + + void foo( int x = 0, + int y = 0 ); + + These constructs are caracterized by a ',' at the + end of the unfinished lines or by unbalanced + parentheses. + */ + if ( TQString("!=<>").find((*yyLine)[j - 1]) == -1 && + (*yyLine)[j + 1] != '=' ) { + if ( braceDepth == 0 && delimDepth == 0 && + j < (int) yyLine->length() - 1 && + !yyLine->endsWith(",") && + (yyLine->contains('(') == yyLine->contains(')')) ) + hook = j; + } + } + } + + if ( hook >= 0 ) { + /* + Yes, we have a delimiter or an operator to align + against! We don't really align against it, but rather + against the following token, if any. In this example, + the following token is "11": + + int x = ( 11 + + 2 ); + + If there is no such token, we use a continuation indent: + + static TQRegExp foo( TQString( + "foo foo foo foo foo foo foo foo foo") ); + */ + hook++; + while ( hook < (int) yyLine->length() ) { + if ( !(*yyLine)[hook].isSpace() ) + return columnForIndex( *yyLine, hook ); + hook++; + } + return indentOfLine( *yyLine ) + ppContinuationIndentSize; + } + + if ( braceDepth != 0 ) + break; + + /* + The line's delimiters are balanced. It looks like a + continuation line or something. + */ + if ( delimDepth == 0 ) { + if ( leftBraceFollowed ) { + /* + We have + + int main() + { + + or + + Bar::Bar() + : Foo( x ) + { + + The "{" should be flush left. + */ + if ( !isContinuationLine() ) + return indentOfLine( *yyLine ); + } else if ( isContinuationLine() || yyLine->endsWith(",") ) { + /* + We have + + x = a + + b + + c; + + or + + int t[] = { + 1, 2, 3, + 4, 5, 6 + + The "c;" should fall right under the "b +", and the + "4, 5, 6" right under the "1, 2, 3,". + */ + return indentOfLine( *yyLine ); + } else { + /* + We have + + stream << 1 + + 2; + + We could, but we don't, try to analyze which + operator has precedence over which and so on, to + obtain the excellent result + + stream << 1 + + 2; + + We do have a special trick above for the assignment + operator above, though. + */ + return indentOfLine( *yyLine ) + ppContinuationIndentSize; + } + } + + if ( !readLine() ) + break; + } + return 0; +} + +/* + Returns the recommended indent for the bottom line of yyProgram if + that line is standalone (or should be indented likewise). + + Indenting a standalone line is tricky, mostly because of braceless + control statements. Grossly, we are looking backwards for a special + line, a "hook line", that we can use as a starting point to indent, + and then modify the indentation level according to the braces met + along the way to that hook. + + Let's consider a few examples. In all cases, we want to indent the + bottom line. + + Example 1: + + x = 1; + y = 2; + + The hook line is "x = 1;". We met 0 opening braces and 0 closing + braces. Therefore, "y = 2;" inherits the indent of "x = 1;". + + Example 2: + + if ( x ) { + y; + + The hook line is "if ( x ) {". No matter what precedes it, "y;" has + to be indented one level deeper than the hook line, since we met one + opening brace along the way. + + Example 3: + + if ( a ) + while ( b ) { + c; + } + d; + + To indent "d;" correctly, we have to go as far as the "if ( a )". + Compare with + + if ( a ) { + while ( b ) { + c; + } + d; + + Still, we're striving to go back as little as possible to accomodate + people with irregular indentation schemes. A hook line near at hand + is much more reliable than a remote one. +*/ +static int indentForStandaloneLine() +{ + for ( int i = 0; i < SmallRoof; i++ ) { + if ( !*yyLeftBraceFollows ) { + YY_SAVE(); + + if ( matchBracelessControlStatement() ) { + /* + The situation is this, and we want to indent "z;": + + if ( x && + y ) + z; + + yyLine is "if ( x &&". + */ + return indentOfLine( *yyLine ) + ppIndentSize; + } + YY_RESTORE(); + } + + if ( yyLine->endsWith(";") || yyLine->contains('{') > 0 ) { + /* + The situation is possibly this, and we want to indent + "z;": + + while ( x ) + y; + z; + + We return the indent of "while ( x )". In place of "y;", + any arbitrarily complex compound statement can appear. + */ + + if ( *yyBraceDepth > 0 ) { + do { + if ( !readLine() ) + break; + } while ( *yyBraceDepth > 0 ); + } + + LinizerState hookState; + + while ( isContinuationLine() ) + readLine(); + hookState = *yyLinizerState; + + readLine(); + if ( *yyBraceDepth <= 0 ) { + do { + if ( !matchBracelessControlStatement() ) + break; + hookState = *yyLinizerState; + } while ( readLine() ); + } + + *yyLinizerState = hookState; + + while ( isContinuationLine() ) + readLine(); + + /* + Never trust lines containing only '{' or '}', as some + people (Richard M. Stallman) format them weirdly. + */ + if ( yyLine->stripWhiteSpace().length() > 1 ) + return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize; + } + + if ( !readLine() ) + return -*yyBraceDepth * ppIndentSize; + } + return 0; +} + +/* + Constructs global variables used by the indenter. +*/ +static void initializeIndenter() +{ + literal = new TQRegExp( "([\"'])(?:\\\\.|[^\\\\])*\\1" ); + literal->setMinimal( TRUE ); + label = new TQRegExp( + "^\\s*((?:case\\b([^:]|::)+|[a-zA-Z_0-9]+)(?:\\s+slots)?:)(?!:)" ); + inlineCComment = new TQRegExp( "/\\*.*\\*/" ); + inlineCComment->setMinimal( TRUE ); + braceX = new TQRegExp( "^\\s*\\}\\s*(?:else|catch)\\b" ); + iflikeKeyword = new TQRegExp( "\\b(?:catch|do|for|if|while)\\b" ); + + yyLinizerState = new LinizerState; +} + +/* + Destroys global variables used by the indenter. +*/ +static void terminateIndenter() +{ + delete literal; + delete label; + delete inlineCComment; + delete braceX; + delete iflikeKeyword; + delete yyLinizerState; +} + +/* + Returns the recommended indent for the bottom line of program. + Unless null, typedIn stores the character of yyProgram that + triggered reindentation. + + This function works better if typedIn is set properly; it is + slightly more conservative if typedIn is completely wild, and + slighly more liberal if typedIn is always null. The user might be + annoyed by the liberal behavior. +*/ +int indentForBottomLine( const TQStringList& program, TQChar typedIn ) +{ + if ( program.isEmpty() ) + return 0; + + initializeIndenter(); + + yyProgram = new TQStringList( program ); + startLinizer(); + + const TQString& bottomLine = program.last(); + TQChar firstCh = firstNonWhiteSpace( bottomLine ); + int indent; + + if ( bottomLineStartsInCComment() ) { + /* + The bottom line starts in a C-style comment. Indent it + smartly, unless the user has already played around with it, + in which case it's better to leave her stuff alone. + */ + if ( isOnlyWhiteSpace(bottomLine) ) { + indent = indentWhenBottomLineStartsInCComment(); + } else { + indent = indentOfLine( bottomLine ); + } + } else if ( okay(typedIn, '#') && firstCh == TQChar('#') ) { + /* + Preprocessor directives go flush left. + */ + indent = 0; + } else { + if ( isUnfinishedLine() ) { + indent = indentForContinuationLine(); + } else { + indent = indentForStandaloneLine(); + } + + if ( okay(typedIn, '}') && firstCh == TQChar('}') ) { + /* + A closing brace is one level more to the left than the + code it follows. + */ + indent -= ppIndentSize; + } else if ( okay(typedIn, ':') ) { + TQRegExp caseLabel( + "\\s*(?:case\\b(?:[^:]|::)+" + "|(?:public|protected|private|signals|default)(?:\\s+slots)?\\s*" + ")?:.*" ); + + if ( caseLabel.exactMatch(bottomLine) ) { + /* + Move a case label (or the ':' in front of a + constructor initialization list) one level to the + left, but only if the user did not play around with + it yet. Some users have exotic tastes in the + matter, and most users probably are not patient + enough to wait for the final ':' to format their + code properly. + + We don't attempt the same for goto labels, as the + user is probably the middle of "foo::bar". (Who + uses goto, anyway?) + */ + if ( indentOfLine(bottomLine) <= indent ) + indent -= ppIndentSize; + else + indent = indentOfLine( bottomLine ); + } + } + } + delete yyProgram; + terminateIndenter(); + return TQMAX( 0, indent ); +} + +#ifdef Q_TEST_YYINDENT +/* + Test driver. +*/ + +#include <qfile.h> +#include <qtextstream.h> + +#include <errno.h> + +static TQString fileContents( const TQString& fileName ) +{ + TQFile f( fileName ); + if ( !f.open(IO_ReadOnly) ) { + qWarning( "yyindent error: Cannot open file '%s' for reading: %s", + fileName.latin1(), strerror(errno) ); + return TQString::null; + } + + TQTextStream t( &f ); + TQString contents = t.read(); + f.close(); + if ( contents.isEmpty() ) + qWarning( "yyindent error: File '%s' is empty", fileName.latin1() ); + return contents; +} + +int main( int argc, char **argv ) +{ + if ( argc != 2 ) { + qWarning( "usage: yyindent file.cpp" ); + return 1; + } + + TQString code = fileContents( argv[1] ); + TQStringList program = TQStringList::split( '\n', code, TRUE ); + TQStringList p; + TQString out; + + while ( !program.isEmpty() && program.last().stripWhiteSpace().isEmpty() ) + program.remove( program.fromLast() ); + + TQStringList::ConstIterator line = program.begin(); + while ( line != program.end() ) { + p.push_back( *line ); + TQChar typedIn = firstNonWhiteSpace( *line ); + if ( p.last().endsWith(":") ) + typedIn = ':'; + + int indent = indentForBottomLine( p, typedIn ); + + if ( !(*line).stripWhiteSpace().isEmpty() ) { + for ( int j = 0; j < indent; j++ ) + out += " "; + out += (*line).stripWhiteSpace(); + } + out += "\n"; + ++line; + } + + while ( out.endsWith("\n") ) + out.truncate( out.length() - 1 ); + + printf( "%s\n", out.latin1() ); + return 0; +} +#endif |