Skip to content

Commit

Permalink
autocompleter for keywords and types
Browse files Browse the repository at this point in the history
  • Loading branch information
arun3688 authored and adeas31 committed Apr 10, 2017
1 parent 0bb681e commit c57868f
Show file tree
Hide file tree
Showing 19 changed files with 614 additions and 211 deletions.
126 changes: 123 additions & 3 deletions OMEdit/OMEditGUI/Editors/BaseEditor.cpp
Expand Up @@ -658,7 +658,7 @@ static int foldBoxWidth(const QFontMetrics &fm)
* Internal QPlainTextEdit for Editor.
*/
PlainTextEdit::PlainTextEdit(BaseEditor *pBaseEditor)
: QPlainTextEdit(pBaseEditor), mpBaseEditor(pBaseEditor)
: QPlainTextEdit(pBaseEditor),mpCompleter(0),mpBaseEditor(pBaseEditor)
{
setObjectName("BaseEditor");
QTextDocument *pTextDocument = document();
Expand All @@ -672,7 +672,10 @@ PlainTextEdit::PlainTextEdit(BaseEditor *pBaseEditor)
// parentheses matcher
mParenthesesMatchFormat = Utilities::getParenthesesMatchFormat();
mParenthesesMisMatchFormat = Utilities::getParenthesesMisMatchFormat();

// intialize the completer with QStandardItemModel
mpStandardItemModel = new QStandardItemModel();
mpCompleter = new QCompleter(this);
connect(mpCompleter, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString)));
updateLineNumberAreaWidth(0);
updateHighlights();
updateCursorPosition();
Expand All @@ -688,6 +691,61 @@ PlainTextEdit::PlainTextEdit(BaseEditor *pBaseEditor)
connect(this, SIGNAL(customContextMenuRequested(QPoint)), mpBaseEditor, SLOT(showContextMenu(QPoint)));
}

/*!
* \brief PlainTextEdit::insertCompleterKeywords
* add Keyword list to the QStandardItemModel which will be used by the Completer
* This function is set from outside depending on which editor is used (eg.) MetaModelicaEditor,
* ModelicaEditor,CEditor etc..
*/
void PlainTextEdit::insertCompleterKeywords(QStringList keywords)
{
for (int i = 0; i < keywords.size(); ++i)
{
QStandardItem *pStandardItem = new QStandardItem(keywords[i]);
pStandardItem->setIcon(QIcon(":/Resources/icons/completerkeyword.svg"));
pStandardItem->setToolTip("keywords");
mpStandardItemModel->setItem(i, 0, pStandardItem);
}
}

/*!
* \brief PlainTextEdit::insertCompleterTypes
* add types list to the QStandardItemModel which will be used by the Completer
* This function is set from outside depending on which editor is used (eg.) MetaModelicaEditor,
* ModelicaEditor,CEditor etc..
*/
void PlainTextEdit::insertCompleterTypes(QStringList types)
{
for (int k = 0; k < types.size(); ++k)
{
QStandardItem *pStandardItem = new QStandardItem(types[k]);
pStandardItem->setIcon(QIcon(":/Resources/icons/completerType.svg"));
pStandardItem->setToolTip("types");
mpStandardItemModel->appendRow(pStandardItem);
}
}

/*!
* \brief PlainTextEdit::setCompleter
* Sets the editor with the completer with items sorted alphabetically
* This function is set from outside depending on which editor is used (eg.) MetaModelicaEditor,
* ModelicaEditor,CEditor
*/
void PlainTextEdit::setCompleter()
{
// sort the StandardItemModel using QSortFilterProxy
QSortFilterProxyModel *pSortFilterProxyModel = new QSortFilterProxyModel(this);
pSortFilterProxyModel->setSourceModel(mpStandardItemModel);
pSortFilterProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
pSortFilterProxyModel->sort(0,Qt::AscendingOrder);
// set the completer with the QAbstractitem model
mpCompleter->setModel(pSortFilterProxyModel);
mpCompleter->setCaseSensitivity(Qt::CaseSensitive);
mpCompleter->setWrapAround(false);
mpCompleter->setWidget(this);
mpCompleter->setCompletionMode(QCompleter::PopupCompletion);
}

/*!
* \brief PlainTextEdit::setCanHaveBreakpoints
* Sets whether editor supports breakpoints or not. Also sets/unsets the editor's LineNumberArea mouse tracking.
Expand Down Expand Up @@ -1390,6 +1448,29 @@ void PlainTextEdit::resizeEvent(QResizeEvent *pEvent)
mpLineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

QCompleter *PlainTextEdit::completer()
{
return mpCompleter;
}

/* insert the keywords from the completer popup */
void PlainTextEdit::insertCompletion(const QString& completion)
{
QTextCursor cursor = textCursor();
int extra = completion.length() - mpCompleter->completionPrefix().length();
//cursor.movePosition(QTextCursor::Left);
cursor.movePosition(QTextCursor::EndOfWord);
cursor.insertText(completion.right(extra));
setTextCursor(cursor);
}

QString PlainTextEdit::textUnderCursor() const
{
QTextCursor cursor = textCursor();
cursor.select(QTextCursor::WordUnderCursor);
return cursor.selectedText();
}

/*!
* \brief PlainTextEdit::keyPressEvent
* Reimplementation of keyPressEvent.
Expand All @@ -1399,6 +1480,7 @@ void PlainTextEdit::keyPressEvent(QKeyEvent *pEvent)
{
bool shiftModifier = pEvent->modifiers().testFlag(Qt::ShiftModifier);
bool controlModifier = pEvent->modifiers().testFlag(Qt::ControlModifier);
bool isShortcut = (controlModifier && pEvent->key() == Qt::Key_Space); // CTRL+space
if (pEvent->key() == Qt::Key_Escape) {
if (mpBaseEditor->getFindReplaceWidget()->isVisible()) {
mpBaseEditor->getFindReplaceWidget()->close();
Expand Down Expand Up @@ -1439,10 +1521,28 @@ void PlainTextEdit::keyPressEvent(QKeyEvent *pEvent)
/* Ticket #2273. Change shift+enter to enter. */
pEvent->setModifiers(Qt::NoModifier);
}
QPlainTextEdit::keyPressEvent(pEvent);
/* do not change the order of execution as the indentation event will fail when completer is on */
if (mpCompleter && mpCompleter->popup()->isVisible()) {
// The following keys are forwarded by the completer to the widget
switch (pEvent->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Tab:
case Qt::Key_Backtab:
pEvent->ignore();
return; // let the completer do default behavior
default:
break;
}
}
if (!mpCompleter || !isShortcut) // do not process the shortcut when we have a completer
QPlainTextEdit::keyPressEvent(pEvent);

/* If user has pressed enter then a new line is inserted.
* Indent the new line based on the indentation of previous line.
*/

/*! @todo We should add formatter classes to handle this based on editor language i.e Modelica or C/C++. */
if (pEvent->key() == Qt::Key_Enter || pEvent->key() == Qt::Key_Return) {
TabSettings tabSettings = OptionsDialog::instance()->getTabSettings();
Expand All @@ -1454,6 +1554,26 @@ void PlainTextEdit::keyPressEvent(QKeyEvent *pEvent)
cursor.endEditBlock();
setTextCursor(cursor);
}

const bool ctrlOrShift = pEvent->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
if (!mpCompleter || (ctrlOrShift && pEvent->text().isEmpty()))
return;

static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
bool hasModifier = (pEvent->modifiers() != Qt::NoModifier) && !ctrlOrShift;
QString completionPrefix = textUnderCursor();
if (!isShortcut && (hasModifier || pEvent->text().isEmpty()|| completionPrefix.length() < 3
|| eow.contains(pEvent->text().right(1)))) {
mpCompleter->popup()->hide();
return;
}

if (completionPrefix != mpCompleter->completionPrefix()) {
mpCompleter->setCompletionPrefix(completionPrefix);
mpCompleter->popup()->setCurrentIndex(mpCompleter->completionModel()->index(0, 0));
}
//pop up the completer according to editor instance
mpBaseEditor->popUpCompleter();
}

/*!
Expand Down
13 changes: 12 additions & 1 deletion OMEdit/OMEditGUI/Editors/BaseEditor.h
Expand Up @@ -41,6 +41,7 @@
#include <QLineEdit>
#include <QCheckBox>
#include <QToolButton>
#include <QStandardItemModel>

class ModelWidget;
class InfoBar;
Expand Down Expand Up @@ -210,25 +211,31 @@ class BaseEditorDocumentLayout : public QPlainTextDocumentLayout
};

class BaseEditor;
class QCompleter;
class PlainTextEdit : public QPlainTextEdit
{
Q_OBJECT
public:
PlainTextEdit(BaseEditor *pBaseEditor);
LineNumberArea* getLineNumberArea() {return mpLineNumberArea;}
void insertCompleterKeywords(QStringList keywords);
void insertCompleterTypes(QStringList types);
void setCompleter();
void setCanHaveBreakpoints(bool canHaveBreakpoints);
bool canHaveBreakpoints() {return mCanHaveBreakpoints;}
int lineNumberAreaWidth();
void lineNumberAreaPaintEvent(QPaintEvent *event);
void lineNumberAreaMouseEvent(QMouseEvent *event);
void goToLineNumber(int lineNumber);
QCompleter *completer();
private:
QStandardItemModel* mpStandardItemModel;
QCompleter *mpCompleter;
BaseEditor *mpBaseEditor;
LineNumberArea *mpLineNumberArea;
bool mCanHaveBreakpoints;
QTextCharFormat mParenthesesMatchFormat;
QTextCharFormat mParenthesesMisMatchFormat;

void highlightCurrentLine();
void highlightParentheses();
void setLineWrapping();
Expand All @@ -241,6 +248,9 @@ class PlainTextEdit : public QPlainTextEdit
void foldOrUnfold(bool unFold);
void handleHomeKey(bool keepAnchor);
void toggleBlockVisible(const QTextBlock &block);
QString textUnderCursor() const;
private slots:
void insertCompletion(const QString &completion);
public slots:
void updateLineNumberAreaWidth(int newBlockCount);
void updateLineNumberArea(const QRect &rect, int dy);
Expand Down Expand Up @@ -278,6 +288,7 @@ class BaseEditor : public QWidget
QAction* getUnFoldAllAction() {return mpUnFoldAllAction;}
DocumentMarker* getDocumentMarker() {return mpDocumentMarker;}
void setForceSetPlainText(bool forceSetPlainText) {mForceSetPlainText = forceSetPlainText;}
virtual void popUpCompleter () = 0;
private:
void initialize();
void createActions();
Expand Down
113 changes: 72 additions & 41 deletions OMEdit/OMEditGUI/Editors/CEditor.cpp
Expand Up @@ -34,13 +34,17 @@
#include "CEditor.h"
#include "Modeling/ModelWidgetContainer.h"
#include "Options/OptionsDialog.h"

#include <QCompleter>
#include <QMenu>

CEditor::CEditor(QWidget *pParent)
: BaseEditor(pParent)
{

QStringList keywords = CHighlighter::getKeywords();
QStringList types = CHighlighter::getTypes();
mpPlainTextEdit->insertCompleterKeywords(keywords);
mpPlainTextEdit->insertCompleterTypes(types);
mpPlainTextEdit->setCompleter();
}

/*!
Expand All @@ -58,6 +62,18 @@ void CEditor::setPlainText(const QString &text)
}
}

/*!
* \brief CEditor::popUpCompleter()
* \pop up the C keywords and types to the completer in the editor
*/
void CEditor::popUpCompleter()
{
QCompleter *completer = mpPlainTextEdit->completer();
QRect cr = mpPlainTextEdit->cursorRect();
cr.setWidth(completer->popup()->sizeHintForColumn(0)+ completer->popup()->verticalScrollBar()->sizeHint().width());
completer->complete(cr);
}

