Logo Search packages:      
Sourcecode: ktikz version File versions  Download package

tikzeditorview.cpp

/***************************************************************************
 *   Copyright (C) 2008, 2009, 2010 by Glad Deschrijver                    *
 *     <glad.deschrijver@gmail.com>                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include "tikzeditorview.h"

#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <QMessageBox>
#include <QPointer>
#include <QSettings>
#include <QTextCursor>
#include <QToolBar>

#include "editgotolinewidget.h"
#include "editindentdialog.h"
#include "editreplacewidget.h"
#include "editreplacecurrentwidget.h"
#include "tikzeditor.h"
//#include "tikzeditorhighlighter.h"
#include "../common/utils/action.h"
#include "../common/utils/icon.h"
#include "../common/utils/standardaction.h"

TikzEditorView::TikzEditorView(QWidget *parent) : QWidget(parent)
{
      m_parentWidget = parent;

      m_tikzEditor = new TikzEditor;
      m_tikzEditor->setWhatsThis(tr("<p>Enter your TikZ code here.  "
          "The code should begin with \\begin{tikzpicture} and end with "
          "\\end{tikzpicture}.</p>"));
/*
      commandInserter = new TikzCommandInserter(tikzEditor, this);
      tikzHighlighter = new TikzHighlighter(commandInserter, tikzEditor->document());
      tikzHighlighter->rehighlight(); // avoid that textEdit emits the signal contentsChanged() when it is still empty
      tikzController = new TikzPngPreviewer(textEdit);
*/

      m_replaceWidget = new ReplaceWidget(this);
      m_replaceWidget->setVisible(false);
      m_replaceCurrentWidget = new ReplaceCurrentWidget(this);
      m_replaceCurrentWidget->setVisible(false);

      m_goToLineWidget = new GoToLineWidget(this);
      m_goToLineWidget->setVisible(false);

//    QFrame *mainWidget = new QFrame;
//    mainWidget->setLineWidth(1);
//    mainWidget->setFrameShape(QFrame::StyledPanel);
//    mainWidget->setFrameShadow(QFrame::Sunken);
      QVBoxLayout *mainLayout = new QVBoxLayout(this);
      mainLayout->setSpacing(0);
      mainLayout->setMargin(0);
      mainLayout->addWidget(m_tikzEditor);
      mainLayout->addWidget(m_replaceWidget);
      mainLayout->addWidget(m_replaceCurrentWidget);
      mainLayout->addWidget(m_goToLineWidget);

      createActions();

      connect(m_tikzEditor->document(), SIGNAL(modificationChanged(bool)),
              this, SIGNAL(modificationChanged(bool)));
      connect(m_tikzEditor->document(), SIGNAL(contentsChanged()),
              this, SIGNAL(contentsChanged()));
      connect(m_tikzEditor, SIGNAL(cursorPositionChanged(int,int)),
              this, SIGNAL(cursorPositionChanged(int,int)));
      connect(m_tikzEditor, SIGNAL(showStatusMessage(QString,int)),
              this, SIGNAL(showStatusMessage(QString,int)));

      connect(m_tikzEditor, SIGNAL(focusIn()),
              this, SIGNAL(focusIn()));
      connect(m_tikzEditor, SIGNAL(focusOut()),
              this, SIGNAL(focusOut()));

      connect(m_replaceWidget, SIGNAL(search(QString,bool,bool,bool)),
              this, SLOT(search(QString,bool,bool,bool)));
      connect(m_replaceWidget, SIGNAL(replace(QString,QString,bool,bool,bool)),
              this, SLOT(replace(QString,QString,bool,bool,bool)));
      connect(m_replaceWidget, SIGNAL(focusEditor()),
              m_tikzEditor, SLOT(setFocus()));

      connect(m_replaceCurrentWidget, SIGNAL(showReplaceWidget()),
              m_replaceWidget, SLOT(show()));
      connect(m_replaceCurrentWidget, SIGNAL(search(QString,bool,bool,bool,bool)),
              this, SLOT(search(QString,bool,bool,bool,bool)));
      connect(m_replaceCurrentWidget, SIGNAL(replace(QString)),
              this, SLOT(replace(QString)));
      connect(m_replaceCurrentWidget, SIGNAL(replaceAll(QString,QString,bool,bool,bool,bool)),
              this, SLOT(replaceAll(QString,QString,bool,bool,bool,bool)));
      connect(m_replaceCurrentWidget, SIGNAL(setSearchFromBegin(bool)),
              this, SIGNAL(setSearchFromBegin(bool)));

      connect(m_goToLineWidget, SIGNAL(goToLine(int)),
              this, SLOT(goToLine(int)));
}

