📄 completion.cpp
字号:
/************************************************************************ Copyright (C) 2000 Trolltech AS. All rights reserved.**** This file is part of Qt Designer.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#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 QColor getColor( const QString &type ){ if ( type == "function" || type == "slot" || type == "package" ) return Qt::blue; else if ( type == "variable" || type == "widget" || type == "dir" ) return Qt::darkRed; else if ( type == "object" || type == "class" ) return Qt::darkBlue; else if ( type == "property" ) return Qt::darkGreen; else if ( type == "enum" ) return Qt::darkYellow; return Qt::black;}class CompletionItem : public QListBoxItem{public: CompletionItem( QListBox *lb, const QString &txt, const QString &t, const QString &p, const QString &pre, const QString &p2 ) : QListBoxItem( lb ), type( t ), postfix( p ), prefix( pre ), postfix2( p2 ), parag( 0 ), lastState( FALSE ) { setText( txt ); } ~CompletionItem() { delete parag; } void paint( QPainter *painter ) { if ( lastState != isSelected() ) { delete parag; parag = 0; } lastState = isSelected(); if ( !parag ) setupParagraph(); parag->paint( *painter, listBox()->colorGroup() ); } int height( const QListBox * ) const { if ( !parag ) ( (CompletionItem*)this )->setupParagraph(); return parag->rect().height(); } int width( const QListBox * ) const { if ( !parag ) ( (CompletionItem*)this )->setupParagraph(); return parag->rect().width() - 2; } QString text() const { return QListBoxItem::text() + postfix; }private: void setupParagraph(); QString type, postfix, prefix, postfix2; QTextParagraph *parag; bool lastState;};void CompletionItem::setupParagraph() { if ( !parag ) { QTextFormatter *formatter; formatter = new QTextFormatterBreakWords; formatter->setWrapEnabled( FALSE ); parag = new QTextParagraph( 0 ); parag->setTabStops( listBox()->fontMetrics().width( "propertyXXXX" ) ); parag->pseudoDocument()->pFormatter = formatter; parag->insert( 0, " " + type + ( type.isEmpty() ? " " : "\t" ) + prefix + QListBoxItem::text() + postfix + postfix2 ); bool selCol = isSelected() && listBox()->colorGroup().highlightedText() != listBox()->colorGroup().text(); QColor sc = selCol ? listBox()->colorGroup().highlightedText() : getColor( type ); QTextFormat *f1 = parag->formatCollection()->format( listBox()->font(), sc ); QTextFormat *f3 = parag->formatCollection()->format( listBox()->font(), isSelected() ? listBox()->colorGroup().highlightedText() : listBox()->colorGroup().text() ); QFont f( listBox()->font() ); f.setBold( TRUE ); QTextFormat *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() + QListBoxItem::text().length(), f2 ); if ( !postfix.isEmpty() ) parag->setFormat( type.length() + 2 + prefix.length() + QListBoxItem::text().length(), postfix.length(), f3 ); parag->setFormat( type.length() + 2 + prefix.length() + QListBoxItem::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 QVBox( e->topLevelWidget(), 0, WType_Popup ); completionPopup->setFrameStyle( QFrame::Box | QFrame::Plain ); completionPopup->setLineWidth( 1 ); functionLabel = new ArgHintWidget( e->topLevelWidget(), "editor_function_lbl" ); functionLabel->hide(); completionListBox = new QListBox( completionPopup, "editor_completion_lb" ); completionListBox->setFrameStyle( QFrame::NoFrame ); completionListBox->installEventFilter( this ); completionListBox->setHScrollBarMode( QScrollView::AlwaysOn ); completionListBox->setVScrollBarMode( QScrollView::AlwaysOn ); completionListBox->setCornerWidget( new QSizeGrip( 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 QString &s, QTextDocument *, bool strict ){ QChar key( s[ 0 ] ); QMap<QChar, QStringList>::Iterator it = completionMap.find( key ); if ( it == completionMap.end() ) { completionMap.insert( key, QStringList( s ) ); } else { if ( strict ) { QStringList::Iterator sit; for ( sit = (*it).begin(); sit != (*it).end(); ) { QStringList::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 ); }}QValueList<CompletionEntry> EditorCompletion::completionList( const QString &s, QTextDocument *doc ) const{ if ( doc ) ( (EditorCompletion*)this )->updateCompletionMap( doc ); QChar key( s[ 0 ] ); QMap<QChar, QStringList>::ConstIterator it = completionMap.find( key ); if ( it == completionMap.end() ) return QValueList<CompletionEntry>(); QStringList::ConstIterator it2 = (*it).begin(); QValueList<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( QTextDocument *doc ){ bool strict = TRUE; if ( doc != lastDoc ) strict = FALSE; lastDoc = doc; QTextParagraph *s = doc->firstParagraph(); if ( !s->extraData() ) s->setExtraData( new ParagData ); while ( s ) { if ( s->length() == ( (ParagData*)s->extraData() )->lastLengthForCompletion ) { s = s->next(); continue; } QChar c; QString 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 = QString::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; QTextCursor *cursor = curEditor->textCursor(); QTextDocument *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; QChar c = cursor->paragraph()->at( idx - 1 )->c; if ( !c.isLetter() && !c.isNumber() && c != '_' && c != '#' ) return FALSE; QString s; idx--; completionOffset = 1; for (;;) { s.prepend( QString( 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; QValueList<CompletionEntry> lst( completionList( s, doc ) ); if ( lst.count() > 1 ) { QTextStringChar *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 ( QValueList<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() + QSize( completionListBox->verticalScrollBar()->width() + 4, completionListBox->horizontalScrollBar()->height() + 4 ) ); completionListBox->setCurrentItem( 0 ); completionListBox->setFocus(); if ( curEditor->mapToGlobal( QPoint( 0, y ) ).y() + h + completionPopup->height() < QApplication::desktop()->height() ) completionPopup->move( curEditor->mapToGlobal( curEditor-> contentsToViewport( QPoint( x, y + h ) ) ) ); else completionPopup->move( curEditor->mapToGlobal( curEditor-> contentsToViewport( QPoint( x, y - completionPopup->height() ) ) ) ); completionPopup->show(); } else if ( lst.count() == 1 ) { curEditor->insert( lst.first().text.mid( completionOffset, 0xFFFFFF ), (uint) ( QTextEdit::RedoIndentation | QTextEdit::CheckNewLines | QTextEdit::RemoveSelected ) ); } else { return FALSE; } return TRUE;}bool EditorCompletion::eventFilter( QObject *o, QEvent *e ){ if ( !enabled ) return FALSE; if ( o->inherits( "Editor" ) && e->type() == QEvent::KeyPress ) { curEditor = (Editor*)o; QKeyEvent *ke = (QKeyEvent*)e; if ( ke->key() == Key_Tab ) { QString s = curEditor->textCursor()->paragraph()->string()->toString(). left( curEditor->textCursor()->index() ); if ( 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; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -