File indexing completed on 2021-12-23 10:45:19

0001 /*
0002  * SPDX-FileCopyrightText: 1999 Reginald Stadlbauer <reggie@kde.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kcharselectdia.h"
0008 
0009 #include <QAction>
0010 #include <QApplication>
0011 #include <QClipboard>
0012 #include <QDir>
0013 #include <QFontDatabase>
0014 #include <QGridLayout>
0015 #include <QIcon>
0016 #include <QMenu>
0017 
0018 #include <KActionCollection>
0019 #include <KBookmarkManager>
0020 #include <KBookmarkMenu>
0021 #include <KBookmarkOwner>
0022 #include <KConfigGroup>
0023 #include <KLocalizedString>
0024 #include <KSharedConfig>
0025 #include <KStandardAction>
0026 #include <KStandardShortcut>
0027 #include <KToggleAction>
0028 
0029 class KCharSelectBookmarkOwner : public KBookmarkOwner
0030 {
0031 public:
0032     KCharSelectBookmarkOwner(KCharSelectDia *dia)
0033         : d(dia)
0034     {
0035     }
0036     ~KCharSelectBookmarkOwner() override
0037     {
0038     }
0039 
0040     QString currentTitle() const override
0041     {
0042         uint ucs4 = d->charSelect->currentCodePoint();
0043         if (QChar::isPrint(ucs4)) {
0044             return QString::fromUcs4(&ucs4, 1) + QLatin1Char(' ') + formatCodePoint(ucs4);
0045         } else {
0046             return formatCodePoint(ucs4);
0047         }
0048     }
0049 
0050     QUrl currentUrl() const override
0051     {
0052         return QUrl(formatCodePoint(d->charSelect->currentCodePoint()));
0053     }
0054 
0055     void openBookmark(const KBookmark &bm, Qt::MouseButtons, Qt::KeyboardModifiers) override
0056     {
0057         QString c = bm.url().toString(QUrl::PreferLocalFile | QUrl::RemoveScheme);
0058         if (c.startsWith(QLatin1String("U+"))) {
0059             uint uc = c.midRef(2).toUInt(nullptr, 16);
0060             d->charSelect->setCurrentCodePoint(uc);
0061         }
0062     }
0063 
0064 private:
0065     static QString formatCodePoint(uint ucs4)
0066     {
0067         QString c = QString::number(ucs4, 16).toUpper();
0068         while (c.length() < 4) {
0069             c.prepend(QLatin1Char('0'));
0070         }
0071         return QStringLiteral("U+") + c;
0072     }
0073 
0074 private:
0075     KCharSelectDia *d;
0076 };
0077 
0078 /******************************************************************/
0079 /* class KCharSelectDia                                           */
0080 /******************************************************************/
0081 
0082 //==================================================================
0083 KCharSelectDia::KCharSelectDia(QWidget *parent)
0084     : KXmlGuiWindow(parent)
0085 {
0086     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0087     KConfigGroup gr = config->group("General");
0088 
0089     vFont = gr.readEntry("selectedFont", QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0090     vChr = gr.readEntry("char", 33);
0091     _rtl = gr.readEntry("rtl", false);
0092 
0093     QWidget *mainWidget = new QWidget(this);
0094     setCentralWidget(mainWidget);
0095 
0096     grid = new QGridLayout(mainWidget);
0097 
0098     // Add character selection widget from library kdeui
0099     charSelect = new KCharSelect(mainWidget, actionCollection());
0100     charSelect->setAllPlanesEnabled(true);
0101     charSelect->setCurrentCodePoint(vChr);
0102     charSelect->setCurrentFont(vFont);
0103     charSelect->resize(charSelect->sizeHint());
0104     connect(charSelect, &KCharSelect::currentCodePointChanged, this, &KCharSelectDia::charChanged);
0105     connect(charSelect, SIGNAL(codePointSelected(uint)), SLOT(add(uint)));
0106 
0107     connect(charSelect, &KCharSelect::currentFontChanged, this, &KCharSelectDia::fontSelected);
0108     grid->addWidget(charSelect, 0, 0, 1, 4);
0109 
0110     // Build line editor
0111     lined = new QLineEdit(mainWidget);
0112     lined->resize(lined->sizeHint());
0113     lined->setClearButtonEnabled(true);
0114 
0115     lined->setFont(vFont);
0116 
0117     connect(lined, &QLineEdit::textChanged, this, &KCharSelectDia::lineEditChanged);
0118     grid->addWidget(lined, 1, 0, 1, 3);
0119 
0120     bClip = new QPushButton(i18n("&To Clipboard"), mainWidget);
0121     bClip->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
0122     bClip->setFixedSize(bClip->sizeHint());
0123     connect(bClip, &QPushButton::clicked, this, &KCharSelectDia::toClip);
0124     grid->addWidget(bClip, 1, 3);
0125 
0126     // Build menu
0127     KStandardAction::quit(this, SLOT(close()), actionCollection());
0128 
0129     QAction *action = actionCollection()->addAction(QStringLiteral("copy_clip"));
0130     action->setText(i18n("&To Clipboard"));
0131     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
0132     connect(action, &QAction::triggered, this, &KCharSelectDia::toClip);
0133     actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::Copy));
0134 
0135     action = actionCollection()->addAction(QStringLiteral("copy_utf_8"));
0136     action->setText(i18n("To Clipboard &UTF-8"));
0137     connect(action, &QAction::triggered, this, &KCharSelectDia::toClipUTF8);
0138     action = actionCollection()->addAction(QStringLiteral("copy_html"));
0139     action->setText(i18n("To Clipboard &HTML"));
0140     connect(action, &QAction::triggered, this, &KCharSelectDia::toClipHTML);
0141 
0142     action = actionCollection()->addAction(QStringLiteral("from_clip"));
0143     action->setText(i18n("&From Clipboard"));
0144     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste")));
0145     connect(action, &QAction::triggered, this, &KCharSelectDia::fromClip);
0146     actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::Paste));
0147     action = actionCollection()->addAction(QStringLiteral("from_clip_utf8"));
0148     action->setText(i18n("From Clipboard UTF-8"));
0149     connect(action, &QAction::triggered, this, &KCharSelectDia::fromClipUTF8);
0150 
0151     i18n("From Clipboard HTML"); // Intended for future use
0152 
0153     action = actionCollection()->addAction(QStringLiteral("flip"));
0154     action->setText(i18n("&Flip Text"));
0155     connect(action, &QAction::triggered, this, &KCharSelectDia::flipText);
0156 
0157     action = new KToggleAction(i18n("&Reverse Direction"), this);
0158     action->setChecked(_rtl);
0159     actionCollection()->addAction(QStringLiteral("rtl"), action);
0160     connect(action, &QAction::toggled, this, &KCharSelectDia::setRtl);
0161 
0162     charSelect->setFocus();
0163 
0164     if (_rtl)
0165         lined->setAlignment(Qt::AlignRight);
0166     else
0167         lined->setAlignment(Qt::AlignLeft);
0168 
0169     QString filename = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcharselect/bookmarks.xml"));
0170     if (filename.isEmpty()) {
0171         filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kcharselect");
0172         QDir().mkpath(filename);
0173         filename += QStringLiteral("/bookmarks.xml");
0174     }
0175     KBookmarkManager *manager = KBookmarkManager::managerForFile(filename, QStringLiteral("kcharselect"));
0176 
0177     action = actionCollection()->addAction(QStringLiteral("bookmarks"));
0178     action->setText(i18n("Bookmarks"));
0179     QMenu *bmmenu = new QMenu(this);
0180     action->setMenu(bmmenu);
0181 
0182     KBookmarkMenu *bm = new KBookmarkMenu(manager, new KCharSelectBookmarkOwner(this), bmmenu);
0183     actionCollection()->addActions(bmmenu->actions());
0184 
0185     bm->setParent(this);
0186 
0187     setupGUI(ToolBar | Keys | Save | Create);
0188 }
0189 
0190 //==================================================================
0191 void KCharSelectDia::closeEvent(QCloseEvent *event)
0192 {
0193     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0194     KConfigGroup gr = config->group("General");
0195 
0196     gr.writeEntry("selectedFont", vFont);
0197     gr.writeEntry("char", vChr);
0198     gr.writeEntry("rtl", _rtl);
0199 
0200     KXmlGuiWindow::closeEvent(event);
0201 }
0202 
0203 //==================================================================
0204 void KCharSelectDia::charChanged(uint _chr)
0205 {
0206     vChr = _chr;
0207 }
0208 
0209 //==================================================================
0210 void KCharSelectDia::fontSelected(const QFont &_font)
0211 {
0212     lined->setFont(_font);
0213 
0214     vFont = _font;
0215 }
0216 
0217 //==================================================================
0218 void KCharSelectDia::add(uint _chr)
0219 {
0220     charChanged(_chr);
0221 
0222     QString str = lined->text();
0223     const int pos = lined->cursorPosition();
0224     str.insert(pos, QString::fromUcs4(&_chr, 1));
0225     lined->setText(str);
0226     lined->setCursorPosition(pos + QString::fromUcs4(&_chr, 1).size());
0227 }
0228 
0229 //==================================================================
0230 void KCharSelectDia::toClip()
0231 {
0232     QString str = lined->text();
0233     if (str.isEmpty())
0234         str = QString::fromUcs4(&vChr, 1);
0235     QClipboard *cb = QApplication::clipboard();
0236     cb->setText(str, QClipboard::Clipboard);
0237     cb->setText(str, QClipboard::Selection);
0238 }
0239 
0240 //==================================================================
0241 // UTF-8 is rapidly becoming the favored 8-bit encoding for
0242 // Unicode (iso10646-1).
0243 //
0244 void KCharSelectDia::toClipUTF8()
0245 {
0246     QClipboard *cb = QApplication::clipboard();
0247     QString str = lined->text();
0248     if (str.isEmpty())
0249         str = QString::fromUcs4(&vChr, 1);
0250     cb->setText(QLatin1String(str.toUtf8()));
0251 }
0252 
0253 //==================================================================
0254 //  Put valid HTML 4.0 into the clipboard.  Valid ISO-8859-1 Latin 1
0255 //  characters are left undisturbed.  Everything else, including the
0256 //  "c0 control characters" often used by Windows, are clipped
0257 //  as a HTML entity.
0258 //
0259 void KCharSelectDia::toClipHTML()
0260 {
0261     QClipboard *cb = QApplication::clipboard();
0262     QString input;
0263     QString html;
0264     QChar tempchar;
0265     int i = 0;
0266 
0267     input = lined->text();
0268     if (input.isEmpty())
0269         input = QString::fromUcs4(&vChr, 1);
0270     const int inputLength = input.length();
0271     for (i = 0; i < inputLength; ++i) {
0272         tempchar = input.at(i);
0273         if (tempchar.toLatin1() && ((tempchar.unicode() < 128) || (tempchar.unicode() >= 128 + 32))) {
0274             html.append(input.at(i));
0275         } else {
0276             html.append(QString::asprintf("&#x%x;", tempchar.unicode()));
0277         }
0278     }
0279     cb->setText(html);
0280 }
0281 
0282 //==================================================================
0283 //
0284 void KCharSelectDia::fromClip()
0285 {
0286     QClipboard *cb = QApplication::clipboard();
0287     lined->setText(cb->text());
0288 }
0289 
0290 //==================================================================
0291 // UTF-8 is rapidly becoming the favored 8-bit encoding for
0292 // Unicode (iso10646-1).  This function is handy for decoding
0293 // UTF-8 found in legacy applications, consoles, filenames, webpages,
0294 // etc.
0295 //
0296 void KCharSelectDia::fromClipUTF8()
0297 {
0298     QClipboard *cb = QApplication::clipboard();
0299     const QString str = cb->text();
0300 
0301     lined->setText(str.fromUtf8(str.toLatin1()));
0302 }
0303 
0304 //==================================================================
0305 //  Reverse the text held in the line edit buffer.  This is crucial
0306 //  for dealing with visual vs. logical representations of
0307 //  right to left languages, and handy for working around all
0308 //  manner of legacy character order issues.
0309 //
0310 void KCharSelectDia::flipText()
0311 {
0312     QString input;
0313     QString output;
0314     int i;
0315 
0316     input = lined->text();
0317     const int nbLength = input.length();
0318     for (i = 0; i < nbLength; ++i) {
0319         output.prepend(input.at(i));
0320     }
0321     lined->setText(output);
0322 }
0323 
0324 //==================================================================
0325 void KCharSelectDia::setRtl(bool rtl)
0326 {
0327     _rtl = rtl;
0328     if (_rtl)
0329         lined->setAlignment(Qt::AlignRight);
0330     else
0331         lined->setAlignment(Qt::AlignLeft);
0332 }
0333 
0334 //==================================================================
0335 void KCharSelectDia::lineEditChanged()
0336 {
0337     if (_rtl) {
0338         if (lined->cursorPosition())
0339             lined->setCursorPosition(lined->cursorPosition() - 1);
0340     }
0341 }