TikzEditorView::~TikzEditorView()
{
//    tikzHighlighter->deleteLater();
}

QPlainTextEdit *TikzEditorView::editor()
{
      return m_tikzEditor;
}

void TikzEditorView::setFont(const QFont &editorFont)
{
      m_tikzEditor->setFont(editorFont);
      m_tikzEditor->setTabStopWidth(m_tikzEditor->fontMetrics().width("    "));
}

void TikzEditorView::createActions()
{
      m_undoAction = StandardAction::undo(m_tikzEditor, SLOT(undo()), this);
      m_redoAction = StandardAction::redo(m_tikzEditor, SLOT(redo()), this);
      m_cutAction = StandardAction::cut(m_tikzEditor, SLOT(cut()), this);
      m_copyAction = StandardAction::copy(m_tikzEditor, SLOT(copy()), this);
      m_pasteAction = StandardAction::paste(m_tikzEditor, SLOT(paste()), this);
      m_selectAllAction = StandardAction::selectAll(m_tikzEditor, SLOT(selectAll()), this);
      m_undoAction->setStatusTip(tr("Undo the previous action"));
      m_redoAction->setStatusTip(tr("Redo the previous undone action"));
      m_cutAction->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
      m_copyAction->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
      m_pasteAction->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
      m_selectAllAction->setStatusTip(tr("Select all the content"));
      m_undoAction->setWhatsThis(tr("<p>Undo the previous action.</p>"));
      m_redoAction->setWhatsThis(tr("<p>Redo the previous undone action.</p>"));
      m_cutAction->setWhatsThis(tr("<p>Cut the current selection's contents to the clipboard.</p>"));
      m_copyAction->setWhatsThis(tr("<p>Copy the current selection's contents to the clipboard.</p>"));
      m_pasteAction->setWhatsThis(tr("<p>Paste the clipboard's contents into the current selection.</p>"));
      m_selectAllAction->setWhatsThis(tr("<p>Select all the content.</p>"));

      Action *action;
      action = new Action(Icon("format-indent-more"), tr("&Indent..."), this, "edit_indent");
      action->setShortcut(tr("Ctrl+I", "Edit|Indent"));
      action->setStatusTip(tr("Indent the current line or selection"));
      action->setWhatsThis(tr("<p>Indent the current line or selection.</p>"));
      connect(action, SIGNAL(triggered()), this, SLOT(editIndent()));
      m_editActions.append(action);

      action = new Action(tr("C&omment"), this, "edit_comment");
      action->setShortcut(tr("Ctrl+D", "Edit|Comment"));
      action->setStatusTip(tr("Comment the current line or selection"));
      action->setWhatsThis(tr("<p>Comment the current line or selection.</p>"));
      connect(action, SIGNAL(triggered()), this, SLOT(editComment()));
      m_editActions.append(action);

      action = new Action(tr("Unco&mment"), this, "edit_uncomment");
      action->setShortcut(tr("Ctrl+Shift+D", "Edit|Uncomment"));
      action->setStatusTip(tr("Uncomment the current line or selection"));
      action->setWhatsThis(tr("<p>Uncomment the current line or selection.</p>"));
      connect(action, SIGNAL(triggered()), this, SLOT(editUncomment()));
      m_editActions.append(action);

      action = new Action(this);
      action->setSeparator(true);
      m_editActions.append(action);

      m_editActions.append(StandardAction::find(this, SLOT(editFind()), this));
      m_editActions.append(StandardAction::findNext(this, SLOT(editFindNext()), this));
      m_editActions.append(StandardAction::findPrev(this, SLOT(editFindPrevious()), this));
      m_editActions.append(StandardAction::replace(this, SLOT(editReplace()), this));
      m_editActions.append(StandardAction::gotoLine(this, SLOT(editGoToLine()), this));
      m_editActions.at(4)->setStatusTip(tr("Look up a piece of text in the document"));
      m_editActions.at(5)->setStatusTip(tr("Search the next occurrence of a text"));
      m_editActions.at(6)->setStatusTip(tr("Search the previous occurrence of a text"));
      m_editActions.at(7)->setStatusTip(tr("Search and replace a piece of text in the document"));
      m_editActions.at(8)->setStatusTip(tr("Go to a certain line in the document"));
      m_editActions.at(4)->setWhatsThis(tr("<p>Look up a piece of text in the document.</p>"));
      m_editActions.at(5)->setWhatsThis(tr("<p>Search the next occurrence of a text.</p>"));
      m_editActions.at(6)->setWhatsThis(tr("<p>Search the previous occurrence of a text.</p>"));
      m_editActions.at(7)->setWhatsThis(tr("<p>Search and replace a piece of text in the document.</p>"));
      m_editActions.at(8)->setWhatsThis(tr("<p>Go to a certain line in the document.</p>"));

      m_undoAction->setEnabled(false);
      m_redoAction->setEnabled(false);
      m_cutAction->setEnabled(false);
      m_copyAction->setEnabled(false);
      m_pasteAction->setEnabled(m_tikzEditor->canPaste());

      connect(m_tikzEditor, SIGNAL(undoAvailable(bool)),
              m_undoAction, SLOT(setEnabled(bool)));
      connect(m_tikzEditor, SIGNAL(redoAvailable(bool)),
              m_redoAction, SLOT(setEnabled(bool)));
      connect(m_tikzEditor, SIGNAL(copyAvailable(bool)),
              m_cutAction, SLOT(setEnabled(bool)));
      connect(m_tikzEditor, SIGNAL(copyAvailable(bool)),
              m_copyAction, SLOT(setEnabled(bool)));
      connect(QApplication::clipboard(), SIGNAL(dataChanged()),
              this, SLOT(setPasteEnabled()));
}

QMenu *TikzEditorView::menu()
{
      QMenu *editMenu = new QMenu(tr("&Edit"), m_parentWidget);
      editMenu->addAction(m_undoAction);
      editMenu->addAction(m_redoAction);
      editMenu->addSeparator();
      editMenu->addAction(m_cutAction);
      editMenu->addAction(m_copyAction);
      editMenu->addAction(m_pasteAction);
      editMenu->addSeparator();
      editMenu->addAction(m_selectAllAction);
      editMenu->addSeparator();
      editMenu->addActions(m_editActions);
      return editMenu;
}

QToolBar *TikzEditorView::toolBar()
{
      QToolBar *editToolBar = new QToolBar(tr("Edit"), m_parentWidget);
      editToolBar->setObjectName("EditToolBar");
      editToolBar->addAction(m_undoAction);
      editToolBar->addAction(m_redoAction);
//    editToolBar->addAction(m_cutAction);
//    editToolBar->addAction(m_copyAction);
//    editToolBar->addAction(m_pasteAction);
      return editToolBar;
}

void TikzEditorView::setPasteEnabled()
{
      m_pasteAction->setEnabled(m_tikzEditor->canPaste());
}

void TikzEditorView::applySettings()
{
      QSettings settings(ORGNAME, APPNAME);

      settings.beginGroup("Editor");
      QFont editorFont;
      editorFont.fromString(settings.value("Font", qApp->font().toString()).toString());
      setFont(editorFont);
      m_tikzEditor->setShowWhiteSpaces(settings.value("ShowWhiteSpaces", false).toBool());
      m_tikzEditor->setShowTabulators(settings.value("ShowTabulators", false).toBool());
      m_tikzEditor->setShowMatchingBrackets(settings.value("ShowMatchingBrackets", true).toBool());
      m_tikzEditor->setWhiteSpacesColor(settings.value("ColorWhiteSpaces", Qt::gray).value<QColor>());
      m_tikzEditor->setTabulatorsColor(settings.value("ColorTabulators", Qt::gray).value<QColor>());
      m_tikzEditor->setMatchingColor(settings.value("ColorMatchingBrackets", Qt::yellow).value<QColor>());
      settings.endGroup();

/*
      settings.beginGroup("Highlighting");
      customHighlighting = settings.value("Customize", true).toBool();
      QMap<QString, QTextCharFormat> formatList = tikzHighlighter->getDefaultHighlightFormats();
      if (customHighlighting)
      {
            int numOfRules = settings.value("Number", 0).toInt();
            for (int i = 0; i < numOfRules; ++i)
            {
                  QString name = settings.value("Item" + QString::number(i) + "/Name").toString();
                  QString colorName = settings.value("Item" + QString::number(i) + "/Color").toString();
                  QString fontName = settings.value("Item" + QString::number(i) + "/Font").toString();
                  QFont font;
                  font.fromString(fontName);
                  QTextCharFormat format;
                  format.setForeground(QBrush(QColor(colorName)));
                  format.setFont(font);
                  formatList[name] = format;
            }
      }
      settings.endGroup();

      tikzHighlighter->setTextCharFormats(formatList);
      tikzHighlighter->rehighlight();
*/
}

/***************************************************************************/

