/*************************************************************************** * Copyright (C) 2006-2007 by Pino Toscano * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "guiutils.h" // qt/kde includes #include #include #include #include #include #include #include #include // local includes #include "core/action.h" #include "core/annotations.h" #include "core/document.h" #include struct GuiUtilsHelper { GuiUtilsHelper() { } QSvgRenderer *svgStamps(); QList il; std::unique_ptr svgStampFile; }; QSvgRenderer *GuiUtilsHelper::svgStamps() { if (!svgStampFile.get()) { const QString stampFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/stamps.svg")); if (!stampFile.isEmpty()) { svgStampFile = std::make_unique(stampFile); if (!svgStampFile->isValid()) { svgStampFile.reset(); } } } return svgStampFile.get(); } Q_GLOBAL_STATIC(GuiUtilsHelper, s_data) namespace GuiUtils { QString captionForAnnotation(const Okular::Annotation *ann) { Q_ASSERT(ann); const bool hasComment = !ann->contents().isEmpty(); QString ret; switch (ann->subType()) { case Okular::Annotation::AText: if (((Okular::TextAnnotation *)ann)->textType() == Okular::TextAnnotation::Linked) ret = i18n("Pop-up Note"); else { if (((Okular::TextAnnotation *)ann)->inplaceIntent() == Okular::TextAnnotation::TypeWriter) ret = i18n("Typewriter"); else ret = i18n("Inline Note"); } break; case Okular::Annotation::ALine: if (((Okular::LineAnnotation *)ann)->linePoints().count() == 2) ret = hasComment ? i18n("Straight Line with Comment") : i18n("Straight Line"); else ret = hasComment ? i18n("Polygon with Comment") : i18n("Polygon"); break; case Okular::Annotation::AGeom: ret = hasComment ? i18n("Geometry with Comment") : i18n("Geometry"); break; case Okular::Annotation::AHighlight: switch (((Okular::HighlightAnnotation *)ann)->highlightType()) { case Okular::HighlightAnnotation::Highlight: ret = hasComment ? i18n("Highlight with Comment") : i18n("Highlight"); break; case Okular::HighlightAnnotation::Squiggly: ret = hasComment ? i18n("Squiggle with Comment") : i18n("Squiggle"); break; case Okular::HighlightAnnotation::Underline: ret = hasComment ? i18n("Underline with Comment") : i18n("Underline"); break; case Okular::HighlightAnnotation::StrikeOut: ret = hasComment ? i18n("Strike Out with Comment") : i18n("Strike Out"); break; } break; case Okular::Annotation::AStamp: ret = hasComment ? i18n("Stamp with Comment") : i18n("Stamp"); break; case Okular::Annotation::AInk: ret = hasComment ? i18n("Freehand Line with Comment") : i18n("Freehand Line"); break; case Okular::Annotation::ACaret: ret = i18n("Caret"); break; case Okular::Annotation::AFileAttachment: ret = i18n("File Attachment"); break; case Okular::Annotation::ASound: ret = i18n("Sound"); break; case Okular::Annotation::AMovie: ret = i18n("Movie"); break; case Okular::Annotation::AScreen: ret = i18nc("Caption for a screen annotation", "Screen"); break; case Okular::Annotation::AWidget: ret = i18nc("Caption for a widget annotation", "Widget"); break; case Okular::Annotation::ARichMedia: ret = i18nc("Caption for a rich media annotation", "Rich Media"); break; case Okular::Annotation::A_BASE: break; } return ret; } QString authorForAnnotation(const Okular::Annotation *ann) { Q_ASSERT(ann); return !ann->author().isEmpty() ? ann->author() : i18nc("Unknown author", "Unknown"); } QString contentsHtml(const Okular::Annotation *ann) { QString text = ann->contents().toHtmlEscaped(); text.replace(QLatin1Char('\n'), QLatin1String("
")); return text; } QString prettyToolTip(const Okular::Annotation *ann) { Q_ASSERT(ann); QString author = authorForAnnotation(ann); QString contents = contentsHtml(ann); QString tooltip = QStringLiteral("") + i18n("Author: %1", author) + QStringLiteral(""); if (!contents.isEmpty()) tooltip += QStringLiteral("

") + contents; tooltip += QLatin1String("
"); return tooltip; } QPixmap loadStamp(const QString &nameOrPath, int size, bool keepAspectRatio) { const QString name = nameOrPath.toLower(); // _name is the name of an Okular stamp symbols ( multiple symbols in a single *.svg file) QSvgRenderer *r = nullptr; if ((r = s_data->svgStamps()) && r->elementExists(name)) { const QSize stampSize = r->boundsOnElement(name).size().toSize(); const QSize pixmapSize = stampSize.scaled(size, size, keepAspectRatio ? Qt::KeepAspectRatioByExpanding : Qt::IgnoreAspectRatio); QPixmap pixmap(pixmapSize); pixmap.fill(Qt::transparent); QPainter p(&pixmap); r->render(&p, name); p.end(); return pixmap; } // _name is a path (do this before loading as icon name to avoid some rare weirdness ) QPixmap pixmap; pixmap.load(nameOrPath); if (!pixmap.isNull()) { pixmap = pixmap.scaled(size, size, keepAspectRatio ? Qt::KeepAspectRatioByExpanding : Qt::IgnoreAspectRatio, Qt::SmoothTransformation); return pixmap; } // _name is an icon name const KIconLoader *il = iconLoader(); QString path; pixmap = il->loadIcon(name, KIconLoader::User, size, KIconLoader::DefaultState, QStringList(), &path, true); if (path.isEmpty()) pixmap = il->loadIcon(name, KIconLoader::NoGroup, size); return pixmap; // can be a null pixmap } void addIconLoader(KIconLoader *loader) { s_data->il.append(loader); } void removeIconLoader(KIconLoader *loader) { s_data->il.removeAll(loader); } KIconLoader *iconLoader() { return s_data->il.isEmpty() ? KIconLoader::global() : s_data->il.back(); } void saveEmbeddedFile(Okular::EmbeddedFile *ef, QWidget *parent) { const QString caption = i18n("Where do you want to save %1?", ef->name()); const QString path = QFileDialog::getSaveFileName(parent, caption, ef->name()); if (path.isEmpty()) return; QFile targetFile(path); writeEmbeddedFile(ef, parent, targetFile); } void writeEmbeddedFile(Okular::EmbeddedFile *ef, QWidget *parent, QFile &target) { if (!target.open(QIODevice::WriteOnly)) { KMessageBox::error(parent, i18n("Could not open \"%1\" for writing. File was not saved.", target.fileName())); return; } target.write(ef->data()); target.close(); } Okular::Movie *renditionMovieFromScreenAnnotation(const Okular::ScreenAnnotation *annotation) { if (!annotation) return nullptr; if (annotation->action() && annotation->action()->actionType() == Okular::Action::Rendition) { Okular::RenditionAction *renditionAction = static_cast(annotation->action()); return renditionAction->movie(); } return nullptr; } // from Arthur - qt4 static inline int qt_div_255(int x) { return (x + (x >> 8) + 0x80) >> 8; } void colorizeImage(QImage &grayImage, const QColor &color, unsigned int destAlpha) { // Make sure that the image is Format_ARGB32_Premultiplied if (grayImage.format() != QImage::Format_ARGB32_Premultiplied) grayImage = grayImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); // iterate over all pixels changing the alpha component value unsigned int *data = reinterpret_cast(grayImage.bits()); unsigned int pixels = grayImage.width() * grayImage.height(); int red = color.red(), green = color.green(), blue = color.blue(); int source, sourceSat, sourceAlpha; for (unsigned int i = 0; i < pixels; ++i) { // optimize this loop keeping byte order into account source = data[i]; sourceSat = qRed(source); int newR = qt_div_255(sourceSat * red), newG = qt_div_255(sourceSat * green), newB = qt_div_255(sourceSat * blue); if ((sourceAlpha = qAlpha(source)) == 255) { // use destAlpha data[i] = qRgba(newR, newG, newB, destAlpha); } else { // use destAlpha * sourceAlpha product if (destAlpha < 255) sourceAlpha = qt_div_255(destAlpha * sourceAlpha); data[i] = qRgba(newR, newG, newB, sourceAlpha); } } } }