1 /***************************************************************************
2 * Copyright (C) 2008 by Simon Andreas Eugster (simon.eu@gmail.com) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 ***************************************************************************/
10 #include "unicodedialog.h"
12 #include <QWheelEvent>
16 const int MAX_LENGTH_HEX = 4;
17 const uint MAX_UNICODE_V1 = 65535;
20 /// CONSTRUCTORS/DECONSTRUCTORS
22 UnicodeDialog::UnicodeDialog(InputMethod inputMeth) :
23 inputMethod(inputMeth),
29 connect(unicodeNumber, SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString)));
30 connect(unicodeNumber, SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
31 connect(arrowUp, SIGNAL(clicked()), this, SLOT(slotPrevUnicode()));
32 connect(arrowDown, SIGNAL(clicked()), this, SLOT(slotNextUnicode()));
34 switch (inputMethod) {
36 unicodeNumber->setMaxLength(MAX_LENGTH_HEX);
43 arrowUp->setShortcut(Qt::Key_Up);
44 arrowDown->setShortcut(Qt::Key_Down);
45 unicode_link->setText(i18n("Information about unicode characters: <a href=\"http://decodeunicode.org\">http://decodeunicode.org</a>"));
46 arrowUp->setToolTip(i18n("Previous Unicode character (Arrow Up)"));
47 arrowDown->setToolTip(i18n("Next Unicode character (Arrow Down)"));
48 unicodeNumber->setToolTip(i18n("Enter your Unicode number here. Allowed characters: [0-9] and [a-f]."));
49 unicodeNumber->selectAll(); // Selection will be reset by setToolTip and similar, so set it here
53 UnicodeDialog::~UnicodeDialog()
60 int UnicodeDialog::exec()
62 unicodeNumber->setFocus();
63 return QDialog::exec();
69 void UnicodeDialog::showLastUnicode()
71 unicodeNumber->setText(m_lastUnicodeNumber);
72 unicodeNumber->selectAll();
73 slotTextChanged(m_lastUnicodeNumber);
76 bool UnicodeDialog::controlCharacter(QString text)
78 bool isControlCharacter = false;
79 QString t = text.toLower();
81 switch (inputMethod) {
84 || (t.length() == 1 && !(t == "9" || t == "a" || t == "d"))
85 || (t.length() == 2 && t.at(0) == QChar('1'))) {
86 isControlCharacter = true;
92 isControlCharacter = controlCharacter(text.toUInt(&ok, 16));
96 return isControlCharacter;
99 bool UnicodeDialog::controlCharacter(uint value)
101 bool isControlCharacter = false;
103 if (value < 32 && !(value == 9 || value == 10 || value == 13)) {
104 isControlCharacter = true;
106 return isControlCharacter;
110 QString UnicodeDialog::trimmedUnicodeNumber(QString text)
112 while (text.length() > 0 && text.at(0) == QChar('0')) {
113 text = text.remove(0, 1);
118 QString UnicodeDialog::unicodeInfo(QString unicode)
120 QString infoText(i18n("<small>(no character selected)</small>"));
121 if (unicode.length() == 0) return infoText;
123 QString u = trimmedUnicodeNumber(unicode).toLower();
125 if (controlCharacter(u)) {
126 infoText = i18n("Control character. Cannot be inserted/printed. See <a href=\"http://en.wikipedia.org/wiki/Control_character\">Wikipedia:Control_character</a>");
127 } else if (u == "a") {
128 infoText = i18n("Line Feed (newline character, \\\\n)");
129 } else if (u == "20") {
130 infoText = i18n("Standard space character. (Other space characters: U+00a0, U+2000–200b, U+202f)");
131 } else if (u == "a0") {
132 infoText = i18n("No-break space. &nbsp; in HTML. See U+2009 and U+0020.");
133 } else if (u == "ab" || u == "bb" || u == "2039" || u == "203a") {
134 infoText = i18n("<p><strong>«</strong> (u+00ab, <code>&lfquo;</code> in HTML) and <strong>»</strong> (u+00bb, <code>&rfquo;</code> in HTML) are called Guillemets or angle quotes. Usage in different countries: France (with non-breaking Space 0x00a0), Switzerland, Germany, Finland and Sweden.</p><p><strong>‹</strong> and <strong>›</strong> (U+2039/203a, <code>&lsaquo;/&rsaquo;</code>) are their single quote equivalents.</p><p>See <a href=\"http://en.wikipedia.org/wiki/Guillemets\">Wikipedia:Guillemets</a></p>");
135 } else if (u == "2002") {
136 infoText = i18n("En Space (width of an n)");
137 } else if (u == "2003") {
138 infoText = i18n("Em Space (width of an m)");
139 } else if (u == "2004") {
140 infoText = i18n("Three-Per-Em Space. Width: 1/3 of one <em>em</em>");
141 } else if (u == "2005") {
142 infoText = i18n("Four-Per-Em Space. Width: 1/4 of one <em>em</em>");
143 } else if (u == "2006") {
144 infoText = i18n("Six-Per-Em Space. Width: 1/6 of one <em>em</em>");
145 } else if (u == "2007") {
146 infoText = i18n("Figure space (non-breaking). Width of a digit if digits have fixed width in this font.");
147 } else if (u == "2008") {
148 infoText = i18n("Punctuation Space. Width the same as between a punctuation character and the next character.");
149 } else if (u == "2009") {
150 infoText = i18n("Thin space, in HTML also &thinsp;. See U+202f and <a href=\"http://en.wikipedia.org/wiki/Space_(punctuation)\">Wikipedia:Space_(punctuation)</a>");
151 } else if (u == "200a") {
152 infoText = i18n("Hair Space. Thinner than U+2009.");
153 } else if (u == "2019") {
154 infoText = i18n("Punctuation Apostrophe. Should be used instead of U+0027. See <a href=\"http://en.wikipedia.org/wiki/Apostrophe\">Wikipedia:Apostrophe</a>");
155 } else if (u == "2013") {
156 infoText = i18n("<p>An en Dash (dash of the width of an n).</p><p>Usage examples: In English language for value ranges (1878–1903), for relationships/connections (Zurich–Dublin). In the German language it is also used (with spaces!) for showing thoughts: “Es war – wie immer in den Ferien – ein regnerischer Tag.</p> <p>See <a href=\"http://en.wikipedia.org/wiki/Dash\">Wikipedia:Dash</a></p>");
157 } else if (u == "2014") {
158 infoText = i18n("<p>An em Dash (dash of the width of an m).</p><p>Usage examples: In English language to mark—like here—thoughts. Traditionally without spaces. </p><p>See <a href=\"http://en.wikipedia.org/wiki/Dash\">Wikipedia:Dash</a></p>");
159 } else if (u == "202f") {
160 infoText = i18n("<p>Narrow no-break space. Has the same width as U+2009.</p><p>Usage: For units (spaces are marked with U+2423, ␣): 230␣V, −21␣°C, 50␣lb, <em>but</em> 90° (no space). In German for abbreviations (like: i. d. R. instead of i. d. R. with U+00a0).</p><p>See <a href=\"http://de.wikipedia.org/wiki/Schmales_Leerzeichen\">Wikipedia:de:Schmales_Leerzeichen</a></p>");
161 } else if (u == "2026") {
162 infoText = i18n("Ellipsis: If text has been left o… See <a href=\"http://en.wikipedia.org/wiki/Ellipsis\">Wikipedia:Ellipsis</a>");
163 } else if (u == "2212") {
164 infoText = i18n("Minus sign. For numbers: −42");
165 } else if (u == "2423") {
166 infoText = i18n("Open box; stands for a space.");
167 } else if (u == "2669") {
168 infoText = i18n("Quarter note (Am.) or crochet (Brit.). See <a href=\"http://en.wikipedia.org/wiki/Quarter_note\">Wikipedia:Quarter_note</a>");
169 } else if (u == "266a" || u == "266b") {
170 infoText = i18n("Eighth note (Am.) or quaver (Brit.). Half as long as a quarter note (U+2669). See <a href=\"http://en.wikipedia.org/wiki/Eighth_note\">Wikipedia:Eighth_note</a>");
171 } else if (u == "266c") {
172 infoText = i18n("Sixteenth note (Am.) or semiquaver (Brit.). Half as long as an eighth note (U+266a). See <a href=\"http://en.wikipedia.org/wiki/Sixteenth_note\">Wikipedia:Sixteenth_note</a>");
173 } else if (u == "1D162") {
174 infoText = i18n("Thirty-second note (Am.) or demisemiquaver (Brit.). Half as long as a sixteenth note (U+266b). See <a href=\"http://en.wikipedia.org/wiki/Quarter_note\">Wikipedia:Thirty-second_note</a>");
176 infoText = i18n("<small>No additional information available for this character.</small>");
182 QString UnicodeDialog::validateText(QString text)
184 QRegExp regex("([0-9]|[a-f])", Qt::CaseInsensitive, QRegExp::RegExp2);
185 QString newText = "";
188 switch (inputMethod) {
190 // Remove all characters we don't want
191 while ((pos = regex.indexIn(text, pos)) != -1) {
192 newText += regex.cap(1);
205 void UnicodeDialog::updateOverviewChars(uint unicode)
211 for (i = 1; i <= 4; i++) {
212 if (unicode > i && !controlCharacter(unicode - i)) {
214 left = QChar(unicode - i) + left;
218 for (i = 1; i <= 8; i++) {
219 if (unicode + i <= MAX_UNICODE_V1 && !controlCharacter(unicode + i)) {
220 right += QChar(unicode + i);
225 leftChars->setText(left);
226 rightChars->setText(right);
230 void UnicodeDialog::clearOverviewChars()
232 leftChars->setText("");
233 rightChars->setText("");
236 QString UnicodeDialog::nextUnicode(QString text, Direction direction)
239 QString newText = "";
242 switch (inputMethod) {
244 value = text.toUInt(&ok, 16);
254 if (value == (uint) - 1) value = MAX_UNICODE_V1;
255 if (value > MAX_UNICODE_V1) value = 0;
257 newText.setNum(value, 16);
267 void UnicodeDialog::readChoices()
269 // Get a pointer to a shared configuration instance, then get the TitleWidget group.
270 KSharedConfigPtr config = KGlobal::config();
271 KConfigGroup titleConfig(config, "TitleWidget");
273 // Default is 2013 because there is also (perhaps interesting) information.
274 m_lastUnicodeNumber = titleConfig.readEntry("unicode_number", QString("2013"));
277 void UnicodeDialog::writeChoices()
279 // Get a pointer to a shared configuration instance, then get the TitleWidget group.
280 KSharedConfigPtr config = KGlobal::config();
281 KConfigGroup titleConfig(config, "TitleWidget");
283 titleConfig.writeEntry("unicode_number", m_lastUnicodeNumber);
290 * \brief Validates the entered Unicode number and displays its Unicode character.
292 void UnicodeDialog::slotTextChanged(QString text)
294 unicodeNumber->blockSignals(true);
296 QString newText = validateText(text);
297 if (newText.length() == 0) {
298 unicodeChar->setText("");
299 unicodeNumber->setText("");
300 clearOverviewChars();
302 m_lastUnicodeNumber = "";
303 labelInfoText->setText(unicodeInfo(""));
307 int cursorPos = unicodeNumber->cursorPosition();
309 unicodeNumber->setText(newText);
310 unicodeNumber->setCursorPosition(cursorPos);
312 // Get the decimal number as uint to create the QChar from
315 switch (inputMethod) {
317 value = newText.toUInt(&ok, 16);
320 value = newText.toUInt(&ok, 10);
323 updateOverviewChars(value);
326 // Impossible! validateText never fails!
329 // If an invalid character has been entered:
330 // Reset the cursor position because the entered char has been deleted.
331 if (text != newText && newText == m_lastUnicodeNumber) {
332 unicodeNumber->setCursorPosition(m_lastCursorPos);
335 m_lastCursorPos = unicodeNumber->cursorPosition();
336 m_lastUnicodeNumber = newText;
338 labelInfoText->setText(unicodeInfo(newText));
339 unicodeChar->setText(QChar(value));
342 unicodeNumber->blockSignals(false);
346 * When return pressed, we return the selected unicode character
347 * if it was not a control character.
349 void UnicodeDialog::slotReturnPressed()
351 QString text = trimmedUnicodeNumber(unicodeNumber->text());
352 if (!controlCharacter(text)) {
353 emit charSelected(unicodeChar->text());
359 void UnicodeDialog::slotNextUnicode()
361 QString text = unicodeNumber->text();
362 unicodeNumber->setText(nextUnicode(text, Forward));
365 void UnicodeDialog::slotPrevUnicode()
367 QString text = unicodeNumber->text();
368 unicodeNumber->setText(nextUnicode(text, Backward));
371 void UnicodeDialog::wheelEvent(QWheelEvent * event)
373 if (frame->underMouse()) {
374 if (event->delta() > 0) slotNextUnicode();
375 else slotPrevUnicode();
379 #include "unicodedialog.moc"