/*!
* \brief CEditor::showContextMenu
* Create a context menu.
Expand Down Expand Up @@ -127,55 +143,70 @@ void CHighlighter::initializeSettings()
rule.mFormat = mTextFormat;
mHighlightingRules.append(rule);
// keywords
QStringList keywordPatterns;
keywordPatterns << "\\bauto\\b"
<< "\\bbreak\\b"
<< "\\bcase\\b"
<< "\\bconst\\b"
<< "\\bcontinue\\b"
<< "\\bdefault\\b"
<< "\\bdo\\b"
<< "\\belse\\b"
<< "\\benum\\b"
<< "\\bextern\\b"
<< "\\bfor\\b"
<< "\\bgoto\\b"
<< "\\bif\\b"
<< "\\blong\\b"
<< "\\bregister\\b"
<< "\\breturn\\b"
<< "\\bshort\\b"
<< "\\bsigned\\b"
<< "\\bsizeof\\b"
<< "\\bstatic\\b"
<< "\\bclass\\b"
<< "\\bstruct\\b"
<< "\\bswitch\\b"
<< "\\btypedef\\b"
<< "\\bunion\\b"
<< "\\bunsigned\\b"
<< "\\bvoid\\b"
<< "\\bvolatile\\b"
<< "\\bwhile\\b";
QStringList keywordPatterns = getKeywords();
foreach (const QString &pattern, keywordPatterns) {
rule.mPattern = QRegExp(pattern);
QString newPattern = QString("\\b%1\\b").arg(pattern);
rule.mPattern = QRegExp(newPattern);
rule.mFormat = mKeywordFormat;
mHighlightingRules.append(rule);
}
// Modelica types
QStringList typePatterns;
typePatterns << "\\bchar\\b"
<< "\\bdouble\\b"
<< "\\bint\\b"
<< "\\bdouble\\b"
<< "\\bfloat\\b";
// types
QStringList typePatterns = getTypes();
foreach (const QString &pattern, typePatterns) {
rule.mPattern = QRegExp(pattern);
QString newPattern = QString("\\b%1\\b").arg(pattern);
rule.mPattern = QRegExp(newPattern);
rule.mFormat = mTypeFormat;
mHighlightingRules.append(rule);
}
}

// Function which returns list of keywords for the highlighter
QStringList CHighlighter::getKeywords()
{
QStringList keywordsList;
keywordsList << "auto"
<< "break"
<< "case"
<< "const"
<< "continue"
<< "default"
<< "do"
<< "else"
<< "enum"
<< "extern"
<< "for"
<< "goto"
<< "if"
<< "long"
<< "register"
<< "return"
<< "short"
<< "signed"
<< "sizeof"
<< "static"
<< "class"
<< "struct"
<< "switch"
<< "typedef"
<< "union"
<< "unsigned"
<< "void"
<< "volatile"
<< "while";
return keywordsList;
}

// Function which returns list of types for the highlighter
QStringList CHighlighter::getTypes()
{
QStringList typesList;
typesList << "char"
<< "double"
<< "int"
<< "float";
return typesList;
}

//! Highlights the multilines text.
//! Quoted text or multiline comments.
void CHighlighter::highlightMultiLine(const QString &text)
Expand Down

0 comments on commit c57868f

Please sign in to comment.