From d1838aa1bcb679d6db1047b3ecc395e6854be60c Mon Sep 17 00:00:00 2001 From: Alf Gaida Date: Sun, 25 Sep 2016 22:51:07 +0200 Subject: [PATCH] Cherry-picking upstream release 0.5.0. * Added build-dependency libqt5svg5-dev * Bumped compat to 10 * Bumped minimum version debhelper (>= 10) * Bumped minimum version libfm-qt-dev (>= 0.11.1) * Bumped minimum version liblxqt0-dev (>= 0.11.0) * Bumped minimum version libqt5xdg-dev (>= 2.0.0) * Removed --parallel from rules, standard compat 10 --- .gitignore | 3 + CHANGELOG | 169 ++++++++++++++++ CMakeLists.txt | 25 +-- README.md | 26 ++- data/lximage-qt.desktop.in | 2 +- debian/.gitignore | 1 + debian/changelog | 13 ++ debian/control | 9 +- debian/rules | 3 +- src/CMakeLists.txt | 5 +- src/application.cpp | 7 +- src/application.h | 2 - src/imageview.cpp | 143 +++++++++++--- src/imageview.h | 11 ++ src/job.cpp | 2 +- src/loadimagejob.cpp | 6 +- src/mainwindow.cpp | 186 +++++++++--------- src/mainwindow.h | 2 +- src/mainwindow.ui | 5 +- src/preferencesdialog.cpp | 2 - src/saveimagejob.cpp | 2 +- src/screenshotdialog.cpp | 57 +++--- src/settings.cpp | 6 +- .../lximage-qt-screenshot_ca.desktop | 4 + src/translations/lximage-qt_ca.desktop | 4 + 25 files changed, 495 insertions(+), 200 deletions(-) create mode 100644 .gitignore create mode 100644 CHANGELOG create mode 100644 src/translations/lximage-qt-screenshot_ca.desktop create mode 100644 src/translations/lximage-qt_ca.desktop diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48cd491 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +*.kdev4 +src/translations/lximage-qt diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..3f6bc71 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,169 @@ + +lximage-qt-0.5.0 / 2016-09-24 +============================= + + * Bump version to 0.5.0 (#67) + * Remove Core and Qt from Categories in desktop file (#64) + * Extend README.md + * Fix broken compatibility introduced by libfm-qt API changes. This closes lxde/lximage-qt#63. + * Add Catalan translations + * Quieten compiler warning + * Code cleanup + * Use LXQtCompilerSettings cmake module + * Treat SVG files separately as SVG images + * build: Update translations based on *.ui + * Fix typo in Portuguese translation for desktop file + * Fix typo in German translation for desktop file (#55) + * build: Use external translations (#54) + * ts-files removal (#53) + * Hide cursor smartly in fullscreen mode + * build: Use liblxqt's TranslateDesktop module + * Adds support for GIF animation. + * Implement an EOG-like behavior on starting By clicking on an image for the first time, the user wants to see it clearly with lximage-qt. So, the following behavior is implemented here: + * Add --version command line option + * Fix missing Russian translation in desktop file + * Fix memory leak if taking screenshot with cursor + * Polish translation updated + * Another update + * Improved Russian translation - thanks to uazure + * Fix typo + * Add Russian translation + * Italian translation update + * CMake: Adapt to libfm-qt Targets + * Turn on C++11 support. This closes bug lxde/lximage-qt #36. + * Exec should have an argument + * all GPL files are (or any later) + * Add release script + * Update translations + * Set the color table properly for scaled images + * Add Greek (el) translation Remove needless country variant from language code + * Corrected language code (de_DE -> de) of german translation, marked translations as done. + * replace tabs with spaces + * remove trailing spaces + * replace glib with Qt for command-line parsing + * Don't save file in private mode + * Prevents the slideshow timeout to be set to 0 in the UI + * Correctly include CMake modules in intree/superbuild mode + * Remove lximage-qt from the Utilities category + * Update README + * Update .gitignore + * Hungarian translations added + * save and restore window size and maximized state + +0.4.0 / 2015-02-18 +================== + + * Release v0.4.0 + * src/CMakeLists.txt: do not completely overwrite CMAKE_CXX_FLAGS + * Create lximage-qt_it.desktop + * Create lximage-qt_it.ts + * CMakeLists cleanups + * Portuguese update + * Added german translation, re-generated all other .ts files. + * Added keyboard shortcut to print. + * Adds .desktop translation support + * Portuguese language update + * Remove debian directory (Close #9) + * Fix typo Zoomo -> Zoom + * Use proper naming conventions for translations + * Clean up CMakeLists, dropping support for Qt 5 + +0.3.0 / 2014-10-15 +================== + + * Release v0.3.0 + * Rename preferencedialog.ui to preferencesdialog.ui + * Ignore build dir. + * debian: enable qt5 by default + * Fix lxde/lxde-qt #269 - Screenshots are not saved aedequately unless file extension is chosen manually. + * Support Qt5 and libfm-qt5. + * Make sure all enums are handled in switch + +0.2.0 / 2014-05-09 +================== + + * Release 0.2.0 + * Update desktop files + * Update README/COPYING/AUTHORS + * Add some missing link_directories() + * Commit from LXDE Pootle server by user yinghua_wang.: 70 of 70 strings translated (0 fuzzy). + * Add CPack rules for creating tarball + * Avoid creating a scaled image cache if current scale factor is 1.0 (original size). + * Rewrite the scaled image caching code in LxImage::ImageView to improve its readability and correctness. + * Add LxImage::Job class as a base class for multi-threading jobs. + * Avoid copying subimages to speed up scaling images. + * Limit the size of pixmap cache. + * Limit the size of pixmap cache. + * Create a cache for the high-quality scaled image of the currently viewport and use it to override the default paintEvent() of QGraphicsView as needed. This improves the image quality a lot when we scale down large photos. + * Cancel autoZoomFit when calling zoomOriginal(), zoomIn(), and zoomOut(). + * Add copy and paste buttons to the toolbar. + * Automatically zoom to fit current window size by default. + * Make the preferences dialog non-modal and apply the settings to all existing windows. + * Add "Delete file" and "File properties" actions to the file menu. + * Add a very basic thumbnails pane based on Fm::FolderView of libfm-qt. + * Implement the preferences dialog. * Enable keyboard shortcuts in fullscreen mode. + * Implement very basic slide show functionality. + * Jump to the previous or the next image by using mouse wheel. + * Avoid scaling up an image while zoomFit() if it's smaller than the current view. + * Support grabbing mouse cursor when taking a screenshot. + * Add very basic printing support. + * Commit from LXDE Pootle server by user adrianoh2.: 70 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user Fitoschido.: 70 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user hirkmt.: 70 of 70 strings translated (0 fuzzy). + * Remove xsettings support and add an option in the preference dialog to set a fallback icon theme instead. + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * Improve cmake integration for translations. The *.ts files are only updated when UPDATE_TRANSLATIONS cmake option is turned on. + * Commit from LXDE Pootle server by user zvacet.: 65 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user zvacet.: 50 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user wwycheuk.: 65 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user mbouzada.: 70 of 70 strings translated (0 fuzzy). + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * Commit from LXDE Pootle server by user Fitoschido.: 68 of 70 strings translated (0 fuzzy). + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * Corrected caml cased string toolBar. + * Commit from LXDE Pootle server by user smarquespt.: 70 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user brother.: 24 of 24 strings translated (0 fuzzy). + * Correct misspelled 'Zoom'. + * Commit from LXDE Pootle server by user andika.: 70 of 70 strings translated (0 fuzzy). + * New files added from LXDE Pootle server based on templates + * Commit from LXDE Pootle server by user strebski.: 70 of 70 strings translated (0 fuzzy). + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * Commit from LXDE Pootle server by user LStranger.: 70 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user brother.: 70 of 70 strings translated (0 fuzzy). + * Commit from LXDE Pootle server by user LStranger.: 2 of 70 strings translated (0 fuzzy). + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * New files added from LXDE Pootle server based on templates + * Add zh_TW translation and a template ts file. + * Add a desktop entry file for the built-in screenshot tool. + * Add --screenshot command line argument to launch the built-in screenshot utility. + * Improve the screenshot tool. Implement pasting from clipboard. + * Add ability to taking screenshots to lximage-qt. + * debian : Add missing libx11 build-depend + * Add missing files. + * Add Xdg::DesktopSettings for detecting desktop-specific settings. Get icon theme name via XSettings or config files when available. + * Supporting saving files. (needs some more polishing, though). + * Add a basic debian directory to enable daily builds. + * Add a context menu. + * Use libexif to read EXIF orientation tags then apply them to images loaded. + * Refactor - move image loading code to LxImage::LoadImageJob class. + * Remove unused data member. + * Add a preferences dialog (not working yet). Little adjustment for menu positions and add placeholders for features not implemented. + * Fix filename encoding handling so non-English filenames can be passed correctly from command line arguments. + * Canonicalize filenames passed through command line arguments. Add an icon borrowed from GPicView. Rearrange menus and implement "fullscreen" and "copy to clipboard". + * Implement basic single instance support and command line argument parsing. + * Properly cancel pending tasks and make going back/forward more smooth. Enhance window title display. + * Little fix to avoid loading a cancelled image. + * Supports rotation of images. + * Use the latest libfm-qt APIs to filter out non-image files. Implement jumping to first and last file in the folder. + * Fix incorrect reference couting of GCancellable objects to avoid crashes. Add some shortcut keys to improve usability. + * Use glib/gio GInputStream + GIOSchedulerJob to load the images with multi-threading. Refactor, simplify class methods of LxImage::MainWindow. + * Use libfm to load folders containing the specified image. Add dependency on libexif for future implementation of EXIF related stuff. Add LxImage::Applcation class to handle application initiation. + * Initial import into git diff --git a/CMakeLists.txt b/CMakeLists.txt index 109d1f9..3b0b270 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(lximage-qt) include(GNUInstallDirs) set(MAJOR_VERSION 0) -set(MINOR_VERSION 4) +set(MINOR_VERSION 5) set(PATCH_VERSION 0) set(LXIMAGE_VERSION ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}) @@ -13,35 +13,18 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_AUTOMOC ON) -# C++ 11 support -if (CMAKE_VERSION VERSION_LESS "3.1") - include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) - if(COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - else() - CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) - # -std=c++0x is deprecated but some tools e.g. qmake or older gcc are still using it - if(COMPILER_SUPPORTS_CXX0X) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - else() - message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER} does not support c++11/c++0x") - endif() - endif() -else() - set(CMAKE_CXX_STANDARD 11) -endif() - - find_package(Qt5Widgets REQUIRED) find_package(Qt5DBus REQUIRED) find_package(Qt5PrintSupport REQUIRED QUIET) find_package(Qt5X11Extras REQUIRED QUIET) find_package(Qt5LinguistTools REQUIRED QUIET) +find_package(Qt5Svg REQUIRED QUIET) find_package(fm-qt REQUIRED QUIET) find_package(lxqt REQUIRED) #just a build dependency for .desktop files translation message(STATUS "Building with Qt ${Qt5Core_VERSION_STRING}") +include(LXQtCompilerSettings NO_POLICY_SCOPE) + find_package(PkgConfig REQUIRED) # FIXME: we'll need this to provide detail info for photos in the future diff --git a/README.md b/README.md index e830d19..13a554a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ -# lximage-qt +# LXImage-Qt -The Qt port of LXImage, a simple and fast image viewer. +## Overview + +LXImage-Qt is the Qt port of LXImage, a simple and fast image viewer. + +In addition it features a tool to take screenshots. + +It is maintained by the LXQt project but can be used independently from this desktop environment. + +## Installation + +### Compiling source code + +Runtime dependencies are qtx11extras and [libfm-qt](https://github.com/lxde/libfm-qt) (LXImage-Qt used to depend on [PCManFM-Qt](https://github.com/lxde/pcmanfm-qt) but the relevant code belongs to what was outsourced in libfm-qt). +Additional build dependencies are CMake and optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information. + +Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` has to be set to `/usr` on most operating systems. + +To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual. + +### Binary packages + +Official binary packages are available in Arch Linux, Debian (as of Debian stretch), Fedora and openSUSE (Leap 42.1 and Tumbleweed). +Just use the distributions' package manager to search for string 'lximage'. diff --git a/data/lximage-qt.desktop.in b/data/lximage-qt.desktop.in index 80bee7d..f659a6e 100644 --- a/data/lximage-qt.desktop.in +++ b/data/lximage-qt.desktop.in @@ -7,5 +7,5 @@ Icon=lximage-qt Exec=lximage-qt %F StartupNotify=true Terminal=false -Categories=Graphics;Core;Qt;Viewer;RasterGraphics;2DGraphics;Photography; +Categories=Graphics;Viewer;RasterGraphics;2DGraphics;Photography; MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-tga;image/x-portable-pixmap;image/x-portable-bitmap;image/x-targa;image/x-portable-greymap;application/pcx;image/svg+xml;image/svg-xml; diff --git a/debian/.gitignore b/debian/.gitignore index e556b3e..bd029f5 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -1,6 +1,7 @@ /*.debhelper /*.log /*.substvars +/debhelper-build-stamp /files /lximage-qt/ diff --git a/debian/changelog b/debian/changelog index 392694f..bc43518 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +lximage-qt (0.5.0-1) experimental; urgency=medium + + * Cherry-picking upstream release 0.5.0. + * Added build-dependency libqt5svg5-dev + * Bumped compat to 10 + * Bumped minimum version debhelper (>= 10) + * Bumped minimum version libfm-qt-dev (>= 0.11.1) + * Bumped minimum version liblxqt0-dev (>= 0.11.0) + * Bumped minimum version libqt5xdg-dev (>= 2.0.0) + * Removed --parallel from rules, standard compat 10 + + -- Alf Gaida Sun, 25 Sep 2016 22:49:20 +0200 + lximage-qt (0.4.1~38-gf8fc532-1) experimental; urgency=medium * Cherry-picking upstream version 0.4.1~38-gf8fc532. diff --git a/debian/control b/debian/control index 4f0807c..0073ccb 100644 --- a/debian/control +++ b/debian/control @@ -10,19 +10,20 @@ Build-Depends: debhelper (>= 10), libexif-dev, libglib2.0-dev, libfm-dev, - libfm-qt-dev (>= 0.11.1~), + libfm-qt-dev (>= 0.11.1), libkf5windowsystem-dev, - liblxqt0-dev (>= 0.10.96~), + liblxqt0-dev (>= 0.11.0), libmenu-cache-dev, + libqt5svg5-dev, libqt5x11extras5-dev, - libqt5xdg-dev (>= 1.3.1~), + libqt5xdg-dev (>= 2.0.0), libx11-dev, libxfixes-dev, pkg-config, qttools5-dev, qttools5-dev-tools Standards-Version: 3.9.8 -Vcs-Browser: https://anonscm.debian.org/git/pkg-lxqt/lximage-qt.git/?h=debian/experimental +Vcs-Browser: https://anonscm.debian.org/cgit/pkg-lxqt/lximage-qt.git/?h=debian/experimental Vcs-Git: https://anonscm.debian.org/git/pkg-lxqt/lximage-qt.git -b debian/experimental Homepage: https://github.com/lxde/lximage-qt diff --git a/debian/rules b/debian/rules index 5858ca7..9dbedc2 100755 --- a/debian/rules +++ b/debian/rules @@ -6,8 +6,7 @@ export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: - dh ${@} --buildsystem cmake\ - --parallel + dh ${@} --buildsystem cmake override_dh_auto_configure: dh_auto_configure -- \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc75837..eb7e8ae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,3 @@ -# set visibility to hidden to hide symbols, unlesss they're exporeted manually in the code -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") - include_directories( ${X11_INCLUDE_DIR} ${XFIXES_INCLUDE_DIRS} @@ -81,7 +78,7 @@ add_definitions( -DLXIMAGE_VERSION="${LXIMAGE_VERSION}" ) -set(QT_LIBRARIES Qt5::Widgets Qt5::Core Qt5::DBus Qt5::PrintSupport Qt5::X11Extras) +set(QT_LIBRARIES Qt5::Widgets Qt5::Core Qt5::DBus Qt5::PrintSupport Qt5::X11Extras Qt5::Svg) target_link_libraries(lximage-qt fm-qt diff --git a/src/application.cpp b/src/application.cpp index 33e8390..e84024b 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -35,8 +35,8 @@ static const char* ifaceName = "org.lxde.LxImage.Application"; Application::Application(int& argc, char** argv): QApplication(argc, argv), - windowCount_(0), - libFm() { + libFm(), + windowCount_(0) { setApplicationVersion(LXIMAGE_VERSION); } @@ -63,7 +63,7 @@ bool Application::init(int argc, char** argv) { new ApplicationAdaptor(this); dbus.registerObject("/Application", this); - connect(this, SIGNAL(aboutToQuit()), SLOT(onAboutToQuit())); + connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit); if(settings_.useFallbackIconTheme()) QIcon::setThemeName(settings_.fallbackIconTheme()); @@ -179,6 +179,5 @@ void Application::editPreferences() { } void Application::onAboutToQuit() { - qDebug("aboutToQuit"); settings_.save(); } diff --git a/src/application.h b/src/application.h index f1af02a..618a092 100644 --- a/src/application.h +++ b/src/application.h @@ -41,11 +41,9 @@ public: void addWindow() { // call this when you create a new toplevel window ++windowCount_; - qDebug("add window"); } void removeWindow() { // call this when you destroy a toplevel window - qDebug("remove window"); --windowCount_; if(0 == windowCount_) quit(); diff --git a/src/imageview.cpp b/src/imageview.cpp index 173c179..015e925 100644 --- a/src/imageview.cpp +++ b/src/imageview.cpp @@ -24,21 +24,25 @@ #include #include #include -#include #include #include #include +#include + +#define CURSOR_HIDE_DELY 3000 namespace LxImage { ImageView::ImageView(QWidget* parent): QGraphicsView(parent), - imageItem_(new QGraphicsRectItem()), scene_(new QGraphicsScene(this)), - gifMovie_(NULL), + imageItem_(new QGraphicsRectItem()), + gifMovie_(nullptr), + cacheTimer_(nullptr), + cursorTimer_(nullptr), + scaleFactor_(1.0), autoZoomFit_(false), - cacheTimer_(NULL), - scaleFactor_(1.0) { + isSVG(false) { setViewportMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0); @@ -58,6 +62,10 @@ ImageView::~ImageView() { cacheTimer_->stop(); delete cacheTimer_; } + if(cursorTimer_) { + cursorTimer_->stop(); + delete cursorTimer_; + } } @@ -88,6 +96,34 @@ void ImageView::mouseDoubleClickEvent(QMouseEvent* event) { QAbstractScrollArea::mouseDoubleClickEvent(event); } +void ImageView::mousePressEvent(QMouseEvent * event) { + QGraphicsView::mousePressEvent(event); + if(cursorTimer_) cursorTimer_->stop(); +} + +void ImageView::mouseReleaseEvent(QMouseEvent* event) { + QGraphicsView::mouseReleaseEvent(event); + if(cursorTimer_) cursorTimer_->start(CURSOR_HIDE_DELY); +} + +void ImageView::mouseMoveEvent(QMouseEvent* event) { + QGraphicsView::mouseMoveEvent(event); + if(cursorTimer_ && (viewport()->cursor().shape() == Qt::BlankCursor + || viewport()->cursor().shape() == Qt::OpenHandCursor)) { + cursorTimer_->start(CURSOR_HIDE_DELY); // restart timer + viewport()->setCursor(Qt::OpenHandCursor); + } +} + +void ImageView::focusInEvent(QFocusEvent* event) { + QGraphicsView::focusInEvent(event); + if(cursorTimer_ && (viewport()->cursor().shape() == Qt::BlankCursor + || viewport()->cursor().shape() == Qt::OpenHandCursor)) { + cursorTimer_->start(CURSOR_HIDE_DELY); // restart timer + viewport()->setCursor(Qt::OpenHandCursor); + } +} + void ImageView::resizeEvent(QResizeEvent* event) { QGraphicsView::resizeEvent(event); if(autoZoomFit_) @@ -136,10 +172,13 @@ void ImageView::zoomOriginal() { } void ImageView::setImage(QImage image, bool show) { - if(gifMovie_ && show) { // a gif animation was shown + if(show && (gifMovie_ || isSVG)) { // a gif animation or SVG file was shown before scene_->clear(); - delete gifMovie_; - gifMovie_ = NULL; + isSVG = false; + if(gifMovie_) { // should be deleted explicitly + delete gifMovie_; + gifMovie_ = nullptr; + } // recreate the rect item imageItem_ = new QGraphicsRectItem(); imageItem_->hide(); @@ -168,21 +207,24 @@ void ImageView::setImage(QImage image, bool show) { } void ImageView::setGifAnimation(QString fileName) { - QImage image(fileName); - if(image.isNull()) { - image_ = QImage(); - imageItem_->hide(); - imageItem_->setBrush(QBrush()); + /* the built-in gif reader gives the first frame, which won't + be shown but is used for tracking position and dimensions */ + image_ = QImage(fileName); + if(image_.isNull()) { + if(imageItem_) { + imageItem_->hide(); + imageItem_->setBrush(QBrush()); + } scene_->setSceneRect(0, 0, 0, 0); } else { scene_->clear(); - imageItem_ = NULL; // it's deleted by clear(); + imageItem_ = nullptr; // it's deleted by clear(); if(gifMovie_) { delete gifMovie_; - gifMovie_ = NULL; + gifMovie_ = nullptr; } - QPixmap pix(image.size()); + QPixmap pix(image_.size()); pix.fill(Qt::transparent); QGraphicsItem *gifItem = new QGraphicsPixmapItem(pix); QLabel *gifLabel = new QLabel(); @@ -192,9 +234,6 @@ void ImageView::setGifAnimation(QString fileName) { gifLabel->setMovie(gifMovie_); gifWidget->setWidget(gifLabel); gifMovie_->start(); - /* the first frame won't be shown but will be - used for tracking position and dimensions */ - image_ = gifMovie_->currentImage(); scene_->addItem(gifItem); scene_->setSceneRect(gifItem->boundingRect()); } @@ -204,6 +243,29 @@ void ImageView::setGifAnimation(QString fileName) { queueGenerateCache(); // deletes the cache timer in this case } +void ImageView::setSVG(QString fileName) { + image_ = QImage(fileName); // for tracking position and dimensions + if(image_.isNull()) { + if(imageItem_) { + imageItem_->hide(); + imageItem_->setBrush(QBrush()); + } + scene_->setSceneRect(0, 0, 0, 0); + } + else { + scene_->clear(); + imageItem_ = nullptr; + isSVG = true; + QGraphicsSvgItem *svgItem = new QGraphicsSvgItem(fileName); + scene_->addItem(svgItem); + scene_->setSceneRect(svgItem->boundingRect()); + } + + if(autoZoomFit_) + zoomFit(); + queueGenerateCache(); // deletes the cache timer in this case +} + void ImageView::setScaleFactor(double factor) { if(factor != scaleFactor_) { scaleFactor_ = factor; @@ -215,7 +277,7 @@ void ImageView::setScaleFactor(double factor) { void ImageView::paintEvent(QPaintEvent* event) { // if the image is scaled and we have a high quality cached image - if(scaleFactor_ != 1.0 && !cachedPixmap_.isNull()) { + if(imageItem_ && scaleFactor_ != 1.0 && !cachedPixmap_.isNull()) { // rectangle of the whole image in viewport coordinate QRect viewportImageRect = sceneToViewport(imageItem_->rect()); // the visible part of the image. @@ -244,20 +306,20 @@ void ImageView::queueGenerateCache() { cachedPixmap_ = QPixmap(); // we don't need to cache the scaled image if its the same as the original image (scale:1.0) - // no cache for gif animations either - if(scaleFactor_ == 1.0 || gifMovie_) { + // no cache for gif animations or SVG images either + if(scaleFactor_ == 1.0 || gifMovie_ || isSVG) { if(cacheTimer_) { cacheTimer_->stop(); delete cacheTimer_; - cacheTimer_ = NULL; + cacheTimer_ = nullptr; } return; } - if(!cacheTimer_ && !gifMovie_) { + if(!cacheTimer_) { cacheTimer_ = new QTimer(); cacheTimer_->setSingleShot(true); - connect(cacheTimer_, SIGNAL(timeout()), SLOT(generateCache())); + connect(cacheTimer_, &QTimer::timeout, this, &ImageView::generateCache); } if(cacheTimer_) cacheTimer_->start(200); // restart the timer @@ -267,7 +329,9 @@ void ImageView::queueGenerateCache() { void ImageView::generateCache() { // disable the one-shot timer cacheTimer_->deleteLater(); - cacheTimer_ = NULL; + cacheTimer_ = nullptr; + + if(!imageItem_ || image_.isNull()) return; // generate a cache for "the visible part" of the scaled image // rectangle of the whole image in viewport coordinate @@ -295,12 +359,6 @@ void ImageView::generateCache() { // convert the cached scaled image to pixmap cachedPixmap_ = QPixmap::fromImage(scaled); viewport()->update(); - /* - qDebug() << "viewportImageRect" << viewportImageRect - << "cachedRect_" << cachedRect_ - << "cachedSceneRect_" << cachedSceneRect_ - << "subRect" << subRect; - */ } // convert viewport coordinate to the original image (not scaled). @@ -317,5 +375,26 @@ QRect ImageView::sceneToViewport(const QRectF& rect) { return QRect(topLeft, bottomRight); } +void ImageView::blankCursor() { + viewport()->setCursor(Qt::BlankCursor); +} + +void ImageView::hideCursor(bool enable) { + if(enable) { + if(cursorTimer_) delete cursorTimer_; + cursorTimer_ = new QTimer(this); + cursorTimer_->setSingleShot(true); + connect(cursorTimer_, &QTimer::timeout, this, &ImageView::blankCursor); + if(viewport()->cursor().shape() == Qt::OpenHandCursor) + cursorTimer_->start(CURSOR_HIDE_DELY); + } + else if (cursorTimer_) { + cursorTimer_->stop(); + delete cursorTimer_; + cursorTimer_ = nullptr; + if(viewport()->cursor().shape() == Qt::BlankCursor) + viewport()->setCursor(Qt::OpenHandCursor); + } +} } // namespace LxImage diff --git a/src/imageview.h b/src/imageview.h index 5fb9b41..ac566cf 100644 --- a/src/imageview.h +++ b/src/imageview.h @@ -42,6 +42,7 @@ public: void setImage(QImage image, bool show = true); void setGifAnimation(QString fileName); + void setSVG(QString fileName); QImage image() { return image_; @@ -67,9 +68,16 @@ public: autoZoomFit_ = value; } + // if set to true, hides the cursor after 3s of inactivity + void hideCursor(bool enable); + protected: virtual void wheelEvent(QWheelEvent* event); virtual void mouseDoubleClickEvent(QMouseEvent* event); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void mouseMoveEvent(QMouseEvent* event); + virtual void focusInEvent(QFocusEvent* event); virtual void resizeEvent(QResizeEvent* event); virtual void paintEvent(QPaintEvent* event); @@ -80,6 +88,7 @@ private: private Q_SLOTS: void generateCache(); + void blankCursor(); private: QGraphicsScene* scene_; // the topmost container of all graphic items @@ -90,8 +99,10 @@ private: QRect cachedRect_; // rectangle containing the cached region (in viewport coordinate) QRect cachedSceneRect_; // rectangle containing the cached region (in scene/original image coordinate) QTimer* cacheTimer_; + QTimer *cursorTimer_; // for hiding cursor in fullscreen mode double scaleFactor_; bool autoZoomFit_; + bool isSVG; // is the image an SVG file? }; } diff --git a/src/job.cpp b/src/job.cpp index 4839ae7..a7afd99 100644 --- a/src/job.cpp +++ b/src/job.cpp @@ -35,7 +35,7 @@ Job::~Job() { // This is called from the worker thread, not main thread gboolean Job::_jobThread(GIOSchedulerJob* job, GCancellable* cancellable, Job* pThis) { - bool ret = pThis->run(); + pThis->run(); // do final step in the main thread if(!g_cancellable_is_cancelled(pThis->cancellable_)) g_io_scheduler_job_send_to_mainloop(job, GSourceFunc(_finish), pThis, NULL); diff --git a/src/loadimagejob.cpp b/src/loadimagejob.cpp index 67a733b..a57cb55 100644 --- a/src/loadimagejob.cpp +++ b/src/loadimagejob.cpp @@ -29,8 +29,8 @@ using namespace LxImage; LoadImageJob::LoadImageJob(MainWindow* window, FmPath* filePath): Job(), - path_(fm_path_ref(filePath)), - mainWindow_(window) { + mainWindow_(window), + path_(fm_path_ref(filePath)) { } LoadImageJob::~LoadImageJob() { @@ -71,7 +71,7 @@ bool LoadImageJob::run() { // use libexif to extract additional info embedded in jpeg files ExifLoader *exif_loader = exif_loader_new(); // write image data to exif loader - int ret = exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size()); + exif_loader_write(exif_loader, (unsigned char*)imageBuffer.data().constData(), (unsigned int)imageBuffer.size()); ExifData *exif_data = exif_loader_get_data(exif_loader); exif_loader_unref(exif_loader); if(exif_data) { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7d78b5e..94b4795 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include "application.h" #include #include @@ -46,21 +46,21 @@ using namespace LxImage; MainWindow::MainWindow(): QMainWindow(), - currentFile_(NULL), - slideShowTimer_(NULL), - // currentFileInfo_(NULL), - loadJob_(NULL), - saveJob_(NULL), - folder_(NULL), - folderPath_(NULL), + contextMenu_(new QMenu(this)), + slideShowTimer_(nullptr), + image_(), + currentFile_(nullptr), + // currentFileInfo_(nullptr), + imageModified_(false), + folder_(nullptr), + folderPath_(nullptr), folderModel_(new Fm::FolderModel()), proxyModel_(new Fm::ProxyFolderModel()), modelFilter_(new ModelFilter()), - imageModified_(false), - contextMenu_(new QMenu(this)), - thumbnailsDock_(NULL), - thumbnailsView_(NULL), - image_() { + thumbnailsDock_(nullptr), + thumbnailsView_(nullptr), + loadJob_(nullptr), + saveJob_(nullptr) { setAttribute(Qt::WA_DeleteOnClose); // FIXME: check if current image is saved before close @@ -70,8 +70,8 @@ MainWindow::MainWindow(): Settings& settings = app->settings(); ui.setupUi(this); - connect(ui.actionScreenshot, SIGNAL(triggered(bool)), app, SLOT(screenshot())); - connect(ui.actionPreferences, SIGNAL(triggered(bool)), app ,SLOT(editPreferences())); + connect(ui.actionScreenshot, &QAction::triggered, app, &Application::screenshot); + connect(ui.actionPreferences, &QAction::triggered, app , &Application::editPreferences); proxyModel_->addFilter(modelFilter_); proxyModel_->sort(Fm::FolderModel::ColumnFileName, Qt::AscendingOrder); @@ -79,7 +79,7 @@ MainWindow::MainWindow(): // build context menu ui.view->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui.view, SIGNAL(customContextMenuRequested(QPoint)), SLOT(onContextMenu(QPoint))); + connect(ui.view, &QWidget::customContextMenuRequested, this, &MainWindow::onContextMenu); // install an event filter on the image view ui.view->installEventFilter(this); @@ -107,11 +107,11 @@ MainWindow::MainWindow(): // create shortcuts QShortcut* shortcut = new QShortcut(Qt::Key_Left, this); - connect(shortcut, SIGNAL(activated()), SLOT(on_actionPrevious_triggered())); + connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionPrevious_triggered); shortcut = new QShortcut(Qt::Key_Right, this); - connect(shortcut, SIGNAL(activated()), SLOT(on_actionNext_triggered())); + connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionNext_triggered); shortcut = new QShortcut(Qt::Key_Escape, this); - connect(shortcut, SIGNAL(activated()), SLOT(onExitFullscreen())); + connect(shortcut, &QShortcut::activated, this, &MainWindow::onExitFullscreen); } MainWindow::~MainWindow() { @@ -174,7 +174,6 @@ void MainWindow::on_actionZoomOut_triggered() { } void MainWindow::onFolderLoaded(FmFolder* folder) { - qDebug("Finish loading: %d files", proxyModel_->rowCount()); // if currently we're showing a file, get its index in the folder now // since the folder is fully loaded. if(currentFile_ && !currentIndex_.isValid()) { @@ -207,14 +206,14 @@ void MainWindow::pasteImage(QImage newImage) { // cancel loading of current image if(loadJob_) { loadJob_->cancel(); // the job object will be freed automatically later - loadJob_ = NULL; + loadJob_ = nullptr; } setModified(true); currentIndex_ = QModelIndex(); // invaludate current index since we don't have a folder model now if(currentFile_) fm_path_unref(currentFile_); - currentFile_ = NULL; + currentFile_ = nullptr; image_ = newImage; ui.view->setImage(image_); @@ -302,7 +301,13 @@ void MainWindow::on_actionSave_triggered() { void MainWindow::on_actionSaveAs_triggered() { if(saveJob_) // if we're currently saving another file return; - QString fileName = saveFileName(currentFile_ ? Fm::Path(currentFile_).displayName() : QString()); + QString baseName; + if(currentFile_) { + char* dispName = fm_path_display_name(currentFile_, false); + baseName = QString::fromUtf8(dispName); + g_free(dispName); + } + QString fileName = saveFileName(baseName); if(!fileName.isEmpty()) { FmPath* path = fm_path_new_for_str(qPrintable(fileName)); // save the image file asynchronously @@ -354,7 +359,6 @@ void MainWindow::on_actionNext_triggered() { FmFileInfo* info = proxyModel_->fileInfoFromIndex(index); if(info) { FmPath* path = fm_file_info_get_path(info); - qDebug("try load: %s", fm_path_get_basename(path)); loadImage(path, index); } } @@ -365,7 +369,6 @@ void MainWindow::on_actionPrevious_triggered() { return; if(currentIndex_.isValid()) { QModelIndex index; - qDebug("current row: %d", currentIndex_.row()); if(currentIndex_.row() > 0) index = proxyModel_->index(currentIndex_.row() - 1, 0); else @@ -373,7 +376,6 @@ void MainWindow::on_actionPrevious_triggered() { FmFileInfo* info = proxyModel_->fileInfoFromIndex(index); if(info) { FmPath* path = fm_file_info_get_path(info); - qDebug("try load: %s", fm_path_get_basename(path)); loadImage(path, index); } } @@ -385,7 +387,6 @@ void MainWindow::on_actionFirst_triggered() { FmFileInfo* info = proxyModel_->fileInfoFromIndex(index); if(info) { FmPath* path = fm_file_info_get_path(info); - qDebug("try load: %s", fm_path_get_basename(path)); loadImage(path, index); } } @@ -396,8 +397,7 @@ void MainWindow::on_actionLast_triggered() { if(index.isValid()) { FmFileInfo* info = proxyModel_->fileInfoFromIndex(index); if(info) { - FmPath* path = fm_file_info_get_path(info); - qDebug("try load: %s", fm_path_get_basename(path)); + FmPath* path = fm_file_info_get_path(info);; loadImage(path, index); } } @@ -423,7 +423,7 @@ void MainWindow::loadFolder(FmPath* newFolderPath) { // the image is loaded (the method is only called if the loading is not cancelled) void MainWindow::onImageLoaded(LoadImageJob* job) { - loadJob_ = NULL; // the job object will be freed later automatically + loadJob_ = nullptr; // the job object will be freed later automatically image_ = job->image(); ui.view->setAutoZoomFit(true); @@ -448,12 +448,11 @@ void MainWindow::onImageSaved(SaveImageJob* job) { if(!job->error()) { setModified(false); } - saveJob_ = NULL; + saveJob_ = nullptr; } // filter events of other objects, mainly the image view. bool MainWindow::eventFilter(QObject* watched, QEvent* event) { - // qDebug() << event; if(watched == ui.view) { // we got an event for the image view switch(event->type()) { case QEvent::Wheel: { // mouse wheel event @@ -585,7 +584,7 @@ void MainWindow::loadImage(FmPath* filePath, QModelIndex index) { // cancel loading of current image if(loadJob_) { loadJob_->cancel(); // the job object will be freed automatically later - loadJob_ = NULL; + loadJob_ = nullptr; } if(imageModified_) { // TODO: ask the user to save the modified image? @@ -601,21 +600,27 @@ void MainWindow::loadImage(FmPath* filePath, QModelIndex index) { image_ = QImage(); const char* basename = fm_path_get_basename(currentFile_); - char* mimeType = g_content_type_guess(basename, NULL, 0, NULL); - if(mimeType && strcmp(mimeType, "image/gif") == 0) { - g_free(mimeType); - char *file_Name = fm_path_to_str(currentFile_); - QString fileName(file_Name); - g_free(file_Name); + char* mime_type = g_content_type_guess(basename, NULL, 0, NULL); + QString mimeType; + if (mime_type) { + mimeType = QString(mime_type); + g_free(mime_type); + } + if(mimeType == "image/gif" + || mimeType == "image/svg+xml" || mimeType == "image/svg+xml-compressed") { + char *file_name = fm_path_to_str(currentFile_); + QString fileName(file_name); + g_free(file_name); ui.view->setAutoZoomFit(true); // like in onImageLoaded() - ui.view->setGifAnimation(fileName); + if(mimeType == "image/gif") + ui.view->setGifAnimation(fileName); + else + ui.view->setSVG(fileName); image_ = ui.view->image(); updateUI(); show(); } else { - if(mimeType) - g_free(mimeType); // start a new gio job to load the specified image loadJob_ = new LoadImageJob(this, filePath); loadJob_->start(); @@ -633,55 +638,55 @@ void MainWindow::saveImage(FmPath* filePath) { // FIXME: add a cancel button to the UI? update status bar? } -QGraphicsItem* MainWindow::getGifItem() { - if(!ui.view->items().isEmpty()) { - QGraphicsItem *gifItem = ui.view->items().at(0); - if(gifItem->isWidget()) // we have gif animation - return gifItem; - } - return NULL; +QGraphicsItem* MainWindow::getGraphicsItem() { + if(!ui.view->items().isEmpty()) + return ui.view->items().at(0); + return nullptr; } void MainWindow::on_actionRotateClockwise_triggered() { - QGraphicsItem *gifItem = getGifItem(); + QGraphicsItem *graphItem = getGraphicsItem(); if(!image_.isNull()) { QTransform transform; transform.rotate(90.0); image_ = image_.transformed(transform, Qt::SmoothTransformation); - /* when this is a gif animation, we need to rotate the first frame + /* when this is GIF or SVG, we need to rotate its corresponding QImage without showing it to have the right measure for auto-zooming */ - ui.view->setImage(image_, gifItem ? false : true); + ui.view->setImage(image_, graphItem->isWidget() // we have gif animation + || static_cast(graphItem) // an SVG image + ? false : true); setModified(true); } - if(gifItem) { + if(graphItem) { QTransform transform; - transform.translate(gifItem->sceneBoundingRect().height(), 0); + transform.translate(graphItem->sceneBoundingRect().height(), 0); transform.rotate(90); // we need to apply transformations in the reverse order - QTransform prevTrans = gifItem->transform(); - gifItem->setTransform(transform, false); - gifItem->setTransform(prevTrans, true); + QTransform prevTrans = graphItem->transform(); + graphItem->setTransform(transform, false); + graphItem->setTransform(prevTrans, true); } } void MainWindow::on_actionRotateCounterclockwise_triggered() { - QGraphicsItem *gifItem = getGifItem(); + QGraphicsItem *graphItem = getGraphicsItem(); if(!image_.isNull()) { QTransform transform; transform.rotate(-90.0); image_ = image_.transformed(transform, Qt::SmoothTransformation); - ui.view->setImage(image_, gifItem ? false : true); + ui.view->setImage(image_, graphItem->isWidget() || static_cast(graphItem) + ? false : true); setModified(true); } - if(gifItem) { + if(graphItem) { QTransform transform; - transform.translate(0, gifItem->sceneBoundingRect().width()); + transform.translate(0, graphItem->sceneBoundingRect().width()); transform.rotate(-90); - QTransform prevTrans = gifItem->transform(); - gifItem->setTransform(transform, false); - gifItem->setTransform(prevTrans, true); + QTransform prevTrans = graphItem->transform(); + graphItem->setTransform(transform, false); + graphItem->setTransform(prevTrans, true); } } @@ -708,37 +713,37 @@ void MainWindow::on_actionPaste_triggered() { } void MainWindow::on_actionFlipVertical_triggered() { - if(QGraphicsItem *gifItem = getGifItem()) { + bool hasQGraphicsItem(false); + if(QGraphicsItem *graphItem = getGraphicsItem()) { + hasQGraphicsItem = true; QTransform transform; transform.scale(1, -1); - transform.translate(0, -gifItem->sceneBoundingRect().height()); - QTransform prevTrans = gifItem->transform(); - gifItem->setTransform(transform, false); - gifItem->setTransform(prevTrans, true); - setModified(true); - /* we don't need to flip the first frame because its position - and dimensions are the same as before while it isn't shown */ + transform.translate(0, -graphItem->sceneBoundingRect().height()); + QTransform prevTrans = graphItem->transform(); + graphItem->setTransform(transform, false); + graphItem->setTransform(prevTrans, true); } - else if(!image_.isNull()) { + if(!image_.isNull()) { image_ = image_.mirrored(false, true); - ui.view->setImage(image_); + ui.view->setImage(image_, !hasQGraphicsItem); setModified(true); } } void MainWindow::on_actionFlipHorizontal_triggered() { - if(QGraphicsItem *gifItem = getGifItem()) { + bool hasQGraphicsItem(false); + if(QGraphicsItem *graphItem = getGraphicsItem()) { + hasQGraphicsItem = true; QTransform transform; transform.scale(-1, 1); - transform.translate(-gifItem->sceneBoundingRect().width(), 0); - QTransform prevTrans = gifItem->transform(); - gifItem->setTransform(transform, false); - gifItem->setTransform(prevTrans, true); - setModified(true); + transform.translate(-graphItem->sceneBoundingRect().width(), 0); + QTransform prevTrans = graphItem->transform(); + graphItem->setTransform(transform, false); + graphItem->setTransform(prevTrans, true); } - else if(!image_.isNull()) { - image_ = image_.mirrored(true, false); - ui.view->setImage(image_); + if(!image_.isNull()) { + image_ = image_.mirrored(true, true); + ui.view->setImage(image_, !hasQGraphicsItem); setModified(true); } } @@ -767,11 +772,9 @@ void MainWindow::on_actionPrint_triggered() { QRect pageRect = printer.pageRect(); int cols = (image_.width() / pageRect.width()) + (image_.width() % pageRect.width() ? 1 : 0); int rows = (image_.height() / pageRect.height()) + (image_.height() % pageRect.height() ? 1 : 0); - // qDebug() << "page:" << printer.pageRect() << "image:" << image_.size() << "cols, rows:" << cols << rows; for(int row = 0; row < rows; ++row) { for(int col = 0; col < cols; ++col) { QRect srcRect(pageRect.width() * col, pageRect.height() * row, pageRect.width(), pageRect.height()); - // qDebug() << "row:" << row << "col:" << col << "src:" << srcRect << "page:" << printer.pageRect(); painter.drawImage(QPoint(0, 0), image_, srcRect); if(col + 1 == cols && row + 1 == rows) // this is the last page break; @@ -795,7 +798,7 @@ void MainWindow::on_actionSlideShow_triggered(bool checked) { if(!slideShowTimer_) { slideShowTimer_ = new QTimer(); // switch to the next image when timeout - connect(slideShowTimer_, SIGNAL(timeout()), SLOT(on_actionNext_triggered())); + connect(slideShowTimer_, &QTimer::timeout, this, &MainWindow::on_actionNext_triggered); } Application* app = static_cast(qApp); slideShowTimer_->start(app->settings().slideShowInterval() * 1000); @@ -805,7 +808,7 @@ void MainWindow::on_actionSlideShow_triggered(bool checked) { else { if(slideShowTimer_) { delete slideShowTimer_; - slideShowTimer_ = NULL; + slideShowTimer_ = nullptr; ui.actionSlideShow->setIcon(QIcon::fromTheme("media-playback-start")); } } @@ -838,15 +841,16 @@ void MainWindow::setShowThumbnails(bool show) { QCoreApplication::processEvents(); listView->scrollTo(currentIndex_, QAbstractItemView::PositionAtCenter); } - connect(thumbnailsView_->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(onThumbnailSelChanged(QItemSelection,QItemSelection))); + connect(thumbnailsView_->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &MainWindow::onThumbnailSelChanged); } } else { if(thumbnailsDock_) { delete thumbnailsView_; - thumbnailsView_ = NULL; + thumbnailsView_ = nullptr; delete thumbnailsDock_; - thumbnailsDock_ = NULL; + thumbnailsDock_ = nullptr; } proxyModel_->setShowThumbnails(false); } @@ -876,6 +880,7 @@ void MainWindow::changeEvent(QEvent* event) { addAction(action); } addActions(ui.menubar->actions()); + ui.view->hideCursor(true); } else { // restore to normal window mode ui.view->setFrameStyle(QFrame::StyledPanel|QFrame::Sunken); @@ -890,6 +895,7 @@ void MainWindow::changeEvent(QEvent* event) { ui.statusBar->show(); if(thumbnailsDock_) thumbnailsDock_->show(); + ui.view->hideCursor(false); } } QWidget::changeEvent(event); diff --git a/src/mainwindow.h b/src/mainwindow.h index 3350395..0139484 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -126,7 +126,7 @@ private: void updateUI(); void setModified(bool modified); QModelIndex indexFromPath(FmPath* filePath); - QGraphicsItem* getGifItem(); + QGraphicsItem* getGraphicsItem(); // GObject related signal handers and callbacks static void _onFolderLoaded(FmFolder* folder, MainWindow* _this) { diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 4c5487a..ad78add 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -221,7 +221,7 @@ Zoom &In - Ctrl++ + Ctrl+= @@ -288,6 +288,9 @@ Original Size + + Ctrl+0 + diff --git a/src/preferencesdialog.cpp b/src/preferencesdialog.cpp index 73fb8b3..123345c 100644 --- a/src/preferencesdialog.cpp +++ b/src/preferencesdialog.cpp @@ -96,8 +96,6 @@ static void findIconThemesInDir(QHash& iconThemes, QString dir } void PreferencesDialog::initIconThemes(Settings& settings) { - Application* app = static_cast(qApp); - // check if auto-detection is done (for example, from xsettings) if(settings.useFallbackIconTheme()) { // auto-detection failed // load xdg icon themes and select the current one diff --git a/src/saveimagejob.cpp b/src/saveimagejob.cpp index d3ded31..7922d33 100644 --- a/src/saveimagejob.cpp +++ b/src/saveimagejob.cpp @@ -28,8 +28,8 @@ using namespace LxImage; SaveImageJob::SaveImageJob(MainWindow* window, FmPath* filePath): Job(), - path_(fm_path_ref(filePath)), mainWindow_(window), + path_(fm_path_ref(filePath)), image_(window->image()) { } diff --git a/src/screenshotdialog.cpp b/src/screenshotdialog.cpp index ff922ee..b5c442d 100644 --- a/src/screenshotdialog.cpp +++ b/src/screenshotdialog.cpp @@ -25,6 +25,7 @@ #include #include "application.h" #include +#include #include #include @@ -83,7 +84,7 @@ QRect ScreenshotDialog::windowFrame(WId wid) { int x, y; // translate to root coordinate XTranslateCoordinates(QX11Info::display(), wid, wa.root, 0, 0, &x, &y, &child); - qDebug("%d, %d, %d, %d", x, y, wa.width, wa.height); + //qDebug("%d, %d, %d, %d", x, y, wa.width, wa.height); result.setRect(x, y, wa.width, wa.height); // get the frame widths added by the window manager @@ -140,38 +141,42 @@ void ScreenshotDialog::doScreenshot() { } } - QPixmap pixmap; - pixmap = QPixmap::grabWindow(wid, x, y, width, height); - QImage image = pixmap.toImage(); - - if(hasXfixes_ && ui.includeCursor->isChecked()) { - // capture the cursor if needed - XFixesCursorImage* cursor = XFixesGetCursorImage(QX11Info::display()); - if(cursor) { - if(cursor->pixels) { // pixles should be an ARGB array - QImage cursorImage; - if(sizeof(long) == 4) { - // FIXME: will we encounter byte-order problems here? - cursorImage = QImage((uchar*)cursor->pixels, cursor->width, cursor->height, QImage::Format_ARGB32); + QImage image; + QScreen *screen = QGuiApplication::primaryScreen(); + if(screen) { + QPixmap pixmap = screen->grabWindow(wid, x, y, width, height); + image = pixmap.toImage(); + + if(hasXfixes_ && ui.includeCursor->isChecked()) { + // capture the cursor if needed + XFixesCursorImage* cursor = XFixesGetCursorImage(QX11Info::display()); + if(cursor) { + if(cursor->pixels) { // pixles should be an ARGB array + QImage cursorImage; + if(sizeof(long) == 4) { + // FIXME: will we encounter byte-order problems here? + cursorImage = QImage((uchar*)cursor->pixels, cursor->width, cursor->height, QImage::Format_ARGB32); + } + else { // XFixes returns long integers which is not 32 bit on 64 bit systems. + long len = cursor->width * cursor->height; + quint32* buf = new quint32[len]; + for(long i = 0; i < len; ++i) + buf[i] = (quint32)cursor->pixels[i]; + cursorImage = QImage((uchar*)buf, cursor->width, cursor->height, QImage::Format_ARGB32, [](void* b) { delete[] (quint32*)b; }, buf); + } + // paint the cursor on the current image + QPainter painter(&image); + painter.drawImage(cursor->x - cursor->xhot, cursor->y - cursor->yhot, cursorImage); } - else { // XFixes returns long integers which is not 32 bit on 64 bit systems. - long len = cursor->width * cursor->height; - quint32* buf = new quint32[len]; - for(long i = 0; i < len; ++i) - buf[i] = (quint32)cursor->pixels[i]; - cursorImage = QImage((uchar*)buf, cursor->width, cursor->height, QImage::Format_ARGB32, [](void* b) { delete[] (quint32*)b; }, buf); - } - // paint the cursor on the current image - QPainter painter(&image); - painter.drawImage(cursor->x - cursor->xhot, cursor->y - cursor->yhot, cursorImage); + XFree(cursor); } - XFree(cursor); } } Application* app = static_cast(qApp); MainWindow* window = app->createWindow(); - window->pasteImage(image); + if(!image.isNull()) + window->pasteImage(image); window->show(); deleteLater(); // destroy ourself diff --git a/src/settings.cpp b/src/settings.cpp index b8a29e3..3dcf7b7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -27,11 +27,11 @@ using namespace LxImage; Settings::Settings(): useFallbackIconTheme_(QIcon::themeName().isEmpty() || QIcon::themeName() == "hicolor"), bgColor_(255, 255, 255), + fullScreenBgColor_(0, 0, 0), showThumbnails_(false), showSidePane_(false), - fullScreenBgColor_(0, 0, 0), - fallbackIconTheme_("oxygen"), slideShowInterval_(5), + fallbackIconTheme_("oxygen"), fixedWindowWidth_(640), fixedWindowHeight_(480), lastWindowWidth_(640), @@ -49,7 +49,7 @@ bool Settings::load() { fullScreenBgColor_ = settings.value("fullScreenBgColor", fullScreenBgColor_).value(); // showThumbnails_; // showSidePane_; - int slideShowInterval_ = settings.value("slideShowInterval", slideShowInterval_).toInt(); + slideShowInterval_ = settings.value("slideShowInterval", slideShowInterval_).toInt(); settings.beginGroup("Window"); fixedWindowWidth_ = settings.value("FixedWidth", 640).toInt(); diff --git a/src/translations/lximage-qt-screenshot_ca.desktop b/src/translations/lximage-qt-screenshot_ca.desktop new file mode 100644 index 0000000..2b85929 --- /dev/null +++ b/src/translations/lximage-qt-screenshot_ca.desktop @@ -0,0 +1,4 @@ +#Translations +Name[ca]=Captura de pantalla +GenericName[ca]=Captura de pantalla +Comment[ca]=Preneu una captura de pantalla diff --git a/src/translations/lximage-qt_ca.desktop b/src/translations/lximage-qt_ca.desktop new file mode 100644 index 0000000..402b30a --- /dev/null +++ b/src/translations/lximage-qt_ca.desktop @@ -0,0 +1,4 @@ +#Translations +Name[ca]=LXImage +GenericName[ca]=Visualitzador d'imatges +Comment[ca]=El visualitzador d'imatges de LXQt