/*
void TikzEditorView::showCursorPosition()
{
      QTextCursor cur = m_tikzEditor->textCursor();
      const int curPos = cur.position();
      cur.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
      emit cursorPositionChanged(cur.blockNumber() + 1, curPos - cur.position() + 1);
}
*/

/***************************************************************************/
/* Go to line */

void TikzEditorView::setLine(const QString &line)
{
      bool ok;
      const int lineNumber = line.toInt(&ok, 10);
      if (ok) setLine(lineNumber);
}


void TikzEditorView::setLine(int lineNumber)
{
      m_replaceWidget->setVisible(false);
      m_goToLineWidget->setVisible(true);
      m_goToLineWidget->setFocus();
      m_goToLineWidget->setMaximumValue(m_tikzEditor->numOfLines());
      m_goToLineWidget->setValue(lineNumber);
}

void TikzEditorView::goToLine(int lineNumber)
{
      m_goToLineWidget->setVisible(false);
      m_tikzEditor->goToLine(lineNumber);
      m_tikzEditor->setFocus();
}

void TikzEditorView::editGoToLine()
{
      int lineNumber;
      lineNumber = m_tikzEditor->textCursor().blockNumber() + 1;
      if (lineNumber < 1)
            lineNumber = 1;
      setLine(lineNumber);
}

/***************************************************************************/

void TikzEditorView::editIndent()
{
      QPointer<IndentDialog> indentDialog = new IndentDialog(this, tr("Indent"));
      if (!indentDialog->exec())
      {
            delete indentDialog;
            return;
      }

      const QString insertString = indentDialog->insertChar();
      const int numOfInserts = indentDialog->numOfInserts();
      delete indentDialog;

      bool go = true;
      QTextCursor textCursor = m_tikzEditor->textCursor();
      if (textCursor.hasSelection())
      {
            textCursor.beginEditBlock();
            const int start = textCursor.selectionStart();
            int end = textCursor.selectionEnd();
            textCursor.setPosition(start, QTextCursor::MoveAnchor);
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            while (textCursor.position() < end && go)
            {
                  for (int i = 0; i < numOfInserts; ++i)
                        textCursor.insertText(insertString);
                  end++;
                  go = textCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor);
            }
            textCursor.endEditBlock();
      }
      else
      {
            textCursor.beginEditBlock();
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            for (int i = 0; i < numOfInserts; ++i)
                  textCursor.insertText(insertString);
            textCursor.endEditBlock();
      }
}

void TikzEditorView::editComment()
{
      bool go = true;
      QTextCursor textCursor = m_tikzEditor->textCursor();
      if (textCursor.hasSelection())
      {
            textCursor.beginEditBlock();
            const int start = textCursor.selectionStart();
            int end = textCursor.selectionEnd();
            textCursor.setPosition(start, QTextCursor::MoveAnchor);
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            while (textCursor.position() < end && go)
            {
                  textCursor.insertText("% ");
                  ++end;
                  ++end;
                  go = textCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor);
            }
            textCursor.endEditBlock();
      }
      else
      {
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            textCursor.insertText("% ");
      }
}

void TikzEditorView::editUncomment()
{
      bool go = true;
      QTextCursor textCursor = m_tikzEditor->textCursor();
      if (textCursor.hasSelection())
      {
            textCursor.beginEditBlock();
            const int start = textCursor.selectionStart();
            int end = textCursor.selectionEnd() - 2;
            textCursor.setPosition(start, QTextCursor::MoveAnchor);
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            while (textCursor.position() < end && go)
            {
                  textCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);
                  if (textCursor.selectedText() == QLatin1String("% "))
                  {
                        textCursor.removeSelectedText();
                        --end;
                  }
                  go = textCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor);
            }
            textCursor.endEditBlock();
      }
      else
      {
            textCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
            textCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);
            if (textCursor.selectedText() == QLatin1String("% "))
                  textCursor.removeSelectedText();
      }
}

/***************************************************************************/

void TikzEditorView::editFind()
{
      m_goToLineWidget->setVisible(false);
      m_replaceWidget->setVisible(true);
      m_replaceWidget->setFocus();
      const QTextCursor textCursor = m_tikzEditor->textCursor();
      if (textCursor.hasSelection())
            m_replaceWidget->setText(textCursor.selectedText());
}

