File indexing completed on 2024-05-12 16:36:08
0001 /* This file is part of the KDE project 0002 Copyright 1999-2006 The KSpread Team <calligra-devel@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "ExternalEditor.h" 0021 0022 // Sheets 0023 #include "CellEditor.h" 0024 #include "CellToolBase.h" 0025 #include "FormulaEditorHighlighter.h" 0026 #include "Map.h" 0027 #include "Sheet.h" 0028 #include "SheetsDebug.h" 0029 0030 // Calligra 0031 #include <KoIcon.h> 0032 0033 // Qt 0034 #include <QApplication> 0035 #include <QFontDatabase> 0036 #include <QFocusEvent> 0037 #include <QKeyEvent> 0038 0039 using namespace Calligra::Sheets; 0040 0041 class ExternalEditor::Private 0042 { 0043 public: 0044 CellToolBase* cellTool; 0045 FormulaEditorHighlighter* highlighter; 0046 bool isArray; 0047 QAction* applyAction; 0048 QAction* cancelAction; 0049 }; 0050 0051 ExternalEditor::ExternalEditor(QWidget *parent) 0052 : KTextEdit(parent) 0053 , d(new Private) 0054 { 0055 d->cellTool = 0; 0056 d->highlighter = 0; 0057 d->isArray = false; 0058 0059 setCurrentFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); 0060 0061 // Try to imitate KLineEdit regarding the margins and size. 0062 document()->setDocumentMargin(1); 0063 setMinimumHeight(fontMetrics().height() + 2 * frameWidth() + 1); 0064 0065 connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); 0066 connect(this, SIGNAL(cursorPositionChanged()), 0067 this, SLOT(slotCursorPositionChanged())); 0068 0069 d->applyAction = new QAction(koIcon("dialog-ok"), i18n("Apply"), this); 0070 d->applyAction->setToolTip(i18n("Apply changes")); 0071 d->applyAction->setEnabled(false); 0072 connect(d->applyAction, SIGNAL(triggered()), SLOT(applyChanges())); 0073 0074 d->cancelAction = new QAction(koIcon("dialog-cancel"), i18n("Cancel"), this); 0075 d->cancelAction->setToolTip(i18n("Discard changes")); 0076 d->cancelAction->setEnabled(false); 0077 connect(d->cancelAction, SIGNAL(triggered()), SLOT(discardChanges())); 0078 } 0079 0080 ExternalEditor::~ExternalEditor() 0081 { 0082 delete d->highlighter; 0083 delete d; 0084 } 0085 0086 QSize ExternalEditor::sizeHint() const 0087 { 0088 return minimumSize(); 0089 //return KTextEdit::sizeHint(); // document()->size().toSize(); 0090 } 0091 0092 void ExternalEditor::setCellTool(CellToolBase* cellTool) 0093 { 0094 if (d->highlighter) delete d->highlighter; 0095 d->cellTool = cellTool; 0096 d->highlighter = new FormulaEditorHighlighter(this, cellTool->selection()); 0097 } 0098 0099 void ExternalEditor::applyChanges() 0100 { 0101 Q_ASSERT(d->cellTool); 0102 d->cellTool->deleteEditor(true, d->isArray); // save changes 0103 d->isArray = false; 0104 } 0105 0106 void ExternalEditor::discardChanges() 0107 { 0108 Q_ASSERT(d->cellTool); 0109 clear(); 0110 d->cellTool->deleteEditor(false); // discard changes 0111 d->cellTool->selection()->update(); 0112 } 0113 0114 void ExternalEditor::setText(const QString &text) 0115 { 0116 Q_ASSERT(d->cellTool); 0117 if (toPlainText() == text) { 0118 return; 0119 } 0120 // This method is called from the embedded editor. Do not send signals back. 0121 blockSignals(true); 0122 KTextEdit::setPlainText(text); 0123 QTextCursor textCursor = this->textCursor(); 0124 textCursor.setPosition(d->cellTool->editor()->cursorPosition()); 0125 setTextCursor(textCursor); 0126 blockSignals(false); 0127 } 0128 0129 int ExternalEditor::cursorPosition() const 0130 { 0131 return textCursor().position(); 0132 } 0133 0134 void ExternalEditor::setCursorPosition(int pos) 0135 { 0136 QTextCursor textCursor(this->textCursor()); 0137 textCursor.setPosition(pos); 0138 setTextCursor(textCursor); 0139 } 0140 0141 void ExternalEditor::keyPressEvent(QKeyEvent *event) 0142 { 0143 Q_ASSERT(d->cellTool); 0144 if (!d->cellTool->selection()->activeSheet()->map()->isReadWrite()) { 0145 return; 0146 } 0147 0148 // Create the embedded editor, if necessary. 0149 if (!d->cellTool->editor()) { 0150 d->cellTool->createEditor(false /* keep content */, false /* no focus */, true /*capture arrows */); 0151 } 0152 0153 // the Enter and Esc key are handled by the embedded editor 0154 if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter) || 0155 (event->key() == Qt::Key_Escape)) { 0156 d->cellTool->editor()->widget()->setFocus(); 0157 QApplication::sendEvent(d->cellTool->editor()->widget(), event); 0158 event->accept(); 0159 return; 0160 } 0161 // call inherited handler 0162 KTextEdit::keyPressEvent(event); 0163 } 0164 0165 void ExternalEditor::focusInEvent(QFocusEvent* event) 0166 { 0167 Q_ASSERT(d->cellTool); 0168 // If the focussing is user induced. 0169 if (event->reason() != Qt::OtherFocusReason) { 0170 debugSheets << "induced by user"; 0171 d->cellTool->setLastEditorWithFocus(CellToolBase::ExternalEditor); 0172 } 0173 // when the external editor gets focus, create also the internal editor 0174 // this in turn means that ranges will be instantly highlighted right 0175 if (!d->cellTool->editor()) 0176 d->cellTool->createEditor(false /* keep content */, false /* no focus */, true /*capture arrows */); 0177 KTextEdit::focusInEvent(event); 0178 } 0179 0180 void ExternalEditor::focusOutEvent(QFocusEvent* event) 0181 { 0182 Q_ASSERT(d->cellTool); 0183 KTextEdit::focusOutEvent(event); 0184 } 0185 0186 void ExternalEditor::slotTextChanged() 0187 { 0188 if (!hasFocus()) return; // only report change if we have focus 0189 emit textChanged(toPlainText()); 0190 // Update the cursor position again, because this slot is invoked after 0191 // slotCursorPositionChanged(). 0192 if (d->cellTool->editor()) { 0193 d->cellTool->editor()->setCursorPosition(textCursor().position()); 0194 } 0195 } 0196 0197 void ExternalEditor::slotCursorPositionChanged() 0198 { 0199 if (!hasFocus() || !d->cellTool->editor()) { 0200 return; 0201 } 0202 // Suppress updates, if this slot got invoked by a text change. It is done 0203 // later by slotTextChanged(). 0204 if (d->cellTool->editor()->toPlainText() == toPlainText()) { 0205 d->cellTool->editor()->setCursorPosition(textCursor().position()); 0206 } 0207 } 0208 0209 QAction* ExternalEditor::applyAction() const 0210 { 0211 return d->applyAction; 0212 } 0213 0214 QAction* ExternalEditor::cancelAction() const 0215 { 0216 return d->cancelAction; 0217 }