/* * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Swift { QtTextEdit::QtTextEdit(SettingsProvider* settings, QWidget* parent) : QTextEdit(parent), checker_(NULL), highlighter_(NULL) { connect(this, SIGNAL(textChanged()), this, SLOT(handleTextChanged())); settings_ = settings; #ifdef HAVE_SPELLCHECKER setUpSpellChecker(); #endif handleTextChanged(); } QtTextEdit::~QtTextEdit() { delete checker_; } void QtTextEdit::keyPressEvent(QKeyEvent* event) { int key = event->key(); Qt::KeyboardModifiers modifiers = event->modifiers(); if ((key == Qt::Key_Enter || key == Qt::Key_Return) && (modifiers == Qt::NoModifier || modifiers == Qt::KeypadModifier)) { emit returnPressed(); } else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier) || (key == Qt::Key_C && modifiers == Qt::ControlModifier && textCursor().selectedText().isEmpty()) || (key == Qt::Key_W && modifiers == Qt::ControlModifier) || (key == Qt::Key_PageUp && modifiers == Qt::ControlModifier) || (key == Qt::Key_PageDown && modifiers == Qt::ControlModifier) || (key == Qt::Key_Tab && modifiers == Qt::ControlModifier) || (key == Qt::Key_A && modifiers == Qt::AltModifier) || (key == Qt::Key_Tab) ) { emit unhandledKeyPressEvent(event); } else if ((key == Qt::Key_Up) || (key == Qt::Key_Down)) { emit unhandledKeyPressEvent(event); QTextEdit::keyPressEvent(event); } else if ((key == Qt::Key_K && modifiers == QtUtilities::ctrlHardwareKeyModifier)) { QTextCursor cursor = textCursor(); cursor.setPosition(toPlainText().size(), QTextCursor::KeepAnchor); cursor.removeSelectedText(); } else { QTextEdit::keyPressEvent(event); } } void QtTextEdit::handleTextChanged() { QSize previous(maximumSize()); setMaximumSize(QSize(maximumWidth(), sizeHint().height())); if (previous != maximumSize()) { updateGeometry(); } } void QtTextEdit::replaceMisspelledWord(const QString& word, int cursorPosition) { QTextCursor cursor = textCursor(); PositionPair wordPosition = getWordFromCursor(cursorPosition); cursor.setPosition(boost::get<0>(wordPosition), QTextCursor::MoveAnchor); cursor.setPosition(boost::get<1>(wordPosition), QTextCursor::KeepAnchor); QTextCharFormat normalFormat; cursor.insertText(word, normalFormat); } PositionPair QtTextEdit::getWordFromCursor(int cursorPosition) { PositionPairList misspelledPositions = highlighter_->getMisspelledPositions(); for (PositionPairList::iterator it = misspelledPositions.begin(); it != misspelledPositions.end(); ++it) { if (cursorPosition >= boost::get<0>(*it) && cursorPosition <= boost::get<1>(*it)) { return *it; } } return boost::make_tuple(-1,-1); } QSize QtTextEdit::sizeHint() const { QFontMetrics inputMetrics(currentFont()); QRect horizontalBounds = contentsRect().adjusted(0,0,0,9999); QRect boundingRect = inputMetrics.boundingRect(horizontalBounds, Qt::TextWordWrap, toPlainText() + "A"); int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); int height = boundingRect.height() + top + bottom + inputMetrics.height(); return QSize(width(), height); //int numberOfLines = 1; //int lineHeight = inputMetrics.lineSpacing(); //return QSize(QTextEdit::sizeHint().width(), lineHeight * numberOfLines); } void QtTextEdit::contextMenuEvent(QContextMenuEvent* event) { QMenu* menu = createStandardContextMenu(); QTextCursor cursor = cursorForPosition(event->pos()); #ifdef HAVE_SPELLCHECKER QAction* insertPoint = menu->actions().first(); QAction* settingsAction = new QAction(tr("Spell Checker Options"), menu); menu->insertAction(insertPoint, settingsAction); menu->insertAction(insertPoint, menu->addSeparator()); addSuggestions(menu, event); QAction* result = menu->exec(event->globalPos()); if (result == settingsAction) { spellCheckerSettingsWindow(); } for (std::vector::iterator it = replaceWordActions_.begin(); it != replaceWordActions_.end(); ++it) { if (*it == result) { replaceMisspelledWord((*it)->text(), cursor.position()); } } #else menu->exec(event->globalPos()); #endif delete menu; } void QtTextEdit::addSuggestions(QMenu* menu, QContextMenuEvent* event) { replaceWordActions_.clear(); QAction* insertPoint = menu->actions().first(); QTextCursor cursor = cursorForPosition(event->pos()); PositionPair wordPosition = getWordFromCursor(cursor.position()); if (boost::get<0>(wordPosition) < 0) { // The click was executed outside a spellable word so no // suggestions are necessary return; } cursor.setPosition(boost::get<0>(wordPosition), QTextCursor::MoveAnchor); cursor.setPosition(boost::get<1>(wordPosition), QTextCursor::KeepAnchor); std::vector wordList; checker_->getSuggestions(Q2PSTRING(cursor.selectedText()), wordList); if (wordList.size() == 0) { QAction* noSuggestions = new QAction(tr("No Suggestions"), menu); noSuggestions->setDisabled(true); menu->insertAction(insertPoint, noSuggestions); } else { for (std::vector::iterator it = wordList.begin(); it != wordList.end(); ++it) { QAction* wordAction = new QAction(it->c_str(), menu); menu->insertAction(insertPoint, wordAction); replaceWordActions_.push_back(wordAction); } } menu->insertAction(insertPoint, menu->addSeparator()); } #ifdef HAVE_SPELLCHECKER void QtTextEdit::setUpSpellChecker() { delete checker_; checker_ = NULL; if (settings_->getSetting(SettingConstants::SPELL_CHECKER)) { std::string dictPath = settings_->getSetting(SettingConstants::DICT_PATH); std::string dictFile = settings_->getSetting(SettingConstants::DICT_FILE); checker_ = SpellCheckerFactory().createSpellChecker(dictPath + dictFile); delete highlighter_; highlighter_ = NULL; highlighter_ = new QtSpellCheckHighlighter(document(), checker_); } } #endif void QtTextEdit::spellCheckerSettingsWindow() { if (!spellCheckerWindow_) { spellCheckerWindow_ = new QtSpellCheckerWindow(settings_); settings_->onSettingChanged.connect(boost::bind(&QtTextEdit::handleSettingChanged, this, _1)); spellCheckerWindow_->show(); } else { spellCheckerWindow_->show(); spellCheckerWindow_->raise(); spellCheckerWindow_->activateWindow(); } } void QtTextEdit::handleSettingChanged(const std::string& settings) { if (settings == SettingConstants::SPELL_CHECKER.getKey() || settings == SettingConstants::DICT_PATH.getKey() || settings == SettingConstants::DICT_FILE.getKey()) { #ifdef HAVE_SPELLCHECKER setUpSpellChecker(); highlighter_->rehighlight(); #endif } } }