File indexing completed on 2024-04-21 05:50:08

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         char32_t 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 = QStringView(c).mid(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(QStringLiteral("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, &KCharSelect::codePointSelected, this, qOverload<char32_t>(&KCharSelectDia::add));
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 
0176     bookmarkManager = new KBookmarkManager(filename, this);
0177 
0178     action = actionCollection()->addAction(QStringLiteral("bookmarks"));
0179     action->setText(i18n("Bookmarks"));
0180     QMenu *bmmenu = new QMenu(this);
0181     action->setMenu(bmmenu);
0182 
0183     KBookmarkMenu *bm = new KBookmarkMenu(bookmarkManager, new KCharSelectBookmarkOwner(this), bmmenu);
0184     actionCollection()->addActions(bmmenu->actions());
0185 
0186     bm->setParent(this);
0187 
0188     setupGUI(ToolBar | Keys | Save | Create);
0189 }
0190 
0191 //==================================================================
0192 void KCharSelectDia::closeEvent(QCloseEvent *event)
0193 {
0194     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0195     KConfigGroup gr = config->group(QStringLiteral("General"));
0196 
0197     gr.writeEntry("selectedFont", vFont);
0198     gr.writeEntry("char", (uint)vChr);
0199     gr.writeEntry("rtl", _rtl);
0200 
0201     KXmlGuiWindow::closeEvent(event);
0202 }
0203 
0204 //==================================================================
0205 void KCharSelectDia::charChanged(char32_t _chr)
0206 {
0207     vChr = _chr;
0208 }
0209 
0210 //==================================================================
0211 void KCharSelectDia::fontSelected(const QFont &_font)
0212 {
0213     lined->setFont(_font);
0214 
0215     vFont = _font;
0216 }
0217 
0218 //==================================================================
0219 void KCharSelectDia::add(char32_t _chr)
0220 {
0221     charChanged(_chr);
0222 
0223     QString str = lined->text();
0224     const int pos = lined->cursorPosition();
0225     str.insert(pos, QString::fromUcs4(&_chr, 1));
0226     lined->setText(str);
0227     lined->setCursorPosition(pos + QString::fromUcs4(&_chr, 1).size());
0228 }
0229 
0230 //==================================================================
0231 void KCharSelectDia::toClip()
0232 {
0233     QString str = lined->text();
0234     if (str.isEmpty())
0235         str = QString::fromUcs4(&vChr, 1);
0236     QClipboard *cb = QApplication::clipboard();
0237     cb->setText(str, QClipboard::Clipboard);
0238     cb->setText(str, QClipboard::Selection);
0239 }
0240 
0241 //==================================================================
0242 // UTF-8 is rapidly becoming the favored 8-bit encoding for
0243 // Unicode (iso10646-1).
0244 //
0245 void KCharSelectDia::toClipUTF8()
0246 {
0247     QClipboard *cb = QApplication::clipboard();
0248     QString str = lined->text();
0249     if (str.isEmpty())
0250         str = QString::fromUcs4(&vChr, 1);
0251     cb->setText(QLatin1String(str.toUtf8()));
0252 }
0253 
0254 //==================================================================
0255 //  Put valid HTML 4.0 into the clipboard.  Valid ISO-8859-1 Latin 1
0256 //  characters are left undisturbed.  Everything else, including the
0257 //  "c0 control characters" often used by Windows, are clipped
0258 //  as a HTML entity.
0259 //
0260 void KCharSelectDia::toClipHTML()
0261 {
0262     QClipboard *cb = QApplication::clipboard();
0263     QString input;
0264     QString html;
0265     QChar tempchar;
0266     int i = 0;
0267 
0268     input = lined->text();
0269     if (input.isEmpty())
0270         input = QString::fromUcs4(&vChr, 1);
0271     const int inputLength = input.length();
0272     for (i = 0; i < inputLength; ++i) {
0273         tempchar = input.at(i);
0274         if (tempchar.toLatin1() && ((tempchar.unicode() < 128) || (tempchar.unicode() >= 128 + 32))) {
0275             html.append(input.at(i));
0276         } else {
0277             html.append(QString::asprintf("&#x%x;", tempchar.unicode()));
0278         }
0279     }
0280     cb->setText(html);
0281 }
0282 
0283 //==================================================================
0284 //
0285 void KCharSelectDia::fromClip()
0286 {
0287     QClipboard *cb = QApplication::clipboard();
0288     lined->setText(cb->text());
0289 }
0290 
0291 //==================================================================
0292 // UTF-8 is rapidly becoming the favored 8-bit encoding for
0293 // Unicode (iso10646-1).  This function is handy for decoding
0294 // UTF-8 found in legacy applications, consoles, filenames, webpages,
0295 // etc.
0296 //
0297 void KCharSelectDia::fromClipUTF8()
0298 {
0299     QClipboard *cb = QApplication::clipboard();
0300     const QString str = cb->text();
0301 
0302     lined->setText(str.fromUtf8(str.toLatin1()));
0303 }
0304 
0305 //==================================================================
0306 //  Reverse the text held in the line edit buffer.  This is crucial
0307 //  for dealing with visual vs. logical representations of
0308 //  right to left languages, and handy for working around all
0309 //  manner of legacy character order issues.
0310 //
0311 void KCharSelectDia::flipText()
0312 {
0313     QString input;
0314     QString output;
0315     int i;
0316 
0317     input = lined->text();
0318     const int nbLength = input.length();
0319     for (i = 0; i < nbLength; ++i) {
0320         output.prepend(input.at(i));
0321     }
0322     lined->setText(output);
0323 }
0324 
0325 //==================================================================
0326 void KCharSelectDia::setRtl(bool rtl)
0327 {
0328     _rtl = rtl;
0329     if (_rtl)
0330         lined->setAlignment(Qt::AlignRight);
0331     else
0332         lined->setAlignment(Qt::AlignLeft);
0333 }
0334 
0335 //==================================================================
0336 void KCharSelectDia::lineEditChanged()
0337 {
0338     if (_rtl) {
0339         if (lined->cursorPosition())
0340             lined->setCursorPosition(lined->cursorPosition() - 1);
0341     }
0342 }
0343 
0344 #include "moc_kcharselectdia.cpp"