1 /* This file is part of the KDE project
2 Copyright (C) 2005 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2004-2012 Jarosław Staniek <staniek@kde.org>
4 Copyright (C) 2014 Wojciech Kosowicz <pcellix@gmail.com>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "kexidbtextedit.h"
23 #include "kexidblineedit.h"
24 #include <kexiutils/utils.h>
25
26 #include <KDbQuerySchema>
27
28 #include <KStandardShortcut>
29
30 #include <QApplication>
31 #include <QPaintEvent>
32 #include <QPainter>
33 #include <QLabel>
34 #include <QMenu>
35 #include <QFontDatabase>
36
37 class DataSourceLabel : public QLabel
38 {
39 Q_OBJECT
40 public:
DataSourceLabel(QWidget * parent)41 explicit DataSourceLabel(QWidget *parent) : QLabel(parent)
42 {
43 }
44 protected:
paintEvent(QPaintEvent * pe)45 void paintEvent(QPaintEvent *pe)
46 {
47 QLabel::paintEvent(pe);
48 QPainter p(this);
49 int leftMargin, topMargin, rightMargin, bottomMargin;
50 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
51 QRect r( rect() );
52 r.setX(r.x() + leftMargin);
53 r.setY(r.y() + topMargin);
54 r.setRight(r.right() - rightMargin);
55 r.setBottom(r.bottom() - bottomMargin);
56 QPixmap dataSourceTagIcon;
57 int x;
58 if (layoutDirection() == Qt::LeftToRight) {
59 dataSourceTagIcon = KexiFormUtils::dataSourceTagIcon();
60 x = r.left() - 1;
61 }
62 else {
63 dataSourceTagIcon = KexiFormUtils::dataSourceRTLTagIcon();
64 x = r.right() - dataSourceTagIcon.width() - 5;
65 }
66 p.drawPixmap(
67 x, r.top() + (r.height() - dataSourceTagIcon.height()) / 2,
68 dataSourceTagIcon
69 );
70 }
71 };
72
73 // --------------
74
KexiDBTextEdit(QWidget * parent)75 KexiDBTextEdit::KexiDBTextEdit(QWidget *parent)
76 : KTextEdit(parent)
77 , KexiDBTextWidgetInterface()
78 , KexiFormDataItemInterface()
79 , m_menuExtender(this, this)
80 , m_slotTextChanged_enabled(true)
81 , m_dataSourceLabel(0)
82 , m_length(0)
83 , m_paletteChangeEvent_enabled(true)
84 {
85 QFont tmpFont;
86 tmpFont.setPointSize(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont).pointSize());
87 setMinimumHeight(QFontMetrics(tmpFont).height() + 6);
88 connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged()));
89 //hmm disabled again because this makes the widget disappear entirely
90 // setAutoFillBackground(true); // otherwise we get transparent background...
91 // installEventFilter(this);
92 setBackgroundRole(QPalette::Base);
93 setAcceptRichText(false);
94 }
95
~KexiDBTextEdit()96 KexiDBTextEdit::~KexiDBTextEdit()
97 {
98 }
99
setInvalidState(const QString & displayText)100 void KexiDBTextEdit::setInvalidState(const QString& displayText)
101 {
102 setReadOnly(true);
103 //! @todo move this to KexiDataItemInterface::setInvalidStateInternal() ?
104 if (focusPolicy() & Qt::TabFocus)
105 setFocusPolicy(Qt::ClickFocus);
106 KTextEdit::setPlainText(displayText);
107 }
108
setValueInternal(const QVariant & add,bool removeOld)109 void KexiDBTextEdit::setValueInternal(const QVariant& add, bool removeOld)
110 {
111 //! @todo how about rich text?
112 if (m_columnInfo && m_columnInfo->field()->type() == KDbField::Boolean) {
113 //! @todo temporary solution for booleans!
114 KTextEdit::setHtml(add.toBool() ? "1" : "0");
115 } else {
116 QString t;
117 if (removeOld) {
118 t = add.toString();
119 }
120 else {
121 t = KexiDataItemInterface::originalValue().toString() + add.toString();
122 }
123
124 if (acceptRichText()) {
125 KTextEdit::setHtml(t);
126 }
127 else {
128 KTextEdit::setPlainText(t);
129 }
130 }
131 }
132
value()133 QVariant KexiDBTextEdit::value()
134 {
135 return acceptRichText() ? toHtml() : toPlainText();
136 }
137
slotTextChanged()138 void KexiDBTextEdit::slotTextChanged()
139 {
140 if (!m_slotTextChanged_enabled)
141 return;
142
143 if (m_length > 0) {
144 QString t;
145 if (acceptRichText()) {
146 t = toHtml();
147 }
148 else {
149 t = toPlainText();
150 }
151 if (t.length() > (int)m_length) {
152 m_slotTextChanged_enabled = false;
153 if (acceptRichText()) {
154 //! @todo KEXI3 setHtml(t.left(m_length));
155 }
156 else {
157 setPlainText(t.left(m_length));
158 }
159 m_slotTextChanged_enabled = true;
160 moveCursorToEnd();
161 }
162 }
163
164 signalValueChanged();
165 }
166
valueIsNull()167 bool KexiDBTextEdit::valueIsNull()
168 {
169 return (acceptRichText() ? toHtml() : toPlainText()).isNull();
170 }
171
valueIsEmpty()172 bool KexiDBTextEdit::valueIsEmpty()
173 {
174 return (acceptRichText() ? toHtml() : toPlainText()).isEmpty();
175 }
176
isReadOnly() const177 bool KexiDBTextEdit::isReadOnly() const
178 {
179 return KTextEdit::isReadOnly();
180 }
181
setReadOnly(bool readOnly)182 void KexiDBTextEdit::setReadOnly(bool readOnly)
183 {
184 KTextEdit::setReadOnly(readOnly);
185 //! @todo KEXI3 KexiDBTextEdit::setReadOnly() - bg color
186 #if 0//TODO
187 QPalette p = palette();
188 QColor c(readOnly
189 ? KexiFormUtils::lighterGrayBackgroundColor(kapp->palette()) : p.color(QPalette::Active, QPalette::Base));
190 setPaper(c);
191 p.setColor(QPalette::Base, c);
192 p.setColor(QPalette::Background, c);
193 setPalette(p);
194 #endif
195 }
196
widget()197 QWidget* KexiDBTextEdit::widget()
198 {
199 return this;
200 }
201
cursorAtStart()202 bool KexiDBTextEdit::cursorAtStart()
203 {
204 return textCursor().atStart();
205 }
206
cursorAtEnd()207 bool KexiDBTextEdit::cursorAtEnd()
208 {
209 return textCursor().atEnd();
210 }
211
clear()212 void KexiDBTextEdit::clear()
213 {
214 document()->clear();
215 }
216
setColumnInfo(KDbConnection * conn,KDbQueryColumnInfo * cinfo)217 void KexiDBTextEdit::setColumnInfo(KDbConnection *conn, KDbQueryColumnInfo* cinfo)
218 {
219 KexiFormDataItemInterface::setColumnInfo(conn, cinfo);
220 if (!cinfo) {
221 m_length = 0;
222 return;
223 }
224
225 if (cinfo->field()->type() == KDbField::Text) {
226 if (!designMode()) {
227 if (cinfo->field()->maxLength() > 0) {
228 m_length = cinfo->field()->maxLength();
229 }
230 }
231 }
232
233 KexiDBTextWidgetInterface::setColumnInfo(m_columnInfo, this);
234 }
235
paintEvent(QPaintEvent * pe)236 void KexiDBTextEdit::paintEvent(QPaintEvent *pe)
237 {
238 KTextEdit::paintEvent(pe);
239 QPainter p(viewport());
240 //! @todo how about rich text?
241 KexiDBTextWidgetInterface::paint(this, &p, toPlainText().isEmpty(), alignment(), hasFocus());
242 }
243
contextMenuEvent(QContextMenuEvent * e)244 void KexiDBTextEdit::contextMenuEvent(QContextMenuEvent *e)
245 {
246 QMenu *menu = createStandardContextMenu();
247 m_menuExtender.exec(menu, e->globalPos());
248 delete menu;
249 }
250
undo()251 void KexiDBTextEdit::undo()
252 {
253 cancelEditor();
254 }
255
setDisplayDefaultValue(QWidget * widget,bool displayDefaultValue)256 void KexiDBTextEdit::setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue)
257 {
258 KexiFormDataItemInterface::setDisplayDefaultValue(widget, displayDefaultValue);
259 // initialize display parameters for default / entered value
260 KexiDisplayUtils::DisplayParameters * const params
261 = displayDefaultValue ? m_displayParametersForDefaultValue : m_displayParametersForEnteredValue;
262 QPalette pal(palette());
263 pal.setColor(QPalette::Active, QPalette::Text, params->textColor);
264 setPalette(pal);
265 setFont(params->font);
266 //! @todo support rich text...
267 /* m_slotTextChanged_enabled = false;
268 //for rich text...
269 const QString origText( text() );
270 KTextEdit::setText(QString());
271 setCurrentFont(params->font);
272 setColor(params->textColor);
273 KTextEdit::setText(origText);
274 m_slotTextChanged_enabled = true;*/
275 }
276
moveCursorToEnd()277 void KexiDBTextEdit::moveCursorToEnd()
278 {
279 moveCursor(QTextCursor::End);
280 }
281
moveCursorToStart()282 void KexiDBTextEdit::moveCursorToStart()
283 {
284 moveCursor(QTextCursor::Start);
285 }
286
selectAll()287 void KexiDBTextEdit::selectAll()
288 {
289 KTextEdit::selectAll();
290 }
291
keyPressEvent(QKeyEvent * ke)292 void KexiDBTextEdit::keyPressEvent(QKeyEvent *ke)
293 {
294 // for instance, Windows uses Ctrl+Tab for moving between tabs, so do not steal this shortcut
295 if (KStandardShortcut::tabNext().contains(QKeySequence(ke->key() | ke->modifiers()))
296 || KStandardShortcut::tabPrev().contains(QKeySequence(ke->key() | ke->modifiers()))) {
297 ke->ignore();
298 return;
299 }
300 KTextEdit::keyPressEvent(ke);
301 }
302
event(QEvent * e)303 bool KexiDBTextEdit::event(QEvent *e)
304 {
305 bool res = KTextEdit::event(e);
306
307 if (e->type() == QEvent::LayoutDirectionChange) {
308 if (m_dataSourceLabel) {
309 m_dataSourceLabel->setLayoutDirection( layoutDirection() );
310 }
311 updateTextForDataSource();
312 }
313 else if (e->type() == QEvent::Resize) {
314 if (m_dataSourceLabel) {
315 m_dataSourceLabel->setFixedWidth(width());
316 }
317 }
318 return res;
319 }
320
updateTextForDataSource()321 void KexiDBTextEdit::updateTextForDataSource()
322 {
323 if (!designMode()) {
324 if (m_dataSourceLabel) {
325 m_dataSourceLabel->hide();
326 }
327 return;
328 }
329 setPlainText(QString());
330 if (!m_dataSourceLabel && !dataSource().isEmpty()) {
331 createDataSourceLabel();
332 }
333 if (m_dataSourceLabel) {
334 m_dataSourceLabel->setText(dataSource());
335 m_dataSourceLabel->setIndent( KexiFormUtils::dataSourceTagIcon().width()
336 + (layoutDirection() == Qt::LeftToRight ? 0 : 7) );
337 m_dataSourceLabel->setVisible(!dataSource().isEmpty());
338 }
339 }
340
setDataSource(const QString & ds)341 void KexiDBTextEdit::setDataSource(const QString &ds)
342 {
343 KexiFormDataItemInterface::setDataSource(ds);
344 updateTextForDataSource();
345 }
346
setDataSourcePluginId(const QString & pluginId)347 void KexiDBTextEdit::setDataSourcePluginId(const QString &pluginId)
348 {
349 KexiFormDataItemInterface::setDataSourcePluginId(pluginId);
350 updateTextForDataSource();
351 }
352
createDataSourceLabel()353 void KexiDBTextEdit::createDataSourceLabel()
354 {
355 if (m_dataSourceLabel)
356 return;
357 m_dataSourceLabel = new DataSourceLabel(viewport());
358 m_dataSourceLabel->hide();
359 m_dataSourceLabel->move(0, 0);
360 int leftMargin, topMargin, rightMargin, bottomMargin;
361 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
362 m_dataSourceLabel->setContentsMargins(leftMargin, topMargin, rightMargin, bottomMargin);
363 }
364
selectAllOnFocusIfNeeded()365 void KexiDBTextEdit::selectAllOnFocusIfNeeded()
366 {
367 }
368
focusOutEvent(QFocusEvent * e)369 void KexiDBTextEdit::focusOutEvent(QFocusEvent *e)
370 {
371 KTextEdit::focusOutEvent(e);
372 if (textCursor().hasSelection()) {
373 moveCursorToEnd();
374 }
375 }
376
updatePalette()377 void KexiDBTextEdit::updatePalette()
378 {
379 m_paletteChangeEvent_enabled = false;
380 setPalette(isReadOnly() ?
381 KexiUtils::paletteForReadOnly(m_originalPalette)
382 : m_originalPalette);
383 m_paletteChangeEvent_enabled = true;
384 }
385
changeEvent(QEvent * e)386 void KexiDBTextEdit::changeEvent(QEvent *e)
387 {
388 if (e->type() == QEvent::PaletteChange && m_paletteChangeEvent_enabled) {
389 m_originalPalette = palette();
390 updatePalette();
391 }
392 KTextEdit::changeEvent(e);
393 }
394
395 #include "kexidbtextedit.moc"
396