bool TikzEditorView::search(const QString &text, bool isCaseSensitive,
    bool findWholeWords, bool forward, bool startAtCursor)
{
      bool isFound = false;

      QTextDocument::FindFlags flags = 0;
      if (isCaseSensitive) flags |= QTextDocument::FindCaseSensitively;
      if (findWholeWords) flags |= QTextDocument::FindWholeWords;

      QTextCursor textCursor = m_tikzEditor->textCursor();
      if (!startAtCursor)
      {
            if (forward) textCursor.movePosition(QTextCursor::Start);
            else textCursor.movePosition(QTextCursor::End);
            m_tikzEditor->setTextCursor(textCursor);
      }
      else
            textCursor.setPosition(textCursor.selectionStart());
      if (!forward) flags |= QTextDocument::FindBackward;
      else textCursor.movePosition(QTextCursor::Right);
      const QTextCursor found = m_tikzEditor->document()->find(text, textCursor, flags);

      if (found.isNull())
      {
            const QString msg = (forward) ?
                tr("End of document reached.\n\nContinue from the beginning?")
                : tr("Beginning of document reached.\n\nContinue from the end?");
            const int ret = QMessageBox::warning(this, "Find", msg,
                QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape);
            if (ret == QMessageBox::Yes)
            {
                  return search(text, isCaseSensitive, findWholeWords, forward, false);
            }
      }
      else
      {
            m_tikzEditor->setTextCursor(found);
            emit setSearchFromBegin(false);
            isFound = true;
      }
      m_tikzEditor->viewport()->repaint();
      return isFound;
}

void TikzEditorView::editFindNext()
{
      m_goToLineWidget->setVisible(false);
      m_replaceWidget->setVisible(true);
      m_replaceWidget->setFocus();
      m_replaceWidget->setForward(true);
      m_replaceWidget->doFind();
}

void TikzEditorView::editFindPrevious()
{
      m_goToLineWidget->setVisible(false);
      m_replaceWidget->setVisible(true);
      m_replaceWidget->setFocus();
      m_replaceWidget->setForward(false);
      m_replaceWidget->doFind();
}

void TikzEditorView::editReplace()
{
/*
      m_goToLineWidget->setVisible(false);
      m_replaceWidget->setVisible(true);
      m_replaceWidget->setFocus();
      const QTextCursor textCursor = m_tikzEditor->textCursor();
      if (textCursor.hasSelection())
            m_replaceWidget->setText(textCursor.selectedText());
*/
      editFind();
}

void TikzEditorView::replace(const QString &replacement)
{
      QTextCursor textCursor = m_tikzEditor->textCursor();

      if (textCursor.hasSelection())
      {
            const int start = textCursor.selectionStart();
            textCursor.beginEditBlock();
            textCursor.removeSelectedText();
            textCursor.insertText(replacement);
            textCursor.setPosition(start, QTextCursor::MoveAnchor);
            textCursor.setPosition(start + replacement.length(), QTextCursor::KeepAnchor);
            textCursor.endEditBlock();
            m_tikzEditor->setTextCursor(textCursor);
      }
}

void TikzEditorView::replace(const QString &text, const QString &replacement,
    bool isCaseSensitive, bool findWholeWords, bool forward, bool startAtCursor)
{
      m_replaceWidget->setVisible(false);
      m_replaceCurrentWidget->setReplacement(text, replacement);
      m_replaceCurrentWidget->setVisible(true);
      m_replaceCurrentWidget->search(text, replacement, isCaseSensitive, findWholeWords, forward, startAtCursor);
/*
      bool go = true;
      while (go && search(text, isCaseSensitive, findWholeWords, forward, startAtCursor))
      {
            switch(QMessageBox::warning(this, "Replace", tr("Replace this occurrence?"), QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
            {
                  case QMessageBox::Yes:
                        replace(replacement);
                        emit setSearchFromBegin(false);
                        break;
                  case QMessageBox::YesToAll:
                        replace(replacement);
                        replaceAll(text, replacement, isCaseSensitive, findWholeWords, forward, startAtCursor);
                        return;
                        break;
                  case QMessageBox::No:
                        emit setSearchFromBegin(false);
                        break;
                  case QMessageBox::Cancel:
                        go = false;
                        break;
                  default:
                        break;
            }
      }
      if (go)
            emit setSearchFromBegin(true);
*/
}

void TikzEditorView::replaceAll(const QString &text, const QString &replacement,
    bool isCaseSensitive, bool findWholeWords, bool forward, bool startAtCursor)
{
      while (search(text, isCaseSensitive, findWholeWords, forward, startAtCursor))
      {
            replace(replacement);
            emit setSearchFromBegin(false);
      }
      emit setSearchFromBegin(true);
}

void TikzEditorView::setCompleter(QCompleter *completer)
{
      m_tikzEditor->setCompleter(completer);
}

Generated by  Doxygen 1.6.0   Back to index