File indexing completed on 2025-04-27 03:58:40

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-06-15
0007  * Description : localize selector widget
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "localizeselector.h"
0016 
0017 // Qt includes
0018 
0019 #include <QLabel>
0020 #include <QIcon>
0021 #include <QMenu>
0022 #include <QAction>
0023 #include <QListWidget>
0024 #include <QWidgetAction>
0025 #include <QStyle>
0026 #include <QToolButton>
0027 #include <QApplication>
0028 #include <QScrollBar>
0029 #include <QListWidgetItem>
0030 #include <QGridLayout>
0031 #include <QScopedPointer>
0032 #include <QEventLoop>
0033 
0034 // KDE includes
0035 
0036 #include <klocalizedstring.h>
0037 
0038 // Local includes
0039 
0040 #include "digikam_debug.h"
0041 #include "localizeconfig.h"
0042 #include "localizesettings.h"
0043 #include "donlinetranslator.h"
0044 #include "altlangstredit.h"
0045 
0046 namespace Digikam
0047 {
0048 
0049 class Q_DECL_HIDDEN TranslateAction : public QWidgetAction
0050 {
0051     Q_OBJECT
0052 
0053 public:
0054 
0055     explicit TranslateAction(QObject* const parent)
0056         : QWidgetAction(parent)
0057     {
0058     }
0059 
0060     QWidget* createWidget(QWidget* parent) override
0061     {
0062         m_list         = new QListWidget(parent);
0063         QFontMetrics fontMt(m_list->font());
0064         QRect fontRect = fontMt.boundingRect(0, 0, m_list->width(), m_list->height(), 0, QLatin1String("XX-XX"));
0065         int width      =  m_list->contentsMargins().left() + m_list->contentsMargins().right();
0066         width         += fontRect.width() + m_list->verticalScrollBar()->height();
0067         m_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0068         m_list->setFixedWidth(width);
0069 
0070         return m_list;
0071     }
0072 
0073 public:
0074 
0075     QListWidget* m_list = nullptr;
0076 };
0077 
0078 class Q_DECL_HIDDEN LocalizeSelector::Private
0079 {
0080 public:
0081 
0082     explicit Private()
0083       : translateButton (nullptr),
0084         settingsButton  (nullptr),
0085         translateAction (nullptr)
0086     {
0087     }
0088 
0089 public:
0090 
0091     QToolButton*                   translateButton;
0092     QToolButton*                   settingsButton;
0093 
0094     TranslateAction*               translateAction;
0095 };
0096 
0097 LocalizeSelector::LocalizeSelector(QWidget* const parent)
0098     : DHBox(parent),
0099       d      (new Private)
0100 {
0101     d->translateButton = new QToolButton(this);
0102     d->translateButton->setIcon(QIcon::fromTheme(QLatin1String("language-chooser")));
0103     d->translateButton->setPopupMode(QToolButton::MenuButtonPopup);
0104     QMenu* const menu  = new QMenu(d->translateButton);
0105     d->translateAction = new TranslateAction(d->translateButton);
0106     menu->addAction(d->translateAction);
0107     d->translateButton->setMenu(menu);
0108 
0109     d->settingsButton  = new QToolButton(this);
0110     d->settingsButton->setIcon(QIcon::fromTheme(QLatin1String("configure")));
0111     d->settingsButton->setToolTip(i18nc("@info", "Open localize setup"));
0112 
0113     setContentsMargins(QMargins());
0114     setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0115                     QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0116 
0117     slotLocalizeChanged();
0118 
0119     // --------------------------------------------------------
0120 
0121     connect(d->settingsButton, &QToolButton::clicked,
0122             this, &LocalizeSelector::slotOpenLocalizeSetup);
0123 
0124     connect(d->translateAction->m_list, &QListWidget::itemClicked,
0125             this, &LocalizeSelector::slotTranslate);
0126 
0127     connect(d->translateButton, &QToolButton::pressed,
0128             d->translateButton, &QToolButton::showMenu);
0129 
0130     connect(LocalizeSettings::instance(), &LocalizeSettings::signalSettingsChanged,
0131             this, &LocalizeSelector::slotLocalizeChanged);
0132 }
0133 
0134 LocalizeSelector::~LocalizeSelector()
0135 {
0136     delete d;
0137 }
0138 
0139 void LocalizeSelector::populateTranslationEntries()
0140 {
0141     d->translateAction->m_list->clear();
0142 
0143     QStringList allRFC3066  = DOnlineTranslator::supportedRFC3066(LocalizeSettings::instance()->settings().translatorEngine);
0144     LocalizeContainer set   = LocalizeSettings::instance()->settings();
0145 
0146     Q_FOREACH (const QString& lg, set.translatorLang)
0147     {
0148         QListWidgetItem* const item = new QListWidgetItem(d->translateAction->m_list);
0149         item->setText(lg);
0150         item->setToolTip(i18nc("@info", "Translate to %1", AltLangStrEdit::languageNameRFC3066(lg)));
0151         d->translateAction->m_list->addItem(item);
0152     }
0153 }
0154 
0155 void LocalizeSelector::slotOpenLocalizeSetup()
0156 {
0157     LocalizeSettings::instance()->openLocalizeSetup();
0158 }
0159 
0160 void LocalizeSelector::slotLocalizeChanged()
0161 {
0162     populateTranslationEntries();
0163     d->translateButton->setToolTip(i18nc("@info: language edit widget", "Select language to translate with %1",
0164                                    DOnlineTranslator::engineName(LocalizeSettings::instance()->settings().translatorEngine)));
0165 }
0166 
0167 void LocalizeSelector::slotTranslate(QListWidgetItem* item)
0168 {
0169     d->translateButton->menu()->close();
0170 
0171     if (item)
0172     {
0173         Q_EMIT signalTranslate(item->text());
0174     }
0175 }
0176 
0177 // ------------------------------------------------------------------------
0178 
0179 class Q_DECL_HIDDEN LocalizeSelectorList::Private
0180 {
0181 public:
0182 
0183     explicit Private()
0184       : trLabel   (nullptr),
0185         trSelector(nullptr),
0186         trList    (nullptr)
0187     {
0188     }
0189 
0190 public:
0191 
0192     QLabel*           trLabel;
0193     LocalizeSelector* trSelector;
0194     LanguagesList*    trList;
0195 };
0196 
0197 LocalizeSelectorList::LocalizeSelectorList(QWidget* const parent)
0198     : QWidget(parent),
0199       d      (new Private)
0200 {
0201     QGridLayout* const grid  = new QGridLayout(this);
0202 
0203     d->trLabel               = new QLabel(this);
0204     d->trSelector            = new LocalizeSelector(this);
0205     d->trList                = new LanguagesList(this);
0206     d->trList->setContextMenuPolicy(Qt::CustomContextMenu);
0207 
0208     grid->addWidget(d->trLabel,      0, 0, 1, 1);
0209     grid->addWidget(d->trSelector,   0, 1, 1, 1);
0210     grid->addWidget(d->trList,       1, 0, 1, 2);
0211     grid->setColumnStretch(0, 10);
0212     grid->setRowStretch(2, 10);
0213     grid->setContentsMargins(0, 0, 0, 0);
0214 
0215     connect(d->trSelector, SIGNAL(signalTranslate(QString)),
0216             this, SLOT(slotAppendTranslation(QString)));
0217 
0218     connect(d->trList, SIGNAL(customContextMenuRequested(QPoint)),
0219             this, SLOT(slotShowContextMenu(QPoint)));
0220 }
0221 
0222 LocalizeSelectorList::~LocalizeSelectorList()
0223 {
0224     delete d;
0225 }
0226 
0227 void LocalizeSelectorList::setTitle(const QString& title)
0228 {
0229     d->trLabel->setText(title);
0230 }
0231 
0232 void LocalizeSelectorList::clearLanguages()
0233 {
0234     d->trList->clear();
0235 }
0236 
0237 void LocalizeSelectorList::addLanguage(const QString& code)
0238 {
0239     d->trList->addTopLevelItem(new QTreeWidgetItem(d->trList, QStringList() << code << AltLangStrEdit::languageNameRFC3066(code)));
0240 }
0241 
0242 QStringList LocalizeSelectorList::languagesList() const
0243 {
0244     QStringList codes;
0245 
0246     QTreeWidgetItemIterator it(d->trList);
0247 
0248     while (*it)
0249     {
0250         codes << (*it)->text(0);
0251         ++it;
0252     }
0253 
0254     return codes;
0255 }
0256 
0257 void LocalizeSelectorList::slotShowContextMenu(const QPoint& pos)
0258 {
0259     QPoint globalPos = d->trList->mapToGlobal(pos);
0260 
0261     QMenu menu;
0262     QAction* const rm = menu.addAction(i18nc("@action", "Remove this entry"));
0263     QAction* const cl = menu.addAction(i18nc("@action", "Clear List"));
0264     QAction* const ac = menu.exec(globalPos);
0265 
0266     if      (ac == rm)
0267     {
0268         delete d->trList->currentItem();
0269     }
0270     else if (ac == cl)
0271     {
0272         d->trList->clear();
0273     }
0274 
0275     Q_EMIT signalSettingsChanged();
0276 }
0277 
0278 void LocalizeSelectorList::slotAppendTranslation(const QString& lang)
0279 {
0280     QTreeWidgetItemIterator it(d->trList);
0281 
0282     while (*it)
0283     {
0284         if ((*it)->text(0).startsWith(lang))
0285         {
0286             return;
0287         }
0288 
0289         ++it;
0290     }
0291 
0292     addLanguage(lang);
0293 
0294     Q_EMIT signalSettingsChanged();
0295 }
0296 
0297 // ------------------------------------------------------------------------
0298 
0299 bool s_inlineTranslateString(const QString& text, const QString& trCode, QString& tr, QString& error)
0300 {
0301     QScopedPointer<DOnlineTranslator> trengine(new DOnlineTranslator);
0302     QScopedPointer<QEventLoop> waitingLoop(new QEventLoop);
0303 
0304     DOnlineTranslator::Language srcLang = DOnlineTranslator::Auto;
0305     DOnlineTranslator::Language trLang  = DOnlineTranslator::language(DOnlineTranslator::fromRFC3066(LocalizeSettings::instance()->settings().translatorEngine, trCode));
0306 
0307     qCDebug(DIGIKAM_WIDGETS_LOG) << "Request to translate with Web-service:";
0308     qCDebug(DIGIKAM_WIDGETS_LOG) << "Text to translate        :" << text;
0309     qCDebug(DIGIKAM_WIDGETS_LOG) << "To target language       :" << trLang;
0310     qCDebug(DIGIKAM_WIDGETS_LOG) << "With source language     :" << srcLang;
0311 
0312     QObject::connect(trengine.data(), &DOnlineTranslator::signalFinished,
0313                      waitingLoop.data(), &QEventLoop::quit);
0314 
0315     trengine->translate(text,                                                            // String to translate
0316                         LocalizeSettings::instance()->settings().translatorEngine,       // Web service
0317                         trLang,                                                          // Target language
0318                         srcLang,                                                         // Source langage
0319                         DOnlineTranslator::Auto);
0320 
0321     waitingLoop->exec(QEventLoop::ExcludeUserInputEvents);
0322 
0323     if (trengine->error() == DOnlineTranslator::NoError)
0324     {
0325         tr = trengine->translation();
0326         qCDebug(DIGIKAM_WIDGETS_LOG) << "Text translated          :" << tr;
0327 
0328         return true;
0329     }
0330     else
0331     {
0332         error = QChar(trengine->error());
0333     }
0334 
0335     return false;
0336 }
0337 
0338 } // namespace Digikam
0339 
0340 #include "localizeselector.moc"
0341 
0342 #include "moc_localizeselector.cpp"