diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt index 38ffb0cee8..c3071a3e09 100644 --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -1,619 +1,622 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/qtlockedfile ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ${OCIO_INCLUDE_DIR} ) add_subdirectory( tests ) if (APPLE) find_library(FOUNDATION_LIBRARY Foundation) find_library(APPKIT_LIBRARY AppKit) endif () set(kritaui_LIB_SRCS canvas/kis_canvas_widget_base.cpp canvas/kis_canvas2.cpp canvas/kis_canvas_updates_compressor.cpp canvas/kis_canvas_controller.cpp canvas/kis_display_color_converter.cpp canvas/kis_display_filter.cpp canvas/kis_exposure_gamma_correction_interface.cpp canvas/kis_tool_proxy.cpp canvas/kis_canvas_decoration.cc canvas/kis_coordinates_converter.cpp canvas/kis_grid_manager.cpp canvas/kis_grid_decoration.cpp canvas/kis_grid_config.cpp canvas/kis_prescaled_projection.cpp canvas/kis_qpainter_canvas.cpp canvas/kis_projection_backend.cpp canvas/kis_update_info.cpp canvas/kis_image_patch.cpp canvas/kis_image_pyramid.cpp canvas/kis_infinity_manager.cpp canvas/kis_change_guides_command.cpp canvas/kis_guides_decoration.cpp canvas/kis_guides_manager.cpp canvas/kis_guides_config.cpp canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp canvas/KisSnapPointStrategy.cpp canvas/KisSnapPixelStrategy.cpp canvas/KisMirrorAxisConfig.cpp dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_generator_layer.cpp dialogs/kis_dlg_file_layer.cpp dialogs/kis_dlg_filter.cpp dialogs/kis_dlg_stroke_selection_properties.cpp dialogs/kis_dlg_image_properties.cc dialogs/kis_dlg_layer_properties.cc dialogs/kis_dlg_preferences.cc dialogs/slider_and_spin_box_sync.cpp dialogs/kis_dlg_blacklist_cleanup.cpp dialogs/kis_dlg_layer_style.cpp dialogs/kis_dlg_png_import.cpp dialogs/kis_dlg_import_image_sequence.cpp dialogs/kis_delayed_save_dialog.cpp dialogs/KisSessionManagerDialog.cpp dialogs/KisNewWindowLayoutDialog.cpp dialogs/KisDlgChangeCloneSource.cpp flake/kis_node_dummies_graph.cpp flake/kis_dummies_facade_base.cpp flake/kis_dummies_facade.cpp flake/kis_node_shapes_graph.cpp flake/kis_node_shape.cpp flake/kis_shape_controller.cpp flake/kis_shape_layer.cc flake/kis_shape_layer_canvas.cpp flake/kis_shape_selection.cpp flake/kis_shape_selection_canvas.cpp flake/kis_shape_selection_model.cpp flake/kis_take_all_shapes_command.cpp brushhud/kis_uniform_paintop_property_widget.cpp brushhud/kis_brush_hud.cpp brushhud/kis_round_hud_button.cpp brushhud/kis_dlg_brush_hud_config.cpp brushhud/kis_brush_hud_properties_list.cpp brushhud/kis_brush_hud_properties_config.cpp kis_aspect_ratio_locker.cpp kis_autogradient.cc kis_bookmarked_configurations_editor.cc kis_bookmarked_configurations_model.cc kis_bookmarked_filter_configurations_model.cc KisPaintopPropertiesBase.cpp kis_canvas_resource_provider.cpp kis_derived_resources.cpp kis_categories_mapper.cpp kis_categorized_list_model.cpp kis_categorized_item_delegate.cpp kis_clipboard.cc kis_config.cc KisOcioConfiguration.cpp kis_control_frame.cpp kis_composite_ops_model.cc kis_paint_ops_model.cpp kis_cursor.cc kis_cursor_cache.cpp kis_custom_pattern.cc kis_file_layer.cpp kis_change_file_layer_command.h kis_safe_document_loader.cpp kis_splash_screen.cpp kis_filter_manager.cc kis_filters_model.cc KisImageBarrierLockerWithFeedback.cpp kis_image_manager.cc kis_image_view_converter.cpp kis_import_catcher.cc kis_layer_manager.cc kis_mask_manager.cc kis_mimedata.cpp kis_node_commands_adapter.cpp kis_node_manager.cpp kis_node_juggler_compressed.cpp kis_node_selection_adapter.cpp kis_node_insertion_adapter.cpp KisNodeDisplayModeAdapter.cpp kis_node_model.cpp kis_node_filter_proxy_model.cpp kis_model_index_converter_base.cpp kis_model_index_converter.cpp kis_model_index_converter_show_all.cpp kis_painting_assistant.cc kis_painting_assistants_decoration.cpp KisDecorationsManager.cpp kis_paintop_box.cc kis_paintop_option.cpp kis_paintop_options_model.cpp kis_paintop_settings_widget.cpp kis_popup_palette.cpp kis_png_converter.cpp kis_preference_set_registry.cpp KisResourceServerProvider.cpp KisResourceBundleServerProvider.cpp KisSelectedShapesProxy.cpp kis_selection_decoration.cc kis_selection_manager.cc KisSelectionActionsAdapter.cpp kis_statusbar.cc kis_zoom_manager.cc kis_favorite_resource_manager.cpp kis_workspace_resource.cpp kis_action.cpp kis_action_manager.cpp KisActionPlugin.cpp kis_canvas_controls_manager.cpp kis_tooltip_manager.cpp kis_multinode_property.cpp kis_stopgradient_editor.cpp KisWelcomePageWidget.cpp KisChangeCloneLayersCommand.cpp kisexiv2/kis_exif_io.cpp kisexiv2/kis_exiv2.cpp kisexiv2/kis_iptc_io.cpp kisexiv2/kis_xmp_io.cpp opengl/kis_opengl.cpp opengl/kis_opengl_canvas2.cpp opengl/kis_opengl_canvas_debugger.cpp opengl/kis_opengl_image_textures.cpp opengl/kis_texture_tile.cpp opengl/kis_opengl_shader_loader.cpp opengl/kis_texture_tile_info_pool.cpp opengl/KisOpenGLUpdateInfoBuilder.cpp opengl/KisOpenGLModeProber.cpp opengl/KisScreenInformationAdapter.cpp kis_fps_decoration.cpp tool/KisToolChangesTracker.cpp tool/KisToolChangesTrackerData.cpp tool/kis_selection_tool_helper.cpp tool/kis_selection_tool_config_widget_helper.cpp tool/kis_rectangle_constraint_widget.cpp tool/kis_shape_tool_helper.cpp tool/kis_tool.cc tool/kis_delegated_tool_policies.cpp tool/kis_tool_freehand.cc tool/kis_speed_smoother.cpp tool/kis_painting_information_builder.cpp tool/kis_stabilized_events_sampler.cpp tool/kis_tool_freehand_helper.cpp tool/kis_tool_multihand_helper.cpp tool/kis_figure_painting_tool_helper.cpp tool/KisAsyncronousStrokeUpdateHelper.cpp tool/kis_tool_paint.cc tool/kis_tool_shape.cc tool/kis_tool_ellipse_base.cpp tool/kis_tool_rectangle_base.cpp tool/kis_tool_polyline_base.cpp tool/kis_tool_utils.cpp tool/kis_resources_snapshot.cpp tool/kis_smoothing_options.cpp tool/KisStabilizerDelayedPaintHelper.cpp tool/KisStrokeSpeedMonitor.cpp tool/strokes/freehand_stroke.cpp tool/strokes/KisStrokeEfficiencyMeasurer.cpp tool/strokes/kis_painter_based_stroke_strategy.cpp tool/strokes/kis_filter_stroke_strategy.cpp tool/strokes/kis_color_picker_stroke_strategy.cpp tool/strokes/KisFreehandStrokeInfo.cpp tool/strokes/KisMaskedFreehandStrokePainter.cpp tool/strokes/KisMaskingBrushRenderer.cpp tool/strokes/KisMaskingBrushCompositeOpFactory.cpp tool/strokes/move_stroke_strategy.cpp tool/KisSelectionToolFactoryBase.cpp tool/KisToolPaintFactoryBase.cpp widgets/kis_cmb_composite.cc widgets/kis_cmb_contour.cpp widgets/kis_cmb_gradient.cpp widgets/kis_paintop_list_widget.cpp widgets/kis_cmb_idlist.cc widgets/kis_color_space_selector.cc widgets/kis_advanced_color_space_selector.cc widgets/kis_cie_tongue_widget.cpp widgets/kis_tone_curve_widget.cpp widgets/kis_curve_widget.cpp widgets/kis_custom_image_widget.cc widgets/kis_image_from_clipboard_widget.cpp widgets/kis_double_widget.cc widgets/kis_filter_selector_widget.cc widgets/kis_gradient_chooser.cc widgets/kis_iconwidget.cc widgets/kis_mask_widgets.cpp widgets/kis_meta_data_merge_strategy_chooser_widget.cc widgets/kis_multi_bool_filter_widget.cc widgets/kis_multi_double_filter_widget.cc widgets/kis_multi_integer_filter_widget.cc widgets/kis_multipliers_double_slider_spinbox.cpp widgets/kis_paintop_presets_popup.cpp widgets/kis_tool_options_popup.cpp widgets/kis_paintop_presets_chooser_popup.cpp widgets/kis_paintop_presets_save.cpp widgets/kis_paintop_preset_icon_library.cpp widgets/kis_pattern_chooser.cc widgets/kis_preset_chooser.cpp widgets/kis_progress_widget.cpp widgets/kis_selection_options.cc widgets/kis_scratch_pad.cpp widgets/kis_scratch_pad_event_filter.cpp widgets/kis_preset_selector_strip.cpp widgets/kis_slider_spin_box.cpp widgets/KisSelectionPropertySlider.cpp widgets/kis_size_group.cpp widgets/kis_size_group_p.cpp widgets/kis_wdg_generator.cpp widgets/kis_workspace_chooser.cpp widgets/kis_categorized_list_view.cpp widgets/kis_widget_chooser.cpp widgets/kis_tool_button.cpp widgets/kis_floating_message.cpp widgets/kis_lod_availability_widget.cpp widgets/kis_color_label_selector_widget.cpp widgets/kis_color_filter_combo.cpp widgets/kis_elided_label.cpp widgets/kis_stopgradient_slider_widget.cpp widgets/kis_preset_live_preview_view.cpp widgets/KisScreenColorPicker.cpp widgets/KoDualColorButton.cpp widgets/KoStrokeConfigWidget.cpp widgets/KoFillConfigWidget.cpp widgets/KisLayerStyleAngleSelector.cpp widgets/KisMemoryReportButton.cpp widgets/KisDitherWidget.cpp KisPaletteEditor.cpp dialogs/KisDlgPaletteEditor.cpp widgets/KisNewsWidget.cpp widgets/KisGamutMaskToolbar.cpp utils/kis_document_aware_spin_box_unit_manager.cpp utils/KisSpinBoxSplineUnitConverter.cpp utils/KisClipboardUtil.cpp utils/KisDitherUtil.cpp + utils/KisUpdaterBase.cpp + utils/KisAppimageUpdater.cpp + utils/KisManualUpdater.cpp input/kis_input_manager.cpp input/kis_input_manager_p.cpp input/kis_extended_modifiers_mapper.cpp input/kis_abstract_input_action.cpp input/kis_tool_invocation_action.cpp input/kis_pan_action.cpp input/kis_alternate_invocation_action.cpp input/kis_rotate_canvas_action.cpp input/kis_zoom_action.cpp input/kis_change_frame_action.cpp input/kis_gamma_exposure_action.cpp input/kis_show_palette_action.cpp input/kis_change_primary_setting_action.cpp input/kis_abstract_shortcut.cpp input/kis_native_gesture_shortcut.cpp input/kis_single_action_shortcut.cpp input/kis_stroke_shortcut.cpp input/kis_shortcut_matcher.cpp input/kis_select_layer_action.cpp input/KisQtWidgetsTweaker.cpp input/KisInputActionGroup.cpp input/kis_zoom_and_rotate_action.cpp operations/kis_operation.cpp operations/kis_operation_configuration.cpp operations/kis_operation_registry.cpp operations/kis_operation_ui_factory.cpp operations/kis_operation_ui_widget.cpp operations/kis_filter_selection_operation.cpp actions/kis_selection_action_factories.cpp actions/KisPasteActionFactories.cpp actions/KisTransformToolActivationCommand.cpp input/kis_touch_shortcut.cpp kis_document_undo_store.cpp kis_gui_context_command.cpp kis_gui_context_command_p.cpp input/kis_tablet_debugger.cpp input/kis_input_profile_manager.cpp input/kis_input_profile.cpp input/kis_shortcut_configuration.cpp input/config/kis_input_configuration_page.cpp input/config/kis_edit_profiles_dialog.cpp input/config/kis_input_profile_model.cpp input/config/kis_input_configuration_page_item.cpp input/config/kis_action_shortcuts_model.cpp input/config/kis_input_type_delegate.cpp input/config/kis_input_mode_delegate.cpp input/config/kis_input_button.cpp input/config/kis_input_editor_delegate.cpp input/config/kis_mouse_input_editor.cpp input/config/kis_wheel_input_editor.cpp input/config/kis_key_input_editor.cpp processing/fill_processing_visitor.cpp kis_asl_layer_style_serializer.cpp kis_psd_layer_style_resource.cpp canvas/kis_mirror_axis.cpp kis_abstract_perspective_grid.cpp KisApplication.cpp KisAutoSaveRecoveryDialog.cpp KisDetailsPane.cpp KisDocument.cpp KisCloneDocumentStroke.cpp kis_node_view_color_scheme.cpp KisImportExportFilter.cpp KisImportExportManager.cpp KisImportExportUtils.cpp kis_async_action_feedback.cpp KisMainWindow.cpp KisOpenPane.cpp KisPart.cpp KisPrintJob.cpp KisTemplate.cpp KisTemplateCreateDia.cpp KisTemplateGroup.cpp KisTemplates.cpp KisTemplatesPane.cpp KisTemplateTree.cpp KisUndoActionsUpdateManager.cpp KisView.cpp KisCanvasWindow.cpp KisImportExportErrorCode.cpp KisImportExportAdditionalChecks.cpp thememanager.cpp kis_mainwindow_observer.cpp KisViewManager.cpp kis_mirror_manager.cpp qtlockedfile/qtlockedfile.cpp qtsingleapplication/qtlocalpeer.cpp qtsingleapplication/qtsingleapplication.cpp KisResourceBundle.cpp KisResourceBundleManifest.cpp kis_md5_generator.cpp KisApplicationArguments.cpp KisNetworkAccessManager.cpp KisMultiFeedRSSModel.cpp KisRemoteFileFetcher.cpp KisSaveGroupVisitor.cpp KisWindowLayoutResource.cpp KisWindowLayoutManager.cpp KisSessionResource.cpp KisReferenceImagesDecoration.cpp KisReferenceImage.cpp flake/KisReferenceImagesLayer.cpp flake/KisReferenceImagesLayer.h KisMouseClickEater.cpp KisDecorationsWrapperLayer.cpp ) if(WIN32) # Private headers are needed for: # * KisDlgCustomTabletResolution # * KisScreenInformationAdapter include_directories(SYSTEM ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} qtlockedfile/qtlockedfile_win.cpp ) if (NOT USE_QT_TABLET_WINDOWS) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} input/wintab/kis_tablet_support_win.cpp input/wintab/kis_screen_size_choice_dialog.cpp input/wintab/kis_tablet_support_win8.cpp ) else() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} dialogs/KisDlgCustomTabletResolution.cpp ) endif() endif() set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} kis_animation_frame_cache.cpp kis_animation_cache_populator.cpp KisAsyncAnimationRendererBase.cpp KisAsyncAnimationCacheRenderer.cpp KisAsyncAnimationFramesSavingRenderer.cpp dialogs/KisAsyncAnimationRenderDialogBase.cpp dialogs/KisAsyncAnimationCacheRenderDialog.cpp dialogs/KisAsyncAnimationFramesSaveDialog.cpp canvas/kis_animation_player.cpp kis_animation_importer.cpp KisSyncedAudioPlayback.cpp KisFrameDataSerializer.cpp KisFrameCacheStore.cpp KisFrameCacheSwapper.cpp KisAbstractFrameCacheSwapper.cpp KisInMemoryFrameCacheSwapper.cpp input/wintab/drawpile_tablettester/tablettester.cpp input/wintab/drawpile_tablettester/tablettest.cpp ) if (UNIX) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} qtlockedfile/qtlockedfile_unix.cpp ) endif() if(APPLE) set(kritaui_LIB_SRCS ${kritaui_LIB_SRCS} osx.mm ) endif() ki18n_wrap_ui(kritaui_LIB_SRCS widgets/KoFillConfigWidget.ui widgets/KoStrokeConfigWidget.ui widgets/KisDitherWidget.ui forms/wdgdlgpngimport.ui forms/wdgfullscreensettings.ui forms/wdgautogradient.ui forms/wdggeneralsettings.ui forms/wdgperformancesettings.ui forms/wdggenerators.ui forms/wdgbookmarkedconfigurationseditor.ui forms/wdgapplyprofile.ui forms/wdgcustompattern.ui forms/wdglayerproperties.ui forms/wdgcolorsettings.ui forms/wdgtabletsettings.ui forms/wdgcolorspaceselector.ui forms/wdgcolorspaceselectoradvanced.ui forms/wdgdisplaysettings.ui forms/kis_previewwidgetbase.ui forms/kis_matrix_widget.ui forms/wdgselectionoptions.ui forms/wdggeometryoptions.ui forms/wdgnewimage.ui forms/wdgimageproperties.ui forms/wdgmaskfromselection.ui forms/wdgmasksource.ui forms/wdgfilterdialog.ui forms/wdgmetadatamergestrategychooser.ui forms/wdgpaintoppresets.ui forms/wdgpaintopsettings.ui forms/wdgdlggeneratorlayer.ui forms/wdgdlgfilelayer.ui forms/wdgfilterselector.ui forms/wdgfilternodecreation.ui forms/wdgmultipliersdoublesliderspinbox.ui forms/wdgnodequerypatheditor.ui forms/wdgpresetselectorstrip.ui forms/wdgsavebrushpreset.ui forms/wdgpreseticonlibrary.ui forms/wdgdlgblacklistcleanup.ui forms/wdgrectangleconstraints.ui forms/wdgimportimagesequence.ui forms/wdgstrokeselectionproperties.ui forms/KisDetailsPaneBase.ui forms/KisOpenPaneBase.ui forms/wdgstopgradienteditor.ui forms/wdgsessionmanager.ui forms/wdgnewwindowlayout.ui forms/KisWelcomePage.ui forms/WdgDlgPaletteEditor.ui forms/KisNewsPage.ui forms/wdgGamutMaskToolbar.ui forms/wdgchangeclonesource.ui brushhud/kis_dlg_brush_hud_config.ui dialogs/kis_delayed_save_dialog.ui input/config/kis_input_configuration_page.ui input/config/kis_edit_profiles_dialog.ui input/config/kis_input_configuration_page_item.ui input/config/kis_mouse_input_editor.ui input/config/kis_wheel_input_editor.ui input/config/kis_key_input_editor.ui layerstyles/wdgBevelAndEmboss.ui layerstyles/wdgblendingoptions.ui layerstyles/WdgColorOverlay.ui layerstyles/wdgContour.ui layerstyles/wdgdropshadow.ui layerstyles/WdgGradientOverlay.ui layerstyles/wdgInnerGlow.ui layerstyles/wdglayerstyles.ui layerstyles/WdgPatternOverlay.ui layerstyles/WdgSatin.ui layerstyles/WdgStroke.ui layerstyles/wdgstylesselector.ui layerstyles/wdgTexture.ui layerstyles/wdgKisLayerStyleAngleSelector.ui wdgsplash.ui input/wintab/kis_screen_size_choice_dialog.ui input/wintab/drawpile_tablettester/tablettest.ui ) if(WIN32) if(USE_QT_TABLET_WINDOWS) ki18n_wrap_ui(kritaui_LIB_SRCS dialogs/KisDlgCustomTabletResolution.ui ) else() ki18n_wrap_ui(kritaui_LIB_SRCS input/wintab/kis_screen_size_choice_dialog.ui ) endif() endif() add_library(kritaui SHARED ${kritaui_HEADERS_MOC} ${kritaui_LIB_SRCS} ) generate_export_header(kritaui BASE_NAME kritaui) target_link_libraries(kritaui KF5::CoreAddons KF5::Completion KF5::I18n KF5::ItemViews Qt5::Network kritaimpex kritacolor kritaimage kritalibbrush kritawidgets kritawidgetutils ${PNG_LIBRARIES} LibExiv2::LibExiv2 ) if (HAVE_QT_MULTIMEDIA) target_link_libraries(kritaui Qt5::Multimedia) endif() if (NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${X11_X11_LIB} ${X11_Xinput_LIB} ${XCB_LIBRARIES}) endif() if(APPLE) target_link_libraries(kritaui ${FOUNDATION_LIBRARY}) target_link_libraries(kritaui ${APPKIT_LIBRARY}) endif () target_link_libraries(kritaui ${OPENEXR_LIBRARIES}) # Add VSync disable workaround if(NOT WIN32 AND NOT APPLE) target_link_libraries(kritaui ${CMAKE_DL_LIBS} Qt5::X11Extras) endif() if(X11_FOUND) target_link_libraries(kritaui Qt5::X11Extras ${X11_LIBRARIES}) endif() target_include_directories(kritaui PUBLIC $ $ $ $ $ $ $ ) set_target_properties(kritaui PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaui ${INSTALL_TARGETS_DEFAULT_ARGS}) if (APPLE) install(FILES osx.stylesheet DESTINATION ${DATA_INSTALL_DIR}/krita) endif () diff --git a/libs/ui/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidget.cpp index cde6a7da0c..86188813bb 100644 --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -1,458 +1,505 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisWelcomePageWidget.h" #include #include #include #include #include #include #include "kis_action_manager.h" #include "kactioncollection.h" #include "kis_action.h" #include "KConfigGroup" #include "KSharedConfig" #include #include #include "kis_icon_utils.h" #include "krita_utils.h" #include "KoStore.h" #include "kis_config.h" #include "KisDocument.h" #include #include #include +#include +#include +#include + KisWelcomePageWidget::KisWelcomePageWidget(QWidget *parent) : QWidget(parent) { setupUi(this); recentDocumentsListView->setDragEnabled(false); recentDocumentsListView->viewport()->setAutoFillBackground(false); recentDocumentsListView->setSpacing(2); // set up URLs that go to web browser manualLink->setTextFormat(Qt::RichText); manualLink->setTextInteractionFlags(Qt::TextBrowserInteraction); manualLink->setOpenExternalLinks(true); gettingStartedLink->setTextFormat(Qt::RichText); gettingStartedLink->setTextInteractionFlags(Qt::TextBrowserInteraction); gettingStartedLink->setOpenExternalLinks(true); supportKritaLink->setTextFormat(Qt::RichText); supportKritaLink->setTextInteractionFlags(Qt::TextBrowserInteraction); supportKritaLink->setOpenExternalLinks(true); userCommunityLink->setTextFormat(Qt::RichText); userCommunityLink->setTextInteractionFlags(Qt::TextBrowserInteraction); userCommunityLink->setOpenExternalLinks(true); kritaWebsiteLink->setTextFormat(Qt::RichText); kritaWebsiteLink->setTextInteractionFlags(Qt::TextBrowserInteraction); kritaWebsiteLink->setOpenExternalLinks(true); sourceCodeLink->setTextFormat(Qt::RichText); sourceCodeLink->setTextInteractionFlags(Qt::TextBrowserInteraction); sourceCodeLink->setOpenExternalLinks(true); poweredByKDELink->setTextFormat(Qt::RichText); poweredByKDELink->setTextInteractionFlags(Qt::TextBrowserInteraction); poweredByKDELink->setOpenExternalLinks(true); kdeIcon->setIconSize(QSize(20, 20)); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); versionNotificationLabel->setTextFormat(Qt::RichText); versionNotificationLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); versionNotificationLabel->setOpenExternalLinks(true); +// bnVersionUpdate->setVisible(false); + connect(chkShowNews, SIGNAL(toggled(bool)), newsWidget, SLOT(toggleNews(bool))); connect(newsWidget, SIGNAL(newsDataChanged()), this, SLOT(slotUpdateVersionMessage())); // configure the News area KisConfig cfg(true); bool m_getNews = cfg.readEntry("FetchNews", false); chkShowNews->setChecked(m_getNews); setAcceptDrops(true); + // version updates +//#ifdef Q_OS_LINUX + // ADD APPIMAGE CHECKS HERE + if (!qEnvironmentVariable("APPIMAGE").isEmpty()) { + qDebug() << "$APPIMAGE:" << qgetenv("APPIMAGE"); + m_versionUpdater = new KisAppimageUpdater(); + } else { + m_versionUpdater = new KisManualUpdater(); + } + + + connect(bnVersionUpdate, SIGNAL(clicked()), this, SLOT(slotRunVersionUpdate())); } KisWelcomePageWidget::~KisWelcomePageWidget() { } void KisWelcomePageWidget::setMainWindow(KisMainWindow* mainWin) { if (mainWin) { m_mainWindow = mainWin; // set the shortcut links from actions (only if a shortcut exists) if ( mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() != "") { newFileLinkShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() + QString(")")); } if (mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() != "") { openFileShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() + QString(")")); } connect(recentDocumentsListView, SIGNAL(clicked(QModelIndex)), this, SLOT(recentDocumentClicked(QModelIndex))); // we need the view manager to actually call actions, so don't create the connections // until after the view manager is set connect(newFileLink, SIGNAL(clicked(bool)), this, SLOT(slotNewFileClicked())); connect(openFileLink, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileClicked())); connect(clearRecentFilesLink, SIGNAL(clicked(bool)), this, SLOT(slotClearRecentFiles())); slotUpdateThemeColors(); // allows RSS news items to apply analytics tracking. newsWidget->setAnalyticsTracking("?" + analyticsString); } } bool KisWelcomePageWidget::isDevelopmentBuild() { // dev builds contain GIT hash in it and the word git // stable versions do not contain this return qApp->applicationVersion().contains("git"); } void KisWelcomePageWidget::showDropAreaIndicator(bool show) { if (!show) { QString dropFrameStyle = "QFrame#dropAreaIndicator { border: 0px }"; dropFrameBorder->setStyleSheet(dropFrameStyle); } else { QColor textColor = qApp->palette().color(QPalette::Text); QColor backgroundColor = qApp->palette().color(QPalette::Background); QColor blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); // QColor.name() turns it into a hex/web format QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 2px dotted ").append(blendedColor.name()).append(" }") ; dropFrameBorder->setStyleSheet(dropFrameStyle); } } void KisWelcomePageWidget::slotUpdateThemeColors() { textColor = qApp->palette().color(QPalette::Text); backgroundColor = qApp->palette().color(QPalette::Background); // make the welcome screen labels a subtle color so it doesn't clash with the main UI elements blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); blendedStyle = QString("color: ").append(blendedColor.name()); // what labels to change the color... startTitleLabel->setStyleSheet(blendedStyle); recentDocumentsLabel->setStyleSheet(blendedStyle); helpTitleLabel->setStyleSheet(blendedStyle); newFileLinkShortcut->setStyleSheet(blendedStyle); openFileShortcut->setStyleSheet(blendedStyle); clearRecentFilesLink->setStyleSheet(blendedStyle); recentDocumentsListView->setStyleSheet(blendedStyle); newFileLink->setStyleSheet(blendedStyle); openFileLink->setStyleSheet(blendedStyle); // giving the drag area messaging a dotted border QString dottedBorderStyle = QString("border: 2px dotted ").append(blendedColor.name()).append("; color:").append(blendedColor.name()).append( ";"); dragImageHereLabel->setStyleSheet(dottedBorderStyle); // make drop area QFrame have a dotted line dropFrameBorder->setObjectName("dropAreaIndicator"); QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 4px dotted ").append(blendedColor.name()).append("}"); dropFrameBorder->setStyleSheet(dropFrameStyle); // only show drop area when we have a document over the empty area showDropAreaIndicator(false); // add icons for new and open settings to make them stand out a bit more openFileLink->setIconSize(QSize(30, 30)); newFileLink->setIconSize(QSize(30, 30)); openFileLink->setIcon(KisIconUtils::loadIcon("document-open")); newFileLink->setIcon(KisIconUtils::loadIcon("document-new")); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); // HTML links seem to be a bit more stubborn with theme changes... setting inline styles to help with color change userCommunityLink->setText(QString("") .append(i18n("User Community")).append("")); gettingStartedLink->setText(QString("") .append(i18n("Getting Started")).append("")); manualLink->setText(QString("") .append(i18n("User Manual")).append("")); supportKritaLink->setText(QString("") .append(i18n("Support Krita")).append("")); kritaWebsiteLink->setText(QString("") .append(i18n("Krita Website")).append("")); sourceCodeLink->setText(QString("") .append(i18n("Source Code")).append("")); poweredByKDELink->setText(QString("") .append(i18n("Powered by KDE")).append("")); slotUpdateVersionMessage(); // text set from RSS feed // re-populate recent files since they might have themed icons populateRecentDocuments(); } void KisWelcomePageWidget::populateRecentDocuments() { m_recentFilesModel.clear(); // clear existing data before it gets re-populated // grab recent files data int numRecentFiles = m_mainWindow->recentFilesUrls().length() > 5 ? 5 : m_mainWindow->recentFilesUrls().length(); // grab at most 5 for (int i = 0; i < numRecentFiles; i++ ) { QStandardItem *recentItem = new QStandardItem(1,2); // 1 row, 1 column recentItem->setIcon(KisIconUtils::loadIcon("document-export")); QString recentFileUrlPath = m_mainWindow->recentFilesUrls().at(i).toLocalFile(); QString fileName = recentFileUrlPath.split("/").last(); QList brokenUrls; if (m_thumbnailMap.contains(recentFileUrlPath)) { recentItem->setIcon(m_thumbnailMap[recentFileUrlPath]); } else { QFileInfo fi(recentFileUrlPath); if (fi.exists()) { if (fi.suffix() == "ora" || fi.suffix() == "kra") { QScopedPointer store(KoStore::createStore(recentFileUrlPath, KoStore::Read)); if (store) { QString thumbnailpath; if (store->hasFile(QString("Thumbnails/thumbnail.png"))){ thumbnailpath = QString("Thumbnails/thumbnail.png"); } else if (store->hasFile(QString("preview.png"))) { thumbnailpath = QString("preview.png"); } if (!thumbnailpath.isEmpty()) { if (store->open(thumbnailpath)) { QByteArray bytes = store->read(store->size()); store->close(); QImage img; img.loadFromData(bytes); img.setDevicePixelRatio(devicePixelRatioF()); recentItem->setIcon(QIcon(QPixmap::fromImage(img))); } } } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else if (fi.suffix() == "tiff" || fi.suffix() == "tif") { // Workaround for a bug in Qt tiff QImageIO plugin QScopedPointer doc; doc.reset(KisPart::instance()->createDocument()); doc->setFileBatchMode(true); bool r = doc->openUrl(QUrl::fromLocalFile(recentFileUrlPath), KisDocument::DontAddToRecent); if (r) { KisPaintDeviceSP projection = doc->image()->projection(); recentItem->setIcon(QIcon(QPixmap::fromImage(projection->createThumbnail(48, 48, projection->exactBounds())))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } else { QImage img; img.setDevicePixelRatio(devicePixelRatioF()); img.load(recentFileUrlPath); if (!img.isNull()) { recentItem->setIcon(QIcon(QPixmap::fromImage(img.scaledToWidth(48)))); } else { brokenUrls << m_mainWindow->recentFilesUrls().at(i); } } if (brokenUrls.size() > 0 && brokenUrls.last().toLocalFile() != recentFileUrlPath) { m_thumbnailMap[recentFileUrlPath] = recentItem->icon(); } } } Q_FOREACH(const QUrl &url, brokenUrls) { m_mainWindow->removeRecentUrl(url); } // set the recent object with the data if (brokenUrls.isEmpty() || brokenUrls.last().toLocalFile() != recentFileUrlPath) { recentItem->setText(fileName); // what to display for the item recentItem->setToolTip(recentFileUrlPath); m_recentFilesModel.appendRow(recentItem); } } // hide clear and Recent files title if there are none bool hasRecentFiles = m_mainWindow->recentFilesUrls().length() > 0; recentDocumentsLabel->setVisible(hasRecentFiles); clearRecentFilesLink->setVisible(hasRecentFiles); recentDocumentsListView->setIconSize(QSize(48, 48)); recentDocumentsListView->setModel(&m_recentFilesModel); } void KisWelcomePageWidget::slotUpdateVersionMessage() { alertIcon->setIcon(KisIconUtils::loadIcon("warning")); alertIcon->setVisible(false); + KisUpdaterBase::UpdateStatus updateStatus = m_versionUpdater->checkForUpdates(); + // find out if we need an update...or if this is a development version if (isDevelopmentBuild()) { // Development build QString versionLabelText = QString("") .append(i18n("DEV BUILD")).append(""); versionNotificationLabel->setText(versionLabelText); alertIcon->setVisible(true); versionNotificationLabel->setVisible(true); - } else if (newsWidget->hasUpdateAvailable()) { + if (m_versionUpdater->hasUpdateCapability() && updateStatus == KisUpdaterBase::UpdateStatus::UPDATES_AVAILABLE) { + bnVersionUpdate->setVisible(true); + } else { + bnVersionUpdate->setVisible(false); + } - // build URL for label - QString versionLabelText = QString("versionLink() + "?" + - analyticsString + "version-update" + "\">") - .append(i18n("New Version Available!")).append(""); + } else if (updateStatus == KisUpdaterBase::UpdateStatus::UPDATES_AVAILABLE) { + if (m_versionUpdater->hasUpdateCapability()) { + bnVersionUpdate->setVisible(true); + } else { + bnVersionUpdate->setVisible(false); + + // build URL for label + QString versionLabelText = QString("versionLink() + "?" + + analyticsString + "version-update" + "\">") + .append(i18n("New Version Available!")).append(""); + + versionNotificationLabel->setVisible(true); + versionNotificationLabel->setText(versionLabelText); + } - versionNotificationLabel->setVisible(true); - versionNotificationLabel->setText(versionLabelText); alertIcon->setVisible(true); - } else { + } else if (updateStatus == KisUpdaterBase::UpdateStatus::UPTODATE) { // no message needed... exit - versionNotificationLabel->setVisible(false); + QString versionLabelText = QString("Krita is up-to-date."); + versionNotificationLabel->setText(versionLabelText); + versionNotificationLabel->setVisible(true); + bnVersionUpdate->setVisible(false); + return; + } else { + // error + QString versionLabelText = QString("Error during update check!"); + versionNotificationLabel->setText(versionLabelText); + versionNotificationLabel->setVisible(true); + bnVersionUpdate->setVisible(false); return; } if (!blendedStyle.isNull()) { versionNotificationLabel->setStyleSheet(blendedStyle); } } void KisWelcomePageWidget::dragEnterEvent(QDragEnterEvent *event) { //qDebug() << "dragEnterEvent formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dropEvent(QDropEvent *event) { //qDebug() << "KisWelcomePageWidget::dropEvent() formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(false); if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { if (url.toLocalFile().endsWith(".bundle")) { bool r = m_mainWindow->installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { m_mainWindow->openDocument(url, KisMainWindow::None); } } } } void KisWelcomePageWidget::dragMoveEvent(QDragMoveEvent *event) { //qDebug() << "dragMoveEvent"; m_mainWindow->dragMoveEvent(event); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dragLeaveEvent(QDragLeaveEvent */*event*/) { //qDebug() << "dragLeaveEvent"; showDropAreaIndicator(false); m_mainWindow->dragLeave(); } void KisWelcomePageWidget::recentDocumentClicked(QModelIndex index) { QString fileUrl = index.data(Qt::ToolTipRole).toString(); m_mainWindow->openDocument(QUrl::fromLocalFile(fileUrl), KisMainWindow::None ); } +void KisWelcomePageWidget::slotRunVersionUpdate() +{ + m_versionUpdater->doUpdate(); +} + void KisWelcomePageWidget::slotNewFileClicked() { m_mainWindow->slotFileNew(); } void KisWelcomePageWidget::slotOpenFileClicked() { m_mainWindow->slotFileOpen(); } void KisWelcomePageWidget::slotClearRecentFiles() { m_mainWindow->clearRecentFiles(); populateRecentDocuments(); } diff --git a/libs/ui/KisWelcomePageWidget.h b/libs/ui/KisWelcomePageWidget.h index 0d0f3b08ac..bd881a80bf 100644 --- a/libs/ui/KisWelcomePageWidget.h +++ b/libs/ui/KisWelcomePageWidget.h @@ -1,97 +1,99 @@ /* This file is part of the KDE project * Copyright (C) 2018 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISWELCOMEPAGEWIDGET_H #define KISWELCOMEPAGEWIDGET_H #include "kritaui_export.h" #include "KisViewManager.h" #include "KisMainWindow.h" +#include #include #include "ui_KisWelcomePage.h" #include /// A widget for displaying if no documents are open. This will display in the MDI area class KRITAUI_EXPORT KisWelcomePageWidget : public QWidget, public Ui::KisWelcomePage { Q_OBJECT public: explicit KisWelcomePageWidget(QWidget *parent); ~KisWelcomePageWidget() override; void setMainWindow(KisMainWindow* m_mainWindow); bool isDevelopmentBuild(); public Q_SLOTS: /// if a document is placed over this area, a dotted line will appear as an indicator /// that it is a droppable area. KisMainwindow is what triggers this void showDropAreaIndicator(bool show); void slotUpdateThemeColors(); /// this could be called multiple times. If a recent document doesn't /// have a preview, an icon is used that needs to be updated void populateRecentDocuments(); void slotUpdateVersionMessage(); void slotClearRecentFiles(); protected: // QWidget overrides void dragEnterEvent(QDragEnterEvent * event) override; void dropEvent(QDropEvent * event) override; void dragMoveEvent(QDragMoveEvent * event) override; void dragLeaveEvent(QDragLeaveEvent * event) override; private: KisMainWindow *m_mainWindow; QStandardItemModel m_recentFilesModel; QMap m_thumbnailMap; /// help us see how many people are clicking startup screen links /// you can see the results in Matomo (stats.kde.org) /// this will be listed in the "Acquisition" section of Matomo /// just append some text to this to associate it with an event/page const QString analyticsString = "pk_campaign=startup-sceen&pk_kwd="; // keeping track of link colors with theme change QColor textColor; QColor backgroundColor; QColor blendedColor; QString blendedStyle; - + KisUpdaterBase* m_versionUpdater; private Q_SLOTS: void slotNewFileClicked(); void slotOpenFileClicked(); void recentDocumentClicked(QModelIndex index); + void slotRunVersionUpdate(); }; #endif // KISWELCOMEPAGEWIDGET_H diff --git a/libs/ui/forms/KisWelcomePage.ui b/libs/ui/forms/KisWelcomePage.ui index 16ea785892..f8de60f4f8 100644 --- a/libs/ui/forms/KisWelcomePage.ui +++ b/libs/ui/forms/KisWelcomePage.ui @@ -1,851 +1,858 @@ KisWelcomePage 0 0 788 - 476 + 484 0 0 false QFrame::Box QFrame::Plain 4 0 5 0 0 30 0 18 Community 0 0 true User Manual Qt::Horizontal QSizePolicy::Expanding 40 5 0 true Getting Started Qt::Horizontal 40 5 true Support Krita Qt::Horizontal 40 20 true User Community Qt::Horizontal 40 20 true Krita Website Qt::Horizontal 40 20 0 0 true Source Code Qt::Horizontal 40 20 20 20 20 20 20 true true Powered by KDE Qt::Horizontal 40 20 0 0 QFrame::Box 2 Drag Image in window to open Qt::AlignCenter true 30 Qt::Horizontal 40 20 Qt::Vertical 20 20 Qt::Horizontal 5 5 Qt::Vertical 5 5 Qt::Vertical 5 5 Qt::Horizontal 5 5 5 0 20 0 0 70 0 18 Start 0 0 16 16 16 16 true 0 0 true Krita X.X.X Update Available 2 false + + + + Update now! + + + Qt::Horizontal 40 20 0 true Qt::NoFocus New File false true 20 0 false Qt::Horizontal 40 20 0 30 true Qt::NoFocus Open File false true 20 0 false Qt::Horizontal 40 20 18 Recent Documents 0 0 true Qt::NoFocus Clear false true Qt::Horizontal 5 20 0 0 300 250 true false Qt::NoFocus false QFrame::NoFrame QFrame::Plain 0 false false QAbstractItemView::SelectItems QListView::Snap QListView::Fixed 0 QListView::ListMode true false Qt::Vertical 5 5 0 0 18 News 0 true 0 0 Show news about Krita: this needs internet to retrieve information from the krita.org website Check for updates KisNewsWidget QWidget
widgets/KisNewsWidget.h
1
diff --git a/libs/ui/utils/KisAppimageUpdater.cpp b/libs/ui/utils/KisAppimageUpdater.cpp new file mode 100644 index 0000000000..e3e91e72a4 --- /dev/null +++ b/libs/ui/utils/KisAppimageUpdater.cpp @@ -0,0 +1,85 @@ +#include "KisAppimageUpdater.h" + +#include +#include +#include +#include +#include + +#include + +KisAppimageUpdater::KisAppimageUpdater() +{ + ENTER_FUNCTION(); + m_updaterBinary = QString("%1%2AppImageUpdate") + .arg(QCoreApplication::applicationDirPath()) + .arg(QDir::separator()); + + m_updateCapability = findUpdaterBinary(); +} + +KisUpdaterBase::UpdateStatus KisAppimageUpdater::checkForUpdates() +{ + ENTER_FUNCTION(); + if (!hasUpdateCapability()) { + return KisUpdaterBase::UpdateStatus::ERROR; + } + + QProcess process; + int result = process.execute( + QString("%1 --check-for-update %2") + .arg(m_updaterBinary) + .arg(qEnvironmentVariable("APPIMAGE")) + ); + + qDebug() << "KisAppimageUpdater::checkForUpdates()" << result; + + KisUpdaterBase::UpdateStatus updateStatus; + switch (result) { + case 0: + updateStatus = KisUpdaterBase::UpdateStatus::UPTODATE; + break; + case 1: + updateStatus = KisUpdaterBase::UpdateStatus::UPDATES_AVAILABLE; + break; + case 2: + updateStatus = KisUpdaterBase::UpdateStatus::ERROR; + break; + default: + updateStatus = KisUpdaterBase::UpdateStatus::ERROR; + break; + } + + return updateStatus; +} + +bool KisAppimageUpdater::hasUpdateCapability() +{ + ENTER_FUNCTION(); + return m_updateCapability; +} + +void KisAppimageUpdater::doUpdate() +{ + ENTER_FUNCTION(); + + QProcess process; + process.start(QString("%1 %2") + .arg(m_updaterBinary) + .arg(qEnvironmentVariable("APPIMAGE")) + ); + process.waitForFinished(-1); +} + +bool KisAppimageUpdater::findUpdaterBinary() +{ + ENTER_FUNCTION(); + QFileInfo finfo = QFileInfo(m_updaterBinary); + if (finfo.isExecutable()) { + qDebug() << "KisAppimageUpdater::findUpdaterBinary() found and executable"; + return true; + } else { + qDebug() << "KisAppimageUpdater::findUpdaterBinary() not found"; + return false; + } +} diff --git a/libs/ui/utils/KisAppimageUpdater.h b/libs/ui/utils/KisAppimageUpdater.h new file mode 100644 index 0000000000..637d7f6310 --- /dev/null +++ b/libs/ui/utils/KisAppimageUpdater.h @@ -0,0 +1,25 @@ +#ifndef KISAPPIMAGEUPDATER_H +#define KISAPPIMAGEUPDATER_H + +#include + +class QString; + +class KisAppimageUpdater : public KisUpdaterBase +{ + Q_OBJECT + +public: + KisAppimageUpdater(); + + KisUpdaterBase::UpdateStatus checkForUpdates() override; + bool hasUpdateCapability() override; + void doUpdate() override; + +private: + bool findUpdaterBinary(); + QString m_updaterBinary; + bool m_updateCapability; +}; + +#endif // KISAPPIMAGEUPDATER_H diff --git a/libs/ui/utils/KisManualUpdater.cpp b/libs/ui/utils/KisManualUpdater.cpp new file mode 100644 index 0000000000..7db017ea5d --- /dev/null +++ b/libs/ui/utils/KisManualUpdater.cpp @@ -0,0 +1,99 @@ +#include "KisManualUpdater.h" +#include +#include + +#include +#include +#include + + +KisManualUpdater::KisManualUpdater() + : m_rssModel(new MultiFeedRssModel(this)) +{ + m_rssModel->addFeed(QLatin1String("https://krita.org/en/feed/")); + connect(m_rssModel, SIGNAL(feedDataChanged()), this, SLOT(rssDataChanged())); +} + +KisUpdaterBase::UpdateStatus KisManualUpdater::checkForUpdates() +{ + if (m_updateAvailable) { + return KisUpdaterBase::UpdateStatus::UPDATES_AVAILABLE; + } else { + return KisUpdaterBase::UpdateStatus::UPTODATE; + } +} + +void KisManualUpdater::rssDataChanged() +{ + // grab the latest release post and URL for reference later + // if we need to update + QString newVersionNumber; + QString newVersionLink; + + for (int i = 0; i < m_rssModel->rowCount(); i++) + { + const QModelIndex &idx = m_rssModel->index(i); + + if (idx.isValid()) { + + // only use official release announcements to get version number + if ( idx.data(RssRoles::CategoryRole).toString() != "Official Release") { + continue; + } + + QString linkTitle = idx.data(RssRoles::TitleRole).toString(); + + // regex to capture version number + QRegularExpression versionRegex("\\d\\.\\d\\.?\\d?\\.?\\d"); + QRegularExpressionMatch matched = versionRegex.match(linkTitle); + + // only take the top match for release version since that is the newest + if (matched.hasMatch()) { + newVersionNumber = matched.captured(0); + newVersionLink = idx.data(RssRoles::LinkRole).toString(); + break; + } + + } + } + + // see if we need to update our version, or we are on a dev version + calculateVersionUpdateStatus(newVersionNumber); +} + +void KisManualUpdater::calculateVersionUpdateStatus(QString newVersionNumber) +{ + // do version compare to see if there is a new version available + // also check to see if we are on a dev version (newer than newest release) +// QStringList currentVersionParts = qApp->applicationVersion().split("."); + QStringList currentVersionParts = KritaVersionWrapper::versionString().split("."); + QStringList onlineReleaseAnnouncement = newVersionNumber.split("."); + + // is the major version different? + if (onlineReleaseAnnouncement[0] > currentVersionParts[0] ) { + m_updateAvailable = true; // we are a major version behind + return; + } + + // major versions are the same, so check minor versions + if (onlineReleaseAnnouncement[1] > currentVersionParts[1] ) { + m_updateAvailable = true; // we are a minor version behind + return; + } + + // minor versions are the same, so maybe bugfix version is different + // sometimes we don't communicate this, implictly make 0 if it doesn't exist + if (onlineReleaseAnnouncement[2].isNull()) { + onlineReleaseAnnouncement[2] = "0"; + } + if (currentVersionParts[2].isNull()) { + currentVersionParts[2] = "0"; + } + + if (onlineReleaseAnnouncement[2] > currentVersionParts[2] ) { + m_updateAvailable = true; // we are a bugfix version behind + return; + } + +} + diff --git a/libs/ui/utils/KisManualUpdater.h b/libs/ui/utils/KisManualUpdater.h new file mode 100644 index 0000000000..73394d412a --- /dev/null +++ b/libs/ui/utils/KisManualUpdater.h @@ -0,0 +1,29 @@ +#ifndef KISMANUALUPDATER_H +#define KISMANUALUPDATER_H + +#include +#include + +class KisManualUpdater : public KisUpdaterBase +{ + Q_OBJECT + +public: + KisManualUpdater(); + + KisUpdaterBase::UpdateStatus checkForUpdates() override; + + // this updater can only check for updates + inline bool hasUpdateCapability() override { return false; } + inline void doUpdate() override { return; } + +public Q_SLOTS: + void rssDataChanged(); + +private: + void calculateVersionUpdateStatus(QString newVersionNumber); + MultiFeedRssModel* m_rssModel {0}; + bool m_updateAvailable {false}; +}; + +#endif // KISMANUALUPDATER_H diff --git a/libs/ui/utils/KisUpdaterBase.cpp b/libs/ui/utils/KisUpdaterBase.cpp new file mode 100644 index 0000000000..cd4daf4e04 --- /dev/null +++ b/libs/ui/utils/KisUpdaterBase.cpp @@ -0,0 +1,6 @@ +#include "KisUpdaterBase.h" + +KisUpdaterBase::KisUpdaterBase() +{ + +} diff --git a/libs/ui/utils/KisUpdaterBase.h b/libs/ui/utils/KisUpdaterBase.h new file mode 100644 index 0000000000..6cd60731cd --- /dev/null +++ b/libs/ui/utils/KisUpdaterBase.h @@ -0,0 +1,35 @@ +#ifndef KISUPDATERBASE_H +#define KISUPDATERBASE_H + +#include + +class QString; + +class KisUpdaterBase : public QObject +{ + Q_OBJECT + +public: + KisUpdaterBase(); + + enum UpdateStatus { + UPTODATE, + UPDATES_AVAILABLE, + ERROR + }; + + virtual UpdateStatus checkForUpdates() = 0; + + /** + * @brief hasUpdateCapability - can this update, or is it check only? + * @return bool + */ + virtual bool hasUpdateCapability() = 0; + virtual void doUpdate() = 0; + +private: + QString m_newVersionString; +// QString m_newVersionLink; +}; + +#endif // KISUPDATERBASE_H diff --git a/libs/ui/widgets/KisNewsWidget.cpp b/libs/ui/widgets/KisNewsWidget.cpp index 273a05f973..73d136d289 100644 --- a/libs/ui/widgets/KisNewsWidget.cpp +++ b/libs/ui/widgets/KisNewsWidget.cpp @@ -1,223 +1,223 @@ /* * Copyright (c) 2018 boud * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisNewsWidget.h" #include #include #include #include #include #include #include #include "kis_config.h" #include "KisMultiFeedRSSModel.h" #include "QRegularExpression" KisNewsDelegate::KisNewsDelegate(QObject *parent) : QStyledItemDelegate(parent) { } void KisNewsDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { painter->save(); QStyleOptionViewItem optionCopy = option; initStyleOption(&optionCopy, index); QStyle *style = optionCopy.widget? optionCopy.widget->style() : QApplication::style(); QTextDocument doc; doc.setHtml(optionCopy.text); doc.setDocumentMargin(10); /// Painting item without text optionCopy.text = QString(); style->drawControl(QStyle::CE_ItemViewItem, &optionCopy, painter); QAbstractTextDocumentLayout::PaintContext ctx; // Highlighting text if item is selected if (optionCopy.state & QStyle::State_Selected) { ctx.palette.setColor(QPalette::Text, optionCopy.palette.color(QPalette::Active, QPalette::HighlightedText)); } painter->translate(optionCopy.rect.left(), optionCopy.rect.top()); QRect clip(0, 0, optionCopy.rect.width(), optionCopy.rect.height()); doc.setPageSize(clip.size()); doc.drawContents(painter, clip); painter->restore(); } QSize KisNewsDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem optionCopy = option; initStyleOption(&optionCopy, index); QTextDocument doc; doc.setHtml(optionCopy.text); doc.setTextWidth(optionCopy.rect.width()); return QSize(doc.idealWidth(), doc.size().height()); } KisNewsWidget::KisNewsWidget(QWidget *parent) : QWidget(parent) { setupUi(this); m_rssModel = new MultiFeedRssModel(this); connect(m_rssModel, SIGNAL(feedDataChanged()), this, SLOT(rssDataChanged())); setCursor(Qt::PointingHandCursor); listNews->setModel(m_rssModel); listNews->setItemDelegate(new KisNewsDelegate(listNews)); connect(listNews, SIGNAL(clicked(QModelIndex)), this, SLOT(itemSelected(QModelIndex))); } void KisNewsWidget::setAnalyticsTracking(QString text) { analyticsTrackingParameters = text; } bool KisNewsWidget::hasUpdateAvailable() { return needsVersionUpdate; } QString KisNewsWidget::versionNumber() { return newVersionNumber; } QString KisNewsWidget::versionLink() { return newVersionLink; } void KisNewsWidget::toggleNews(bool toggle) { KisConfig cfg(false); cfg.writeEntry("FetchNews", toggle); if (toggle) { m_rssModel->addFeed(QLatin1String("https://krita.org/en/feed/")); } else { m_rssModel->removeFeed(QLatin1String("https://krita.org/en/feed/")); } } void KisNewsWidget::itemSelected(const QModelIndex &idx) { if (idx.isValid()) { QString link = idx.data(RssRoles::LinkRole).toString(); // append query string for analytics tracking if we set it if (analyticsTrackingParameters != "") { // use title in analytics query string QString linkTitle = idx.data(RssRoles::TitleRole).toString(); linkTitle = linkTitle.simplified(); // trims and makes 1 white space linkTitle = linkTitle.replace(" ", ""); analyticsTrackingParameters = analyticsTrackingParameters.append(linkTitle); QDesktopServices::openUrl(QUrl(link.append(analyticsTrackingParameters))); } else { QDesktopServices::openUrl(QUrl(link)); } } } void KisNewsWidget::rssDataChanged() { // grab the latest release post and URL for reference later // if we need to update - for (int i = 0; i < m_rssModel->rowCount(); i++) - { - const QModelIndex &idx = m_rssModel->index(i); +// for (int i = 0; i < m_rssModel->rowCount(); i++) +// { +// const QModelIndex &idx = m_rssModel->index(i); - if (idx.isValid()) { +// if (idx.isValid()) { - // only use official release announcements to get version number - if ( idx.data(RssRoles::CategoryRole).toString() != "Official Release") { - continue; - } +// // only use official release announcements to get version number +// if ( idx.data(RssRoles::CategoryRole).toString() != "Official Release") { +// continue; +// } - QString linkTitle = idx.data(RssRoles::TitleRole).toString(); +// QString linkTitle = idx.data(RssRoles::TitleRole).toString(); - // regex to capture version number - QRegularExpression versionRegex("\\d\\.\\d\\.?\\d?\\.?\\d"); - QRegularExpressionMatch matched = versionRegex.match(linkTitle); +// // regex to capture version number +// QRegularExpression versionRegex("\\d\\.\\d\\.?\\d?\\.?\\d"); +// QRegularExpressionMatch matched = versionRegex.match(linkTitle); - // only take the top match for release version since that is the newest - if (matched.hasMatch()) { - newVersionNumber = matched.captured(0); - newVersionLink = idx.data(RssRoles::LinkRole).toString(); - break; - } +// // only take the top match for release version since that is the newest +// if (matched.hasMatch()) { +// newVersionNumber = matched.captured(0); +// newVersionLink = idx.data(RssRoles::LinkRole).toString(); +// break; +// } - } - } +// } +// } - // see if we need to update our version, or we are on a dev version - calculateVersionUpdateStatus(); +// // see if we need to update our version, or we are on a dev version +// calculateVersionUpdateStatus(); emit newsDataChanged(); } void KisNewsWidget::calculateVersionUpdateStatus() { - // do version compare to see if there is a new version available - // also check to see if we are on a dev version (newer than newest release) - QStringList currentVersionParts = qApp->applicationVersion().split("."); - QStringList onlineReleaseAnnouncement = newVersionNumber.split("."); - - // is the major version different? - if (onlineReleaseAnnouncement[0] > currentVersionParts[0] ) { - needsVersionUpdate = true; // we are a major version behind - return; - } - - // major versions are the same, so check minor versions - if (onlineReleaseAnnouncement[1] > currentVersionParts[1] ) { - needsVersionUpdate = true; // we are a minor version behind - return; - } - - // minor versions are the same, so maybe bugfix version is different - // sometimes we don't communicate this, implictly make 0 if it doesn't exist - if (onlineReleaseAnnouncement[2].isNull()) { - onlineReleaseAnnouncement[2] = "0"; - } - if (currentVersionParts[2].isNull()) { - currentVersionParts[2] = "0"; - } - - if (onlineReleaseAnnouncement[2] > currentVersionParts[2] ) { - needsVersionUpdate = true; // we are a bugfix version behind - return; - } +// // do version compare to see if there is a new version available +// // also check to see if we are on a dev version (newer than newest release) +// QStringList currentVersionParts = qApp->applicationVersion().split("."); +// QStringList onlineReleaseAnnouncement = newVersionNumber.split("."); + +// // is the major version different? +// if (onlineReleaseAnnouncement[0] > currentVersionParts[0] ) { +// needsVersionUpdate = true; // we are a major version behind +// return; +// } + +// // major versions are the same, so check minor versions +// if (onlineReleaseAnnouncement[1] > currentVersionParts[1] ) { +// needsVersionUpdate = true; // we are a minor version behind +// return; +// } + +// // minor versions are the same, so maybe bugfix version is different +// // sometimes we don't communicate this, implictly make 0 if it doesn't exist +// if (onlineReleaseAnnouncement[2].isNull()) { +// onlineReleaseAnnouncement[2] = "0"; +// } +// if (currentVersionParts[2].isNull()) { +// currentVersionParts[2] = "0"; +// } + +// if (onlineReleaseAnnouncement[2] > currentVersionParts[2] ) { +// needsVersionUpdate = true; // we are a bugfix version behind +// return; +// } } diff --git a/packaging/linux/appimage/build-image.sh b/packaging/linux/appimage/build-image.sh index 9c2f943981..37fc9ebb4c 100755 --- a/packaging/linux/appimage/build-image.sh +++ b/packaging/linux/appimage/build-image.sh @@ -1,110 +1,156 @@ #!/bin/bash # Halt on errors and be verbose about what we are doing -set -e +#set -e set -x # Read in our parameters export BUILD_PREFIX=$1 export KRITA_SOURCES=$2 # Save some frequently referenced locations in variables for ease of use / updating export APPDIR=$BUILD_PREFIX/krita.appdir export PLUGINS=$APPDIR/usr/lib/kritaplugins/ -# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. +# qjsonparser, used to add metadata to the plugins needs to work in a en_US.UTF-8 environment. # That's not always the case, so make sure it is export LC_ALL=en_US.UTF-8 export LANG=en_us.UTF-8 # We want to use $prefix/deps/usr/ for all our dependencies export DEPS_INSTALL_PREFIX=$BUILD_PREFIX/deps/usr/ export DOWNLOADS_DIR=$BUILD_PREFIX/downloads/ # Setup variables needed to help everything find what we built export LD_LIBRARY_PATH=$DEPS_INSTALL_PREFIX/lib/:$DEPS_INSTALL_PREFIX/lib/x86_64-linux-gnu/:$APPDIR/usr/lib/:$LD_LIBRARY_PATH export PATH=$DEPS_INSTALL_PREFIX/bin/:$PATH export PKG_CONFIG_PATH=$DEPS_INSTALL_PREFIX/share/pkgconfig/:$DEPS_INSTALL_PREFIX/lib/pkgconfig/:/usr/lib/pkgconfig/:$PKG_CONFIG_PATH export CMAKE_PREFIX_PATH=$DEPS_INSTALL_PREFIX:$CMAKE_PREFIX_PATH export PYTHONPATH=$DEPS_INSTALL_PREFIX/sip/:$DEPS_INSTALL_PREFIX/lib/python3.5/site-packages/:$DEPS_INSTALL_PREFIX/lib/python3.5/ export PYTHONHOME=$DEPS_INSTALL_PREFIX +# download +mkdir -p $DOWNLOADS_DIR +cd $DOWNLOADS_DIR +wget "https://github.com/AppImage/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage" -O AppImageUpdate + # Switch over to our build prefix cd $BUILD_PREFIX # # Now we can get the process started! # # Step 0: place the translations where ki18n and Qt look for them if [ -d $APPDIR/usr/share/locale ] ; then mv $APPDIR/usr/share/locale $APPDIR/usr/share/krita fi -# Step 1: Copy over all the resources provided by dependencies that we need +# Step 1: Copy over all the resources provided by dependencies that we need cp -r $DEPS_INSTALL_PREFIX/share/locale $APPDIR/usr/share/krita cp -r $DEPS_INSTALL_PREFIX/share/kf5 $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/share/mime $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/lib/python3.5 $APPDIR/usr/lib cp -r $DEPS_INSTALL_PREFIX/share/sip $APPDIR/usr/share cp -r $DEPS_INSTALL_PREFIX/translations $APPDIR/usr/ # Step 2: Relocate x64 binaries from the architecture specific directory as required for Appimages mv $APPDIR/usr/lib/x86_64-linux-gnu/* $APPDIR/usr/lib rm -rf $APPDIR/usr/lib/x86_64-linux-gnu/ # Step 3: Update the rpath in the various plugins we have to make sure they'll be loadable in an Appimage context for lib in $PLUGINS/*.so*; do - patchelf --set-rpath '$ORIGIN/..' $lib; + patchelf --set-rpath '$ORIGIN/..' $lib; done for lib in $APPDIR/usr/lib/python3.5/site-packages/PyQt5/*.so*; do - patchelf --set-rpath '$ORIGIN/../..' $lib; + patchelf --set-rpath '$ORIGIN/../..' $lib; done for lib in $APPDIR/usr/lib/python3.5/lib-dynload/*.so*; do - patchelf --set-rpath '$ORIGIN/../..' $lib; + patchelf --set-rpath '$ORIGIN/../..' $lib; done patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so patchelf --set-rpath '$ORIGIN/../../../..' $APPDIR/usr/lib/qml/org/krita/sketch/libkritasketchplugin.so patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so patchelf --set-rpath '$ORIGIN/../..' $APPDIR/usr/lib/python3.5/site-packages/PyQt5/sip.so +# Step 4: Install AppImageUpdate +if [ -f $DOWNLOADS_DIR/AppImageUpdate ]; then + cp $DOWNLOADS_DIR/AppImageUpdate $APPDIR/usr/bin/ + chmod +x $APPDIR/usr/bin/AppImageUpdate +fi + # Step 5: Find out what version of Krita we built and give the Appimage a proper name cd $BUILD_PREFIX/krita-build KRITA_VERSION=$(grep "#define KRITA_VERSION_STRING" libs/version/kritaversion.h | cut -d '"' -f 2) - # Also find out the revision of Git we built # Then use that to generate a combined name we'll distribute cd $KRITA_SOURCES if [[ -d .git ]]; then GIT_REVISION=$(git rev-parse --short HEAD) - VERSION=$KRITA_VERSION-$GIT_REVISION + export VERSION=$KRITA_VERSION-$GIT_REVISION + VERSION_TYPE="developement" + BRANCH="$(git rev-parse --abbrev-ref HEAD)" + if [ "$BRANCH" = "master" ]; then + CHANNEL="Next" + else + CHANNEL="Plus" + fi else - VERSION=$KRITA_VERSION + export VERSION=$KRITA_VERSION + + #if KRITA_BETA is set, set channel to Beta, otherwise set it to stable + grep "define KRITA_BETA 1" libs/version/kritaversion.h; + is_beta=$? + if [ is_beta -eq 0 ]; then + VERSION_TYPE="developement" + CHANNEL="Beta" + else + VERSION_TYPE="stable" + CHANNEL="Stable" + fi fi +DATE=$(git log -1 --format="%ct" | xargs -I{} date -d @{} +%Y-%m-%d) +if [ "$DATE" = "" ] ; then + DATE=$(date +%Y-%m-%d) +fi + +sed -e "s|||" -i $APPDIR/usr/share/metainfo/org.kde.krita.appdata.xml + +# set zsync url for linuxdeployqt +# TODO: replace with real urls +if [ "$CHANNEL" = "Next" ]; then + ZSYNC_URL="zsync|http://localhost:8000/nightly/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Plus" ]; then + ZSYNC_URL="zsync|http://localhost:8000/nightly/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Stable" ]; then + ZSYNC_URL="zsync|http://localhost:8000/stable/Krita-${CHANNEL}-x86_64.AppImage.zsync" +elif [ "$CHANNEL" = "Beta" ]; then + ZSYNC_URL="zsync|http://localhost:8000/unstable/Krita-${CHANNEL}-x86_64.AppImage.zsync" +fi # Return to our build root cd $BUILD_PREFIX +# TODO: icons for channels # place the icon where linuxdeployqt seems to expect it find $APPDIR -name krita.png cp /home/appimage//appimage-workspace/krita.appdir/usr/share/icons/hicolor/256x256/apps/krita.png $APPDIR ls $APPDIR # Step 4: Build the image!!! linuxdeployqt $APPDIR/usr/share/applications/org.kde.krita.desktop \ -executable=$APPDIR/usr/bin/krita \ -qmldir=$DEPS_INSTALL_PREFIX/qml \ -verbose=2 \ -bundle-non-qt-libs \ -extra-plugins=$PLUGINS,$APPDIR/usr/lib/krita-python-libs/PyKrita/krita.so,$APPDIR/usr/lib//qml/org/krita/sketch/libkritasketchplugin.so,$APPDIR/usr/lib/qml/org/krita/draganddrop/libdraganddropplugin.so \ - -appimage - -# Generate a new name for the Appimage file and rename it accordingly -APPIMAGE=krita-"$VERSION"-x86_64.appimage + -updateinformation="${ZSYNC_URL}" \ + -appimage + -mv Krita*x86_64.AppImage $APPIMAGE +mv Krita-${VERSION}-x86_64.AppImage.zsync "Krita-${CHANNEL}-x86_64.AppImage.zsync"