diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9c3819d..adbd1be94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,202 +1,202 @@ cmake_minimum_required(VERSION 3.0) project(plasma-workspace) set(PROJECT_VERSION "5.17.80") set(PROJECT_VERSION_MAJOR 5) set(QT_MIN_VERSION "5.12.0") set(KF5_MIN_VERSION "5.62.0") set(INSTALL_SDDM_THEME TRUE) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets Quick QuickWidgets Concurrent Test Network) find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMMarkNonGuiExecutable) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckIncludeFiles) include(FeatureSummary) include(ECMOptionalAddSubdirectory) include(ECMQtDeclareLoggingCategory) include(KDEPackageAppTemplates) include(KDEClangFormat) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma DocTools Runner NotifyConfig Su NewStuff Wallet IdleTime Declarative I18n KCMUtils TextWidgets KDELibs4Support Crash GlobalAccel DBusAddons Wayland CoreAddons People ActivitiesStats) find_package(KDED CONFIG REQUIRED) find_package(KF5NetworkManagerQt ${KF5_MIN_VERSION}) set_package_properties(KF5NetworkManagerQt PROPERTIES DESCRIPTION "Qt wrapper for NetworkManager API" TYPE OPTIONAL PURPOSE "Needed by geolocation data engine." ) find_package(KF5Kirigami2 ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Kirigami2 PROPERTIES DESCRIPTION "A QtQuick based components set" TYPE RUNTIME ) # WARNING PlasmaQuick provides unversioned CMake config find_package(KUserFeedback) find_package(KF5 REQUIRED COMPONENTS PlasmaQuick) find_package(KF5 REQUIRED COMPONENTS SysGuard) find_package(KF5 REQUIRED COMPONENTS Package) find_package(KF5Baloo) set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "File Searching" TYPE RECOMMENDED PURPOSE "Needed for the File Search runner." ) find_package(KF5TextEditor) find_package(KWinDBusInterface CONFIG REQUIRED) find_package(KF5Screen CONFIG REQUIRED) find_package(KScreenLocker 5.13.80 REQUIRED) find_package(ScreenSaverDBusInterface CONFIG REQUIRED) find_package(KF5Holidays) set_package_properties(KF5Holidays PROPERTIES DESCRIPTION "Holidays provider for Plasma calendar" TYPE OPTIONAL PURPOSE "Needed to for holidays plugin for Plasma Calendar." ) find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE) set_package_properties(Phonon4Qt5 PROPERTIES DESCRIPTION "Qt-based audio library" TYPE REQUIRED) find_package(KF5Activities ${KF5_MIN_VERSION}) set_package_properties(KF5Activities PROPERTIES DESCRIPTION "management of Plasma activities" TYPE OPTIONAL PURPOSE "Needed by activity related plasmoids." ) find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Support for gzip compressed files and data streams" - URL "http://www.zlib.net" + URL "https://www.zlib.net" TYPE REQUIRED ) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" - URL "http://www.x.org" + URL "https://www.x.org" TYPE OPTIONAL PURPOSE "Required for building the X11 based workspace") if(X11_FOUND) find_package(XCB MODULE REQUIRED COMPONENTS XCB RANDR) set_package_properties(XCB PROPERTIES TYPE REQUIRED) if(NOT X11_SM_FOUND) message(FATAL_ERROR "\nThe X11 Session Management (SM) development package could not be found.\nPlease install libSM.\n") endif(NOT X11_SM_FOUND) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS X11Extras) endif() if(X11_FOUND AND XCB_XCB_FOUND) set(HAVE_X11 1) endif() find_package(AppStreamQt 0.10.6) set_package_properties(AppStreamQt PROPERTIES DESCRIPTION "Access metadata for listing available software" URL "https://www.freedesktop.org/wiki/Distributions/AppStream/" TYPE OPTIONAL ) if(${AppStreamQt_FOUND}) set(HAVE_APPSTREAMQT true) endif() include(ConfigureChecks.cmake) include_directories("${CMAKE_CURRENT_BINARY_DIR}") configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-workspace.h) configure_file(config-unix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-unix.h ) configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h) configure_file(config-appstream.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-appstream.h ) add_subdirectory(login-sessions) plasma_install_package(lookandfeel org.kde.breeze.desktop look-and-feel lookandfeel) if (INSTALL_SDDM_THEME) configure_file(sddm-theme/theme.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/sddm-theme/theme.conf) # Install the login theme into the SDDM directory # Longer term we need to look at making SDDM load from look and feel somehow.. and allow copying at runtime #NOTE this trailing slash is important to rename the directory install(DIRECTORY sddm-theme/ DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze PATTERN "README.txt" EXCLUDE PATTERN "components" EXCLUDE PATTERN "dummydata" EXCLUDE PATTERN "theme.conf.cmake" EXCLUDE) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sddm-theme/theme.conf DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze) install(DIRECTORY lookandfeel/contents/components DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze PATTERN "README.txt" EXCLUDE) endif() add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_subdirectory(doc) add_subdirectory(libkworkspace) add_subdirectory(libdbusmenuqt) add_subdirectory(appmenu) add_subdirectory(libtaskmanager) add_subdirectory(libnotificationmanager) add_subdirectory(libcolorcorrect) add_subdirectory(components) add_subdirectory(plasma-windowed) add_subdirectory(shell) add_subdirectory(freespacenotifier) add_subdirectory(klipper) add_subdirectory(krunner) add_subdirectory(ksmserver) add_subdirectory(logout-greeter) add_subdirectory(ksplash) add_subdirectory(systemmonitor) add_subdirectory(statusnotifierwatcher) add_subdirectory(startkde) add_subdirectory(themes) add_subdirectory(kcms) add_subdirectory(containmentactions) add_subdirectory(runners) add_subdirectory(applets) add_subdirectory(dataengines) add_subdirectory(wallpapers) add_subdirectory(kioslave) add_subdirectory(ktimezoned) add_subdirectory(menu) add_subdirectory(phonon) # This ensures pressing the eject button on a CD drive ejects the disc # It listens to the Solid::OpticalDrive::ejectPressed signal that is only # supported by Solid in the HAL backend and does nothing with UDev if(CMAKE_SYSTEM_NAME MATCHES FreeBSD) add_subdirectory(solidautoeject) endif() ecm_optional_add_subdirectory(xembed-sni-proxy) ecm_optional_add_subdirectory(gmenu-dbusmenu-proxy) add_subdirectory(soliduiserver) if(KF5Holidays_FOUND) add_subdirectory(plasmacalendarintegration) endif() add_subdirectory(templates) install(FILES plasma-workspace.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) # add clang-format target for all our real source files file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h) kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) diff --git a/applets/analog-clock/metadata.desktop b/applets/analog-clock/metadata.desktop index 463ea3229..eb412a2a1 100644 --- a/applets/analog-clock/metadata.desktop +++ b/applets/analog-clock/metadata.desktop @@ -1,170 +1,170 @@ [Desktop Entry] Name=Analog Clock Name[af]=Analooghorlosie Name[ar]=ساعة تناظرية Name[ast]=Reló analóxicu Name[be]=Аналагавы гадзіннік Name[be@latin]=Analahavy hadzińnik Name[bg]=Аналогов часовник Name[bn]=অ্যানালগ ঘড়ি Name[bs]=Analogni sat Name[ca]=Rellotge analògic Name[ca@valencia]=Rellotge analògic Name[cs]=Analogové hodiny Name[csb]=Analogòwi zédżer Name[da]=Analogt ur Name[de]=Analoge Uhr Name[el]=Αναλογικό ρολόι Name[en_GB]=Analogue Clock Name[eo]=Analoga horloĝo Name[es]=Reloj analógico Name[et]=Analoogkell Name[eu]=Erloju analogikoa Name[fa]=ساعت قیاسی Name[fi]=Analoginen kello Name[fr]=Horloge analogique Name[fy]=Analoge klok Name[ga]=Clog Analógach Name[gl]=Reloxo analóxico Name[gu]=સાદી ઘડિયાળ Name[he]=שעון מחוגים Name[hi]=एनॉलॉग घड़ी Name[hne]=एनालाग घड़ी Name[hr]=Analogni sat Name[hsb]=Analogny časnik Name[hu]=Mutatós óra Name[ia]=Horologio analogic Name[id]=Jam Analog Name[is]=Skífuklukka Name[it]=Orologio analogico Name[ja]=アナログ時計 Name[kk]=Аналогты сағат Name[km]=នាឡិកា​អាណាឡូក Name[kn]=ಅವಿಚ್ಛಿನ್ನಾತ್ಮಕ (ಅನಲಾಗ್, ಸಾಂಪ್ರದಾಯಿಕ) ಗಡಿಯಾರ Name[ko]=아날로그 시계 Name[ku]=Demjimêra Analog Name[lt]=Analoginis laikrodis Name[lv]=Rādītāju pulkstenis Name[mai]=एनालाग घडी Name[mk]=Аналоген часовник Name[ml]=അനലോഗ് ഘടികാരം Name[mr]=एनॉलॉग घड्याळ Name[nb]=Analog klokke Name[nds]=Analoog Klock Name[ne]=एनालग घडी Name[nl]=Analoge klok Name[nn]=Analog klokke Name[oc]=Relòtge analogic Name[pa]=ਐਨਾਲਾਗ ਘੜੀ Name[pl]=Zegar analogowy Name[pt]=Relógio Analógico Name[pt_BR]=Relógio Analógico Name[ro]=Ceas analog Name[ru]=Часы с циферблатом Name[se]=Analogalaš diibmu Name[si]=ප්‍රතිසම ඔරලෝසුව Name[sk]=Analógové hodiny Name[sl]=Analogna ura Name[sr]=аналогни сат Name[sr@ijekavian]=аналогни сат Name[sr@ijekavianlatin]=analogni sat Name[sr@latin]=analogni sat Name[sv]=Analog klocka Name[ta]=சுழல் கடிகாரம் Name[te]=ఎనలాగ్ గడియారం Name[tg]=Соати аналогӣ Name[th]=นาฬิกาแอนะล็อก Name[tr]=Analog Saat Name[ug]=ئانالوگ سائەت Name[uk]=Аналоговий годинник Name[uz]=Analog soat Name[uz@cyrillic]=Аналог соат Name[vi]=Đồng hồ số Name[wa]=Ôrlodje analodjike Name[x-test]=xxAnalog Clockxx Name[zh_CN]=模拟时钟 Name[zh_TW]=類比時鐘 Comment=A clock with hands Comment[ar]=ساعة بِعقارب Comment[ast]=Un reló con aguyes Comment[bg]=Часовник със стрелки Comment[bs]=Sat sa kazaljkama Comment[ca]=Un rellotge amb agulles Comment[ca@valencia]=Un rellotge amb agulles Comment[cs]=Ručičkové hodiny Comment[da]=Et ur med visere Comment[de]=Eine Uhr mit Zeigern Comment[el]=Ένα ρολόι με δείκτες Comment[en_GB]=A clock with hands Comment[eo]=Horloĝo kun manoj Comment[es]=Un reloj con manecillas Comment[et]=Seieritega kell Comment[eu]=Erloju orraztuna Comment[fi]=Viisarikello Comment[fr]=Une horloge à aiguilles Comment[fy]=In klok mei wizerplaat Comment[ga]=Clog le lámha Comment[gl]=Un reloxo con agullas Comment[he]=שעון עם מחוגים Comment[hi]=सुई वाली घडी Comment[hr]=Sat s kazaljkama Comment[hu]=Óra mutatókkal Comment[ia]=Un horologio con manos Comment[id]=Sebuah jam tangan Comment[is]=Klukka með vísum Comment[it]=Un orologio con lancette Comment[ja]=針のある時計 Comment[kk]=Тілді сағат Comment[km]=ចាក់សោ​ដោយ​ដៃ Comment[kn]=ಮುಳ್ಳುಗಳನ್ನು ಹೊಂದಿರುವ ಗಡಿಯಾರ Comment[ko]=시침과 분침이 있는 시계 Comment[lt]=Laikrodis su rodyklėmis Comment[lv]=Rādītāju pulkstenis Comment[mk]=Часовник со раце Comment[mr]=हात असलेले घड्याळ Comment[nb]=En klokke med visere Comment[nds]=En Klock mit Wiesers Comment[nl]=Een klok met wijzers Comment[nn]=Ei klokke med visarar Comment[pa]=ਸੂਈਆਂ ਨਾਲ ਘੜੀ Comment[pl]=Zegar ze wskazówkami Comment[pt]=Um relógio com ponteiros Comment[pt_BR]=Um relógio com ponteiros Comment[ro]=Ceas cu mâini Comment[ru]=Часы со стрелками Comment[si]=කටු සහිත ඔරලෝසුවක් Comment[sk]=Ručičkové hodiny Comment[sl]=Ura s kazalci Comment[sr]=Сат са казаљкама Comment[sr@ijekavian]=Сат са казаљкама Comment[sr@ijekavianlatin]=Sat sa kazaljkama Comment[sr@latin]=Sat sa kazaljkama Comment[sv]=En klocka med visare Comment[th]=นาฬิกาแบบเข็ม Comment[tr]=İbreli bir saat Comment[ug]=تىللىق سائەت Comment[uk]=Годинник зі стрілками Comment[wa]=Ène ôrlodje avou des aweyes Comment[x-test]=xxA clock with handsxx Comment[zh_CN]=带指针的时钟 Comment[zh_TW]=有手的時鐘 Icon=preferences-system-time Type=Service X-KDE-ServiceTypes=Plasma/Applet X-Plasma-API=declarativeappletscript X-Plasma-MainScript=ui/analogclock.qml X-Plasma-Provides=org.kde.plasma.time,org.kde.plasma.date X-Plasma-StandAloneApp=true X-KDE-PluginInfo-Author=Marco Martin X-KDE-PluginInfo-Email=mart@kde.org X-KDE-PluginInfo-Name=org.kde.plasma.analogclock X-KDE-PluginInfo-Version=3.0 -X-KDE-PluginInfo-Website=http://userbase.kde.org/Plasma/Clocks +X-KDE-PluginInfo-Website=https://userbase.kde.org/Plasma/Clocks X-KDE-PluginInfo-Category=Date and Time X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL-2.0+ X-KDE-PluginInfo-EnabledByDefault=true diff --git a/applets/batterymonitor/package/metadata.desktop b/applets/batterymonitor/package/metadata.desktop index ec92e4189..8d9d20a10 100644 --- a/applets/batterymonitor/package/metadata.desktop +++ b/applets/batterymonitor/package/metadata.desktop @@ -1,190 +1,190 @@ [Desktop Entry] Name=Battery and Brightness Name[ar]=البطّاريّة والسّطوع Name[ast]=Batería y brilléu Name[ca]=Bateria i lluminositat Name[ca@valencia]=Bateria i brillantor Name[cs]=Baterie a Jas Name[da]=Batteri og lysstyrke Name[de]=Akku und Bildschirmhelligkeit Name[el]=Μπαταρία και λαμπρότητα Name[en_GB]=Battery and Brightness Name[es]=Batería y brillo Name[et]=Aku ja heledus Name[eu]=Bateria eta distira Name[fi]=Akku ja kirkkaus Name[fr]=Batterie et luminosité Name[gl]=Batería e brillo Name[he]=סוללה ובהירות Name[hu]=Akkumulátor és fényerő Name[id]=Baterai dan Kecerahan Name[is]=Rafhlaða og skjábirta Name[it]=Batteria e luminosità Name[ja]=バッテリーと明るさ Name[ko]=배터리와 밝기 Name[lt]=Akumuliatorius ir ryškumas Name[nl]=Batterij en helderheid Name[nn]=Batteri og lysstyrke Name[pa]=ਬੈਟਰੀ ਤੇ ਚਮਕ Name[pl]=Bateria i jasność Name[pt]=Bateria e Brilho Name[pt_BR]=Bateria e brilho da tela Name[ru]=Батарея и яркость Name[sk]=Batéria a jas Name[sl]=Baterija in svetlost Name[sr]=Батерија и осветљај Name[sr@ijekavian]=Батерија и освјетљај Name[sr@ijekavianlatin]=Baterija i osvjetljaj Name[sr@latin]=Baterija i osvetljaj Name[sv]=Batteri och ljusstyrka Name[tg]=Батарея ва дурахшонӣ Name[tr]=Pil ve Ekran Parlaklığı Name[uk]=Акумулятор і яскравість дисплея Name[x-test]=xxBattery and Brightnessxx Name[zh_CN]=电池和亮度 Name[zh_TW]=電池與亮度 Comment=See the power status of your battery Comment[ar]=طالع حالة طاقة البطارية Comment[ast]=Visualiza l'estáu de la carga de la batería Comment[be@latin]=Naziraje za kolkaściu enerhii ŭ tvajoj batarei Comment[bg]=Показва състоянието на батерията Comment[bs]=Pazite na stanje popunjenosti baterije Comment[ca]=Vegeu l'estat d'energia de la bateria Comment[ca@valencia]=Vegeu l'estat d'energia de la bateria Comment[cs]=Zobrazí stav nabití vaší baterie Comment[csb]=Òbôczë stón twòji baterëji Comment[da]=Se dit batteris strømstatus Comment[de]=Zeigt den Ladestatus des Akkus an Comment[el]=Δείτε την κατάσταση ισχύος της μπαταρίας σας Comment[en_GB]=See the power status of your battery Comment[eo]=Montri energian staton de viaj baterioj Comment[es]=Mire el estado de potencia de su batería Comment[et]=Aku oleku näitaja Comment[eu]=Ikusi zure bateriaren energia-egoera Comment[fi]=Näyttää akun virtatilanteen Comment[fr]=Voir le niveau d'énergie de votre batterie Comment[fy]=Besjoch de stroomtastân fan jo batterij Comment[ga]=Féach ar stádas cumhachta do chadhnra Comment[gl]=Consulta o estado enerxético da batería Comment[gu]=તમારી બેટ્રી માટે પાવર સ્થિતિ જુઓ Comment[he]=משמש להצגת מצב הטעינה של הסוללה Comment[hi]=बैटरी का पावर देखें Comment[hne]=अपन बेटरी के पावर ल देखव Comment[hr]=Vidite trenutno stanje baterije Comment[hsb]=Pohladajće na status akuwa Comment[hu]=Kijelzi a telepek állapotát Comment[ia]=Vide le stato de energia de tu batteria Comment[id]=Lihat status daya bateraimu Comment[is]=Sjá orkustöðu rafhlöðu Comment[it]=Indica lo stato di carica della batteria Comment[ja]=バッテリの状態を表示します Comment[kk]=Батареяның қуат деңгейін қарау Comment[km]=មើល​ស្ថានភាព​ថាមពល​នៃ​ថ្ម​របស់​អ្នក Comment[kn]=ನಿನ್ನ ವಿದ್ಯುತ್ಕೋಶದ (ಬಾಟರಿ) ಸ್ಥಿತಿಯನ್ನು ನೋಡು Comment[ko]=배터리 상태를 표시합니다 Comment[lt]=Rodyti akumuliatoriaus įkrovą Comment[lv]=Rāda baterijas izlādes stāvokli Comment[mk]=Видете го енергетскиот статус на вашата батерија Comment[ml]=നിങ്ങളുടെ ബാറ്ററിയുടെ വൈദ്യുതി ഊര്‍ജ്ജ സ്ഥിതി കാണുക Comment[mr]=बॅटरीची पॉवर स्थिती पहा Comment[nb]=Se ladningstilstanden for batteriet Comment[nds]=Den Tostand vun Dien Batterien bekieken Comment[nl]=Zie de capaciteitsstatus van uw accu Comment[nn]=Sjå straumnivået på batteriet Comment[pa]=ਆਪਣੀ ਬੈਟਰੀ ਦੀ ਊਰਜਾ ਹਾਲਤ ਵੇਖੋ Comment[pl]=Monitoruje stan naładowania baterii Comment[pt]=Ver o estado de energia da sua bateria Comment[pt_BR]=Mostra o estado da carga da sua bateria Comment[ro]=Vizualizați starea acumulatorului dumneavoastră Comment[ru]=Просмотр уровня заряда батареи Comment[si]=ඔබේ බැටරියේ බල තත්වය බලන්න Comment[sk]=Zobrazenie stavu nabitia vašej batérie Comment[sl]=Oglejte si stanje napolnjenosti baterij Comment[sr]=Пазите на стање попуњености батерије Comment[sr@ijekavian]=Пазите на стање попуњености батерије Comment[sr@ijekavianlatin]=Pazite na stanje popunjenosti baterije Comment[sr@latin]=Pazite na stanje popunjenosti baterije Comment[sv]=Se batteriets laddningsstatus Comment[ta]=See the power status of your battery Comment[te]=మీ బ్యాటరీ యొక్క పవర్ స్థితిని చూడుము Comment[tg]=Вазъияти қувваи барқи батареяро назорат кунед Comment[th]=แสดงสถานะพลังงานของแบตเตอรี่ของคุณ Comment[tr]=Pilinizin güç durumuna bakın Comment[ug]=توكدانىڭىزنىڭ توك ھالىتىنى كۆرسىتىدۇ Comment[uk]=Перегляньте стан заряду акумулятора Comment[wa]=Vey li tchedje di vosse batreye Comment[x-test]=xxSee the power status of your batteryxx Comment[zh_CN]=查看电池的电量状态 Comment[zh_TW]=查看您的電池的電力狀態 Keywords=Power Management;Battery;System;Energy; Keywords[ar]=إدارة الطاقة;بطارية;نظام;طاقة; Keywords[ast]=Xestión d'enerxía;Batería;Sistema;Enerxía; Keywords[bs]=Upravljanje napajenjem;Baterija;Sistem;Energija; Keywords[ca]=Sistema de gestió d'energia;Bateria;Sistema;Energia; Keywords[ca@valencia]=Sistema de gestió d'energia;Bateria;Sistema;Energia; Keywords[cs]=Správa napájení;Baterie;Systém;Energie; Keywords[da]=Strømstyring;battery;system;energi; Keywords[de]=Energieverwaltungssystem;Akku;System;Energie; Keywords[el]=Διαχείριση ισχύος;Μπαταρία;Σύστημα;Ενέργεια; Keywords[en_GB]=Power Management;Battery;System;Energy; Keywords[es]=Gestión de energía;Batería;Sistema;Energía; Keywords[et]=Toitehaldus;aku;süsteem;energia; Keywords[eu]=energia kudeaketa;bateria;sistema;energia; Keywords[fi]=Virranhallinta;Akku;Järjestelmä;Virransäästö; Keywords[fr]=Gestion de l'énergie;Batterie;Système;Énergie; Keywords[gl]=Xestión da enerxía;batería;sistema;enerxía; Keywords[he]=Power Management; Battery; System; Energy;ניהול חשמל;חשמל; סוללה; מערכת;אנרגיה; בטריה; Keywords[hu]=Energiakezelés;Akkumulátor;Rendszer;Energia; Keywords[ia]=Gestion de energia;Batteria;Systema; Energia; Keywords[id]=Pengelolaan Daya;Baterai;Sistem;Energi; Keywords[is]=Orkustjórnun;Rafhlaða;Kerfi;Afl; Keywords[it]=Gestione energetica;Batteria;Sistema;Energia; Keywords[ja]=電源管理;バッテリー;システム;エネルギー; Keywords[kk]=Power Management;Battery;System;Energy; Keywords[ko]=Power Management;Battery;System;Energy;전원 관리;전력 관리;배터리;시스템;에너지; Keywords[lt]=Energijos valdymas;Baterija;Sistema;Energija;Akumuliatorius;Maitinimo valdymas Keywords[mr]=वीज व्यवस्थापन; बॅटरी; प्रणाली; ऊर्जा; Keywords[nb]=Strømstyring; Batteri; System; Energi; Keywords[nds]=Stroompleeg,Batterie,Systeem,Energie Keywords[nl]=Energiebeheer;Batterij;Accu;Systeem;Energie; Keywords[nn]=straumstyring;batteri;system;energi; Keywords[pa]=ਪਾਵਰ ਪਰਬੰਧ;ਬੈਟਰੀ;ਸਿਸਟਮ;ਊਰਜਾ; Keywords[pl]=Zarządzanie Energią;Bateria;System;Energia; Keywords[pt]=Gestão de Energia;Bateria;Sistema;Energia; Keywords[pt_BR]=Gerenciamento de energia;Bateria;Sistema;Energia; Keywords[ro]=gestiunea alimentării;acumulator;sistem;energie; Keywords[ru]=Power Management;Battery;System;Energy;управление питанием;батарея;система;энергия;энергопотребление; Keywords[sk]=Správa napájania;Batéria;Systém;Energia; Keywords[sl]=upravljanje z energijo;baterija;sistem;energija; Keywords[sr]=Power Management;Battery;System;Energy;управљање напајањем;батерија; систем;енергија; Keywords[sr@ijekavian]=Power Management;Battery;System;Energy;управљање напајањем;батерија; систем;енергија; Keywords[sr@ijekavianlatin]=Power Management;Battery;System;Energy;upravljanje napajanjem;baterija; sistem;energija; Keywords[sr@latin]=Power Management;Battery;System;Energy;upravljanje napajanjem;baterija; sistem;energija; Keywords[sv]=Strömhantering;Batteri;System;Energi; Keywords[tr]=Güç Yönetimi;Pil;Sistem;Enerji; Keywords[uk]=Power Management;Battery;System;Energy;керування живленням;акумулятор;система;енергія;батарея;батарейка;живлення; Keywords[x-test]=xxPower Managementxx;xxBatteryxx;xxSystemxx;xxEnergyxx; Keywords[zh_CN]=电源管理;电池;系统;能源; Keywords[zh_TW]=Power Management;Battery;System;Energy; Icon=battery-full Type=Service X-KDE-ServiceTypes=Plasma/Applet X-Plasma-API=declarativeappletscript X-Plasma-MainScript=ui/batterymonitor.qml X-Plasma-NotificationArea=true X-Plasma-NotificationAreaCategory=Hardware X-Plasma-Provides=org.kde.plasma.powermanagement X-KDE-PluginInfo-Author=Sebastian Kügler, Kai Uwe Broulik X-KDE-PluginInfo-Category=System Information X-KDE-PluginInfo-Email=sebas@kde.org, kde@privat.broulik.de X-KDE-PluginInfo-License=GPL-2.0+ X-KDE-PluginInfo-Name=org.kde.plasma.battery X-KDE-PluginInfo-Version=3.0 -X-KDE-PluginInfo-Website=http://vizZzion.org +X-KDE-PluginInfo-Website=https://vizzzion.org X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-EnabledByDefault=true X-Plasma-DBusActivationService=org.kde.Solid.PowerManagement diff --git a/applets/devicenotifier/package/metadata.desktop b/applets/devicenotifier/package/metadata.desktop index b36baa42a..f7ed03c75 100644 --- a/applets/devicenotifier/package/metadata.desktop +++ b/applets/devicenotifier/package/metadata.desktop @@ -1,170 +1,170 @@ [Desktop Entry] Name=Device Notifier Name[ar]=مُخطِر الأجهزة Name[ast]=Avisador de preseos Name[be@latin]=Infarmavańnie pra novyja pryłady Name[bg]=Уведомяване за нови устройства Name[bn]=ডিভাইস নোটিফায়ার Name[bn_IN]=ডিভাইসের সূচনা ব্যবস্থা Name[bs]=Izveštavač o uređajima Name[ca]=Notificador de dispositius Name[ca@valencia]=Notificador de dispositius Name[cs]=Upozornění na zařízení Name[csb]=Dôwôcz wiédzë ò ùrządzeniach Name[da]=Enhedsbekendtgørelse Name[de]=Geräteüberwachung Name[el]=Ειδοποίηση νέας συσκευής Name[en_GB]=Device Notifier Name[eo]=Atentigilo pri nova aparato Name[es]=Notificador de dispositivos Name[et]=Seadmete teadustaja Name[eu]=Gailu-jakinarazlea Name[fa]=اخطار دهنده‌ی دستگاه Name[fi]=Laiteilmoitin Name[fr]=Notification de nouveau périphérique Name[fy]=Apparaat meidieler Name[ga]=Fógróir Gléis Name[gl]=Notificador de dispositivos Name[gu]=ઉપકરણ નોંધ કરનાર Name[he]=מודיע על התקנים Name[hi]=उपकरण सूचक Name[hne]=उपकरन बतइया Name[hr]=Glasnik uređaja Name[hsb]=Zdźělenki wo gratach Name[hu]=Eszközértesítő Name[ia]=Notificator de dispositivo Name[id]=Penotifikasi Perangkat Name[is]=Tilkynningar um ný tæki Name[it]=Notificatore dei dispositivi Name[ja]=デバイスの通知 Name[kk]=Құрылғы құлақтандырғышы Name[km]=កម្មវិធី​ជូនដំណឹង​ឧបករណ៍​ Name[kn]=ಹೊಸ ಸಾಧನ ಸೂಚಕ Name[ko]=장치 알림이 Name[ku]=Hişyarkerê Cîhaz Name[lt]=Pranešimai apie įrenginius Name[lv]=Ierīču paziņotājs Name[mk]=Известувач за уреди Name[ml]=പുതിയ ഡിവൈസ് അറിയിക്കുന്നതിനുള്ള സംവിധാനം Name[mr]=साधन निदर्शक Name[nb]=Enhetsvarsler Name[nds]=Bescheden över Reedschappen Name[nl]=Apparaatmelder Name[nn]=Einingsvarslar Name[pa]=ਜੰਤਰ ਨੋਟੀਫਾਇਰ Name[pl]=Powiadomienia o urządzeniach Name[pt]=Notificação de Dispositivos Name[pt_BR]=Notificação de dispositivos Name[ro]=Notificare dispozitive Name[ru]=Подключаемые устройства Name[si]=උපාංග දැනුම් දීම Name[sk]=Monitor zariadení Name[sl]=Obvestila o napravah Name[sr]=извештавач о уређајима Name[sr@ijekavian]=извјештавач о уређајима Name[sr@ijekavianlatin]=izvještavač o uređajima Name[sr@latin]=izveštavač o uređajima Name[sv]=Underrättelse om enheter Name[ta]=கருவி நோட்டம் Name[th]=แจ้งให้ทราบถึงอุปกรณ์ Name[tr]=Aygıt Bildirici Name[ug]=ئۈسكۈنە ئۇقتۇرۇشى Name[uk]=Сповіщення про пристрої Name[vi]=Trình thông báo thiết bị Name[wa]=Notifiaedje d' éndjin Name[x-test]=xxDevice Notifierxx Name[zh_CN]=设备通知器 Name[zh_TW]=裝置通知 Comment=Notifications and access for new devices Comment[ar]=إخطارات ووصول الأجهزة الجديدة Comment[be@latin]=Infarmavańnie j dostup da novych pryładaŭ Comment[bg]=Уведомления и достъп до новите устройства Comment[bs]=Obavještavanje i pristup novim uređajima Comment[ca]=Notificacions i accés als dispositius nous Comment[ca@valencia]=Notificacions i accés als dispositius nous Comment[cs]=Upozorňování a přístup k novým zařízením Comment[csb]=Dôwanié wiédzë ë przëstãp do nowich ùrządzeniów Comment[da]=Bekendtgørelse om og adgang til nye enheder Comment[de]=Benachrichtigungen über neue Geräte und Zugriff darauf Comment[el]=Ειδοποιήσεις και πρόσβαση νέων συσκευών Comment[en_GB]=Notifications and access for new devices Comment[eo]=Atentigoj kaj atingo por novaj aparatoj Comment[es]=Notificaciones y accesos de nuevos dispositivos Comment[et]=Uutest seadmetest teatamine ja nende kasutamine Comment[eu]=Jakinarazpenak eta gailu berrietara sarbidea Comment[fi]=Ilmoitukset ja pääsy uusille laitteille Comment[fr]=Notifications et accès aux nouveaux périphériques Comment[fy]=Notifikaasjes en tagong foar nije apparaten Comment[ga]=Fógairt agus rochtain ar ghléasanna nua Comment[gl]=Notificacións e acceso a novos dispositivos Comment[gu]=નવા ઉપકરણો માટે નોંધણી અને પ્રવેશ Comment[he]=הודעות על התקנים חדשים וגישה אליהם Comment[hi]=नए उपकरणों के लिए सूचनाएँ व पहुँच Comment[hne]=नवा उपकरन बर सूचना अउ पहुंच Comment[hr]=Obavijesti i pristup novim uređajima Comment[hsb]=Zdźělenki a spřistupnjenje nowych gratow Comment[hu]=Új eszközök elérése, értesítő üzenetek kezelése Comment[ia]=Notificationes e accesso pro nove dispositivos Comment[id]=Notifikasi dan akses terhadap perangkat baru Comment[is]=Tilkynningar um og aðgangur að nýjum tækjum Comment[it]=Notifiche e accesso ai nuovi dispositivi Comment[ja]=新しいデバイスの通知とアクセスを提供します Comment[kk]=Жаңа құрылғылар туралы құлақтандыру және олаға қатынау Comment[km]=កា​រជូន​ដំណឹង និង​ចូល​ដំណើរការ​សម្រាប់​ឧបករណ៍​ថ្មី Comment[kn]=ಹೊಸ ಸಾಧನಗಳಿಗೆ ಸೂಚನೆಗಳು ಮತ್ತು ನಿಲುಕಣೆ Comment[ko]=새 장치가 연결된 것을 알려 주고 접근할 수 있도록 합니다 Comment[ku]=Hişyarî û gihîştin ji bo cîhazên nû Comment[lt]=Pranešimų apie įrenginius ir prieiga prie jų Comment[lv]=Paziņojumi un piekļuve jaunām ierīcēm Comment[mk]=Известувања и пристап до нови уреди Comment[ml]=പുതിയ ഉപകരണങ്ങളുടെ അറിയിപ്പുകളും സമീപനവും Comment[mr]=नवीन साधन करिता सूचना व प्रवेश Comment[nb]=Varslinger om og tilgang til nye enheter Comment[nds]=Bescheden un Togriep för nieg Reedschappen Comment[nl]=Maakt melding van nieuwe apparaten en biedt toegang tot deze apparaten Comment[nn]=Varsling og tilgang til nye einingar Comment[pa]=ਨਵੇਂ ਜੰਤਰਾਂ ਲਈ ਨੋਟੀਫਿਕੇਸ਼ਨ ਅਤੇ ਵਰਤੋਂ Comment[pl]=Powiadamia i daje dostęp do nowych urządzeń Comment[pt]=Notificações e acesso aos dispositivos novos Comment[pt_BR]=Notificações e acesso aos novos dispositivos Comment[ro]=Notificări și acces pentru dispozitivele noi Comment[ru]=Уведомление о подключаемых устройствах и доступ к ним Comment[si]=නව උපකරණ සඳහා පිවිසීම හා දැන්වීම් Comment[sk]=Upozornenia a prístup k novým zariadeniam Comment[sl]=Obvestila o novih napravah in dostop do njih Comment[sr]=Обавештавање и приступ новим уређајима Comment[sr@ijekavian]=Обавјештавање и приступ новим уређајима Comment[sr@ijekavianlatin]=Obavještavanje i pristup novim uređajima Comment[sr@latin]=Obaveštavanje i pristup novim uređajima Comment[sv]=Underrättelser och åtkomst av nya enheter Comment[ta]=Notifications and access for new devices Comment[te]=కొత్త పరికరముల కొరకు నోటీసులు మరియు యాక్సెస్ Comment[th]=การแจ้งให้ทราบและเข้าใช้งานอุปกรณ์ใหม่ Comment[tr]=Yeni donanım bildirimleri ve yeni donanımlara erişim Comment[ug]=يېڭى ئۈسكۈنە ئۇقتۇرۇشى ۋە زىيارىتى Comment[uk]=Сповіщення і доступ до нових пристроїв Comment[wa]=Notifiaedjes eyet accès ås noveas éndjins Comment[x-test]=xxNotifications and access for new devicesxx Comment[zh_CN]=通知和访问新设备 Comment[zh_TW]=通知與存取新裝置 Icon=device-notifier Type=Service X-KDE-ServiceTypes=Plasma/Applet X-Plasma-API=declarativeappletscript X-Plasma-MainScript=ui/devicenotifier.qml X-Plasma-NotificationArea=true X-Plasma-NotificationAreaCategory=Hardware X-Plasma-Provides=org.kde.plasma.removabledevices X-KDE-PluginInfo-Author=Viranch Mehta, Jacopo De Simoi X-KDE-PluginInfo-Email=wilderkde@gmail.com X-KDE-PluginInfo-Name=org.kde.plasma.devicenotifier X-KDE-PluginInfo-Version=1.0 -X-KDE-PluginInfo-Website=http://userbase.kde.org/Plasma/DeviceNotifier +X-KDE-PluginInfo-Website=https://userbase.kde.org/Plasma/DeviceNotifier X-KDE-PluginInfo-Category=System Information X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL-2.0+ X-KDE-PluginInfo-EnabledByDefault=true diff --git a/applets/digital-clock/package/contents/ui/DigitalClock.qml b/applets/digital-clock/package/contents/ui/DigitalClock.qml index 0ac5ba8c9..a9f419777 100644 --- a/applets/digital-clock/package/contents/ui/DigitalClock.qml +++ b/applets/digital-clock/package/contents/ui/DigitalClock.qml @@ -1,699 +1,699 @@ /* * Copyright 2013 Heena Mahour * Copyright 2013 Sebastian Kügler * Copyright 2013 Martin Klapetek * Copyright 2014 David Edmundson * * 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, see . */ import QtQuick 2.6 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as Components import org.kde.plasma.private.digitalclock 1.0 Item { id: main property string timeFormat property date currentTime property bool showSeconds: plasmoid.configuration.showSeconds property bool showLocalTimezone: plasmoid.configuration.showLocalTimezone property bool showDate: plasmoid.configuration.showDate property var dateFormat: { if (plasmoid.configuration.dateFormat === "custom") { return plasmoid.configuration.customDateFormat; // str } else if (plasmoid.configuration.dateFormat === "longDate") { return Qt.SystemLocaleLongDate; // int } else if (plasmoid.configuration.dateFormat === "isoDate") { return Qt.ISODate; // int } else { // "shortDate" return Qt.SystemLocaleShortDate; // int } } property string lastSelectedTimezone: plasmoid.configuration.lastSelectedTimezone property bool displayTimezoneAsCode: plasmoid.configuration.displayTimezoneAsCode property int use24hFormat: plasmoid.configuration.use24hFormat property string lastDate: "" property int tzOffset // This is the index in the list of user selected timezones property int tzIndex: 0 // if the date/timezone cannot be fit with the smallest font to its designated space readonly property bool oneLineMode: plasmoid.formFactor === PlasmaCore.Types.Horizontal && main.height <= 2 * theme.smallestFont.pixelSize && (main.showDate || timezoneLabel.visible) onDateFormatChanged: { setupLabels(); } onDisplayTimezoneAsCodeChanged: { setupLabels(); } onStateChanged: { setupLabels(); } onLastSelectedTimezoneChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) } onShowSecondsChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) } onShowLocalTimezoneChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) } onShowDateChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) } onUse24hFormatChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) } Connections { target: plasmoid onContextualActionsAboutToShow: { ClipboardMenu.secondsIncluded = main.showSeconds; ClipboardMenu.currentDate = main.currentTime; } } Connections { target: plasmoid.configuration onSelectedTimeZonesChanged: { // If the currently selected timezone was removed, // default to the first one in the list var lastSelectedTimezone = plasmoid.configuration.lastSelectedTimezone; if (plasmoid.configuration.selectedTimeZones.indexOf(lastSelectedTimezone) === -1) { plasmoid.configuration.lastSelectedTimezone = plasmoid.configuration.selectedTimeZones[0]; } setupLabels(); setTimezoneIndex(); } } states: [ State { name: "horizontalPanel" when: plasmoid.formFactor === PlasmaCore.Types.Horizontal && !main.oneLineMode PropertyChanges { target: main Layout.fillHeight: true Layout.fillWidth: false Layout.minimumWidth: contentItem.width Layout.maximumWidth: Layout.minimumWidth } PropertyChanges { target: contentItem height: timeLabel.height + (main.showDate || timezoneLabel.visible ? 0.8 * timeLabel.height : 0) width: Math.max(labelsGrid.width, timezoneLabel.paintedWidth, dateLabel.paintedWidth) } PropertyChanges { target: labelsGrid rows: main.showDate ? 1 : 2 } AnchorChanges { target: labelsGrid anchors.horizontalCenter: contentItem.horizontalCenter } PropertyChanges { target: timeLabel height: sizehelper.height width: sizehelper.contentWidth font.pixelSize: timeLabel.height } PropertyChanges { target: timezoneLabel height: main.showDate ? 0.7 * timeLabel.height : 0.8 * timeLabel.height width: main.showDate ? timezoneLabel.paintedWidth : timeLabel.width font.pixelSize: timezoneLabel.height } PropertyChanges { target: dateLabel height: 0.8 * timeLabel.height width: dateLabel.paintedWidth font.pixelSize: dateLabel.height } AnchorChanges { target: dateLabel anchors.top: labelsGrid.bottom anchors.horizontalCenter: labelsGrid.horizontalCenter } PropertyChanges { target: sizehelper /* * The value 0.71 was picked by testing to give the clock the right * size (aligned with tray icons). * Value 0.56 seems to be chosen rather arbitrary as well such that * the time label is slightly larger than the date or timezone label * and still fits well into the panel with all the applied margins. */ height: Math.min(main.showDate || timezoneLabel.visible ? main.height * 0.56 : main.height * 0.71, 3 * theme.defaultFont.pixelSize) font.pixelSize: sizehelper.height } }, State { name: "horizontalPanelSmall" when: plasmoid.formFactor === PlasmaCore.Types.Horizontal && main.oneLineMode PropertyChanges { target: main Layout.fillHeight: true Layout.fillWidth: false Layout.minimumWidth: contentItem.width Layout.maximumWidth: Layout.minimumWidth } PropertyChanges { target: contentItem height: sizehelper.height width: dateLabel.width + dateLabel.anchors.rightMargin + labelsGrid.width } AnchorChanges { target: labelsGrid anchors.right: contentItem.right } PropertyChanges { target: dateLabel height: timeLabel.height width: dateLabel.paintedWidth anchors.rightMargin: labelsGrid.columnSpacing fontSizeMode: Text.VerticalFit } AnchorChanges { target: dateLabel anchors.right: labelsGrid.left anchors.verticalCenter: labelsGrid.verticalCenter } PropertyChanges { target: timeLabel height: sizehelper.height width: sizehelper.contentWidth fontSizeMode: Text.VerticalFit } PropertyChanges { target: timezoneLabel height: 0.7 * timeLabel.height width: timezoneLabel.paintedWidth fontSizeMode: Text.VerticalFit horizontalAlignment: Text.AlignHCenter } PropertyChanges { target: sizehelper height: Math.min(main.height, 3 * theme.defaultFont.pixelSize) fontSizeMode: Text.VerticalFit font.pixelSize: 3 * theme.defaultFont.pixelSize } }, State { name: "verticalPanel" when: plasmoid.formFactor === PlasmaCore.Types.Vertical PropertyChanges { target: main Layout.fillHeight: false Layout.fillWidth: true Layout.maximumHeight: contentItem.height Layout.minimumHeight: Layout.maximumHeight } PropertyChanges { target: contentItem height: main.showDate ? labelsGrid.height + dateLabel.height : labelsGrid.height width: main.width } PropertyChanges { target: labelsGrid rows: 2 } PropertyChanges { target: timeLabel height: sizehelper.contentHeight width: main.width font.pixelSize: Math.min(timeLabel.height, 3 * theme.defaultFont.pixelSize) fontSizeMode: Text.HorizontalFit } PropertyChanges { target: timezoneLabel height: Math.max(0.7 * timeLabel.height, minimumPixelSize) width: main.width fontSizeMode: Text.Fit minimumPixelSize: dateLabel.minimumPixelSize elide: Text.ElideRight } PropertyChanges { target: dateLabel // this can be marginal bigger than contentHeight because of the horizontal fit height: sizehelper.contentHeight width: main.width fontSizeMode: Text.Fit minimumPixelSize: Math.min(0.7 * theme.smallestFont.pixelSize, timeLabel.height) elide: Text.ElideRight } AnchorChanges { target: dateLabel anchors.top: labelsGrid.bottom anchors.horizontalCenter: labelsGrid.horizontalCenter } PropertyChanges { target: sizehelper width: main.width fontSizeMode: Text.HorizontalFit font.pixelSize: 3 * theme.defaultFont.pixelSize } }, State { name: "other" when: plasmoid.formFactor !== PlasmaCore.Types.Vertical && plasmoid.formFactor !== PlasmaCore.Types.Horizontal PropertyChanges { target: main Layout.fillHeight: false Layout.fillWidth: false Layout.minimumWidth: units.gridUnit * 3 Layout.minimumHeight: units.gridUnit * 3 } PropertyChanges { target: contentItem height: main.height width: main.width } PropertyChanges { target: labelsGrid rows: 2 } PropertyChanges { target: timeLabel height: sizehelper.height width: main.width fontSizeMode: Text.Fit } PropertyChanges { target: timezoneLabel height: 0.7 * timeLabel.height width: main.width fontSizeMode: Text.Fit minimumPixelSize: 1 } PropertyChanges { target: dateLabel height: 0.8 * timeLabel.height width: Math.max(timeLabel.contentWidth, units.gridUnit * 3) fontSizeMode: Text.Fit minimumPixelSize: 1 } AnchorChanges { target: dateLabel anchors.top: labelsGrid.bottom anchors.horizontalCenter: labelsGrid.horizontalCenter } PropertyChanges { target: sizehelper height: { if (main.showDate) { if (timezoneLabel.visible) { return 0.4 * main.height } return 0.56 * main.height } else if (timezoneLabel.visible) { return 0.59 * main.height } return main.height } width: main.width fontSizeMode: Text.Fit font.pixelSize: 1024 } } ] MouseArea { id: mouseArea property int wheelDelta: 0 anchors.fill: parent onClicked: plasmoid.expanded = !plasmoid.expanded onWheel: { if (!plasmoid.configuration.wheelChangesTimezone) { return; } var delta = wheel.angleDelta.y || wheel.angleDelta.x var newIndex = main.tzIndex; wheelDelta += delta; // magic number 120 for common "one click" - // See: http://qt-project.org/doc/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop + // See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop while (wheelDelta >= 120) { wheelDelta -= 120; newIndex--; } while (wheelDelta <= -120) { wheelDelta += 120; newIndex++; } if (newIndex >= plasmoid.configuration.selectedTimeZones.length) { newIndex = 0; } else if (newIndex < 0) { newIndex = plasmoid.configuration.selectedTimeZones.length - 1; } if (newIndex !== main.tzIndex) { plasmoid.configuration.lastSelectedTimezone = plasmoid.configuration.selectedTimeZones[newIndex]; main.tzIndex = newIndex; dataSource.dataChanged(); setupLabels(); } } } /* * Visible elements * */ Item { id: contentItem anchors.verticalCenter: main.verticalCenter Grid { id: labelsGrid rows: 1 horizontalItemAlignment: Grid.AlignHCenter verticalItemAlignment: Grid.AlignVCenter flow: Grid.TopToBottom columnSpacing: units.smallSpacing Rectangle { height: 0.8 * sizehelper.height width: 1 visible: main.showDate && main.oneLineMode color: theme.textColor opacity: 0.4 } Components.Label { id: timeLabel font { family: plasmoid.configuration.fontFamily || theme.defaultFont.family weight: plasmoid.configuration.boldText ? Font.Bold : theme.defaultFont.weight italic: plasmoid.configuration.italicText pixelSize: 1024 } minimumPixelSize: 1 text: { // get the time for the given timezone from the dataengine var now = dataSource.data[plasmoid.configuration.lastSelectedTimezone]["DateTime"]; // get current UTC time var msUTC = now.getTime() + (now.getTimezoneOffset() * 60000); // add the dataengine TZ offset to it var currentTime = new Date(msUTC + (dataSource.data[plasmoid.configuration.lastSelectedTimezone]["Offset"] * 1000)); main.currentTime = currentTime; return Qt.formatTime(currentTime, main.timeFormat); } verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } Components.Label { id: timezoneLabel font.weight: timeLabel.font.weight font.italic: timeLabel.font.italic font.pixelSize: 1024 minimumPixelSize: 1 visible: text.length > 0 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Components.Label { id: dateLabel visible: main.showDate font.family: timeLabel.font.family font.weight: timeLabel.font.weight font.italic: timeLabel.font.italic font.pixelSize: 1024 minimumPixelSize: 1 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } /* * end: Visible Elements * */ Components.Label { id: sizehelper font.family: timeLabel.font.family font.weight: timeLabel.font.weight font.italic: timeLabel.font.italic minimumPixelSize: 1 visible: false } FontMetrics { id: timeMetrics font.family: timeLabel.font.family font.weight: timeLabel.font.weight font.italic: timeLabel.font.italic } // Qt's QLocale does not offer any modular time creating like Klocale did // eg. no "gimme time with seconds" or "gimme time without seconds and with timezone". // QLocale supports only two formats - Long and Short. Long is unusable in many situations // and Short does not provide seconds. So if seconds are enabled, we need to add it here. // // What happens here is that it looks for the delimiter between "h" and "m", takes it // and appends it after "mm" and then appends "ss" for the seconds. function timeFormatCorrection(timeFormatString) { var regexp = /(hh*)(.+)(mm)/i var match = regexp.exec(timeFormatString); var hours = match[1]; var delimiter = match[2]; var minutes = match[3] var seconds = "ss"; var amPm = "AP"; var uses24hFormatByDefault = timeFormatString.toLowerCase().indexOf("ap") === -1; // because QLocale is incredibly stupid and does not convert 12h/24h clock format // when uppercase H is used for hours, needs to be h or hh, so toLowerCase() var result = hours.toLowerCase() + delimiter + minutes; if (main.showSeconds) { result += delimiter + seconds; } // add "AM/PM" either if the setting is the default and locale uses it OR if the user unchecked "use 24h format" if ((main.use24hFormat == Qt.PartiallyChecked && !uses24hFormatByDefault) || main.use24hFormat == Qt.Unchecked) { result += " " + amPm; } main.timeFormat = result; setupLabels(); } function setupLabels() { var showTimezone = main.showLocalTimezone || (plasmoid.configuration.lastSelectedTimezone !== "Local" && dataSource.data["Local"]["Timezone City"] !== dataSource.data[plasmoid.configuration.lastSelectedTimezone]["Timezone City"]); var timezoneString = ""; if (showTimezone) { timezoneString = plasmoid.configuration.displayTimezoneAsCode ? dataSource.data[plasmoid.configuration.lastSelectedTimezone]["Timezone Abbreviation"] : TimezonesI18n.i18nCity(dataSource.data[plasmoid.configuration.lastSelectedTimezone]["Timezone City"]); timezoneLabel.text = (main.showDate || main.oneLineMode) && plasmoid.formFactor === PlasmaCore.Types.Horizontal ? "(" + timezoneString + ")" : timezoneString; } else { // this clears the label and that makes it hidden timezoneLabel.text = timezoneString; } if (main.showDate) { dateLabel.text = Qt.formatDate(main.currentTime, main.dateFormat); } else { // clear it so it doesn't take space in the layout dateLabel.text = ""; } // find widest character between 0 and 9 var maximumWidthNumber = 0; var maximumAdvanceWidth = 0; for (var i = 0; i <= 9; i++) { var advanceWidth = timeMetrics.advanceWidth(i); if (advanceWidth > maximumAdvanceWidth) { maximumAdvanceWidth = advanceWidth; maximumWidthNumber = i; } } // replace all placeholders with the widest number (two digits) var format = main.timeFormat.replace(/(h+|m+|s+)/g, "" + maximumWidthNumber + maximumWidthNumber); // make sure maximumWidthNumber is formatted as string // build the time string twice, once with an AM time and once with a PM time var date = new Date(2000, 0, 1, 1, 0, 0); var timeAm = Qt.formatTime(date, format); var advanceWidthAm = timeMetrics.advanceWidth(timeAm); date.setHours(13); var timePm = Qt.formatTime(date, format); var advanceWidthPm = timeMetrics.advanceWidth(timePm); // set the sizehelper's text to the widest time string if (advanceWidthAm > advanceWidthPm) { sizehelper.text = timeAm; } else { sizehelper.text = timePm; } } function dateTimeChanged() { var doCorrections = false; if (main.showDate) { // If the date has changed, force size recalculation, because the day name // or the month name can now be longer/shorter, so we need to adjust applet size var currentDate = Qt.formatDateTime(dataSource.data["Local"]["DateTime"], "yyyy-mm-dd"); if (main.lastDate !== currentDate) { doCorrections = true; main.lastDate = currentDate } } var currentTZOffset = dataSource.data["Local"]["Offset"] / 60; if (currentTZOffset !== tzOffset) { doCorrections = true; tzOffset = currentTZOffset; Date.timeZoneUpdated(); // inform the QML JS engine about TZ change } if (doCorrections) { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)); } } function setTimezoneIndex() { for (var i = 0; i < plasmoid.configuration.selectedTimeZones.length; i++) { if (plasmoid.configuration.selectedTimeZones[i] === plasmoid.configuration.lastSelectedTimezone) { main.tzIndex = i; break; } } } Component.onCompleted: { // Sort the timezones according to their offset // Calling sort() directly on plasmoid.configuration.selectedTimeZones // has no effect, so sort a copy and then assign the copy to it var sortArray = plasmoid.configuration.selectedTimeZones; sortArray.sort(function(a, b) { return dataSource.data[a]["Offset"] - dataSource.data[b]["Offset"]; }); plasmoid.configuration.selectedTimeZones = sortArray; setTimezoneIndex(); tzOffset = -(new Date().getTimezoneOffset()); dateTimeChanged(); timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)); dataSource.onDataChanged.connect(dateTimeChanged); } } diff --git a/applets/digital-clock/package/contents/ui/configAppearance.qml b/applets/digital-clock/package/contents/ui/configAppearance.qml index 2f39ddfa3..941077df0 100644 --- a/applets/digital-clock/package/contents/ui/configAppearance.qml +++ b/applets/digital-clock/package/contents/ui/configAppearance.qml @@ -1,274 +1,274 @@ /* * Copyright 2013 Bhushan Shah * Copyright 2013 Sebastian Kügler * Copyright 2015 Kai Uwe Broulik * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see */ import QtQuick 2.0 import QtQuick.Controls 2.3 as QtControls import QtQuick.Layouts 1.0 as QtLayouts import org.kde.plasma.calendar 2.0 as PlasmaCalendar import org.kde.kquickcontrolsaddons 2.0 import org.kde.kirigami 2.5 as Kirigami QtLayouts.ColumnLayout { id: appearancePage signal configurationChanged property string cfg_fontFamily property alias cfg_boldText: boldCheckBox.checked property string cfg_timeFormat: "" property alias cfg_italicText: italicCheckBox.checked property alias cfg_showLocalTimezone: showLocalTimezone.checked property alias cfg_displayTimezoneAsCode: timezoneCodeRadio.checked property alias cfg_showSeconds: showSeconds.checked property alias cfg_showDate: showDate.checked property string cfg_dateFormat: "shortDate" property alias cfg_customDateFormat: customDateFormat.text property alias cfg_use24hFormat: use24hFormat.currentIndex onCfg_fontFamilyChanged: { // HACK by the time we populate our model and/or the ComboBox is finished the value is still undefined if (cfg_fontFamily) { for (var i = 0, j = fontsModel.count; i < j; ++i) { if (fontsModel.get(i).value === cfg_fontFamily) { fontFamilyComboBox.currentIndex = i break } } } } ListModel { id: fontsModel Component.onCompleted: { var arr = [] // use temp array to avoid constant binding stuff arr.push({text: i18nc("Use default font", "Default"), value: ""}) var fonts = Qt.fontFamilies() var foundIndex = 0 for (var i = 0, j = fonts.length; i < j; ++i) { arr.push({text: fonts[i], value: fonts[i]}) } append(arr) } } Kirigami.FormLayout { QtLayouts.Layout.fillWidth: true QtControls.CheckBox { id: showDate Kirigami.FormData.label: i18n("Information:") text: i18n("Show date") } QtControls.CheckBox { id: showSeconds text: i18n("Show seconds") } QtControls.CheckBox { id: showLocalTimezone text: i18n("Show local time zone") } Item { Kirigami.FormData.isSection: true } QtLayouts.ColumnLayout { Kirigami.FormData.label: i18n("Display time zone as:") Kirigami.FormData.buddyFor: timezoneCityRadio QtControls.RadioButton { id: timezoneCityRadio text: i18n("Time zone city") } QtControls.RadioButton { id: timezoneCodeRadio text: i18n("Time zone code") } } Item { Kirigami.FormData.isSection: true } QtLayouts.RowLayout { QtLayouts.Layout.fillWidth: true Kirigami.FormData.label: i18n("Time display:") QtControls.ComboBox { id: use24hFormat model: [ i18n("12-Hour"), i18n("Use Region Defaults"), i18n("24-Hour") ] onCurrentIndexChanged: cfg_use24hFormat = currentIndex } QtControls.Button { visible: KCMShell.authorize("formats.desktop").length > 0 text: i18n("Change Regional Settings...") icon.name: "preferences-desktop-locale" onClicked: KCMShell.open("formats.desktop") } } Item { Kirigami.FormData.isSection: true } QtLayouts.RowLayout { Kirigami.FormData.label: i18n("Date format:") enabled: showDate.checked QtControls.ComboBox { id: dateFormat textRole: "label" model: [ { 'label': i18n("Long Date"), 'name': "longDate", format: Qt.SystemLocaleLongDate }, { 'label': i18n("Short Date"), 'name': "shortDate", format: Qt.SystemLocaleShortDate }, { 'label': i18n("ISO Date"), 'name': "isoDate", format: Qt.ISODate }, { 'label': i18nc("custom date format", "Custom"), 'name': "custom" } ] onCurrentIndexChanged: cfg_dateFormat = model[currentIndex]["name"] Component.onCompleted: { for (var i = 0; i < model.length; i++) { if (model[i]["name"] === plasmoid.configuration.dateFormat) { dateFormat.currentIndex = i; } } } } QtControls.Label { QtLayouts.Layout.fillWidth: true textFormat: Text.PlainText text: Qt.formatDate(new Date(), cfg_dateFormat === "custom" ? customDateFormat.text : dateFormat.model[dateFormat.currentIndex].format) } } QtControls.TextField { id: customDateFormat QtLayouts.Layout.fillWidth: true enabled: showDate.checked visible: cfg_dateFormat == "custom" } QtControls.Label { - text: i18n("Time Format Documentation") + text: i18n("Time Format Documentation") enabled: showDate.checked visible: cfg_dateFormat == "custom" wrapMode: Text.Wrap QtLayouts.Layout.preferredWidth: QtLayouts.Layout.maximumWidth QtLayouts.Layout.maximumWidth: units.gridUnit * 16 onLinkActivated: Qt.openUrlExternally(link) MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton // We don't want to eat clicks on the Label cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } } Item { Kirigami.FormData.isSection: true } QtLayouts.RowLayout { QtLayouts.Layout.fillWidth: true Kirigami.FormData.label: i18n("Font style:") QtControls.ComboBox { id: fontFamilyComboBox QtLayouts.Layout.fillWidth: true currentIndex: 0 // ComboBox's sizing is just utterly broken QtLayouts.Layout.minimumWidth: units.gridUnit * 10 model: fontsModel // doesn't autodeduce from model because we manually populate it textRole: "text" onCurrentIndexChanged: { var current = model.get(currentIndex) if (current) { cfg_fontFamily = current.value appearancePage.configurationChanged() } } } QtControls.Button { id: boldCheckBox QtControls.ToolTip { text: i18n("Bold text") } icon.name: "format-text-bold" checkable: true Accessible.name: QtControls.ToolTip.text } QtControls.Button { id: italicCheckBox QtControls.ToolTip { text: i18n("Italic text") } icon.name: "format-text-italic" checkable: true Accessible.name: QtControls.ToolTip.text } } } Item { QtLayouts.Layout.fillHeight: true } Component.onCompleted: { if (plasmoid.configuration.displayTimezoneAsCode) { timezoneCodeRadio.checked = true; } else { timezoneCityRadio.checked = true; } } } diff --git a/applets/digital-clock/plugin/CMakeLists.txt b/applets/digital-clock/plugin/CMakeLists.txt index 6e6b25e4b..44cfa6830 100644 --- a/applets/digital-clock/plugin/CMakeLists.txt +++ b/applets/digital-clock/plugin/CMakeLists.txt @@ -1,26 +1,26 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.digitalclock\") find_package(IsoCodes) set_package_properties(IsoCodes PROPERTIES DESCRIPTION "ISO language, territory, currency, script codes and their translations" - URL "http://pkg-isocodes.alioth.debian.org/" + URL "https://salsa.debian.org/iso-codes-team/iso-codes" PURPOSE "Translation of country names in digital clock applet" TYPE RUNTIME ) set(digitalclockplugin_SRCS timezonemodel.cpp timezonesi18n.cpp digitalclockplugin.cpp clipboardmenu.cpp ) add_library(digitalclockplugin SHARED ${digitalclockplugin_SRCS}) target_link_libraries(digitalclockplugin Qt5::Core Qt5::Qml Qt5::Widgets # for QAction... KF5::CoreAddons KF5::I18n) install(TARGETS digitalclockplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/digitalclock) install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/private/digitalclock) diff --git a/applets/icon/iconapplet.cpp b/applets/icon/iconapplet.cpp index dec37e37c..59a0abe6e 100644 --- a/applets/icon/iconapplet.cpp +++ b/applets/icon/iconapplet.cpp @@ -1,579 +1,579 @@ /* * Copyright 2016 Kai Uwe Broulik * * 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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, see . * */ #include "iconapplet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IconApplet::IconApplet(QObject *parent, const QVariantList &data) : Plasma::Applet(parent, data) { } IconApplet::~IconApplet() { // in a handler connected to IconApplet::appletDeleted m_localPath will be empty?! if (destroyed()) { QFile::remove(m_localPath); } } void IconApplet::init() { populate(); } void IconApplet::configChanged() { populate(); } void IconApplet::populate() { m_url = config().readEntry(QStringLiteral("url"), QUrl()); if (!m_url.isValid()) { // the old applet that used a QML plugin and stored its url // in plasmoid.configuration.url had its entries stored in [Configuration][General] // so we look here as well to provide an upgrade path m_url = config().group("General").readEntry(QStringLiteral("url"), QUrl()); } // our backing desktop file already exists? just read all the things from it const QString path = localPath(); if (QFileInfo::exists(path)) { populateFromDesktopFile(path); return; } if (!m_url.isValid()) { // invalid url, use dummy data populateFromDesktopFile(QString()); return; } const QString plasmaIconsFolderPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/plasma_icons"); if (!QDir().mkpath(plasmaIconsFolderPath)) { setLaunchErrorMessage(i18n("Failed to create icon widgets folder '%1'", plasmaIconsFolderPath)); return; } setBusy(true); // unset in populateFromDesktopFile where we'll end up in if all goes well auto *statJob = KIO::stat(m_url, KIO::HideProgressInfo); connect(statJob, &KIO::StatJob::finished, this, [=] { QString desiredDesktopFileName = m_url.fileName(); - // in doubt, just encode the entire URL, e.g. http://www.kde.org/ has no filename + // in doubt, just encode the entire URL, e.g. https://www.kde.org/ has no filename if (desiredDesktopFileName.isEmpty()) { desiredDesktopFileName = KIO::encodeFileName(m_url.toDisplayString()); } // We always want it to be a .desktop file (e.g. also for the "Type=Link" at the end) if (!desiredDesktopFileName.endsWith(QLatin1String(".desktop"))) { desiredDesktopFileName.append(QLatin1String(".desktop")); } QString backingDesktopFile = plasmaIconsFolderPath + QLatin1Char('/'); // KFileUtils::suggestName always appends a suffix, i.e. it expects that we already know the file already exists if (QFileInfo::exists(backingDesktopFile + desiredDesktopFileName)) { desiredDesktopFileName = KFileUtils::suggestName(QUrl::fromLocalFile(plasmaIconsFolderPath), desiredDesktopFileName); } backingDesktopFile.append(desiredDesktopFileName); QString name; // ends up as "Name" in the .desktop file for "Link" files below const QUrl url = statJob->mostLocalUrl(); if (url.isLocalFile()) { const QString localUrlString = url.toLocalFile(); // if desktop file just copy it over if (KDesktopFile::isDesktopFile(localUrlString)) { // if this restriction is set, KIO won't allow running desktop files from outside // registered services, applications, and so on, in this case we'll use the original // .desktop file and lose the ability to customize it if (!KAuthorized::authorize(QStringLiteral("run_desktop_files"))) { populateFromDesktopFile(localUrlString); // we don't call setLocalPath here as we don't want to store localPath to be a system-location // so that the fact that we cannot edit is re-evaluated every time return; } if (!QFile::copy(localUrlString, backingDesktopFile)) { setLaunchErrorMessage(i18n("Failed to copy icon widget desktop file from '%1' to '%2'", localUrlString, backingDesktopFile)); setBusy(false); return; } // set executable flag on the desktop file so KIO doesn't complain about executing it QFile file(backingDesktopFile); file.setPermissions(file.permissions() | QFile::ExeOwner); populateFromDesktopFile(backingDesktopFile); setLocalPath(backingDesktopFile); return; } } // in all other cases just make it a link QString iconName; QString genericName; if (!statJob->error()) { KFileItem item(statJob->statResult(), url); if (name.isEmpty()) { name = item.text(); } if (item.mimetype() != QLatin1String("application/octet-stream")) { iconName = item.iconName(); genericName = item.mimeComment(); } } // KFileItem might return "." as text for e.g. root folders if (name == QLatin1Char('.')) { name.clear(); } if (name.isEmpty()) { name = url.fileName(); } if (name.isEmpty()) { // TODO would be cool to just show the parent folder name instead of the full path name = url.path(); } // For websites the filename e.g. "index.php" is usually not what you want // also "/" isn't very descript when it's not our local "root" folder if (name.isEmpty() || url.scheme().startsWith(QLatin1String("http")) || (!url.isLocalFile() && name == QLatin1String("/"))) { name = url.host(); } if (iconName.isEmpty()) { // In doubt ask KIO::iconNameForUrl, KFileItem can't cope with http:// URLs for instance iconName = KIO::iconNameForUrl(url); } bool downloadFavIcon = false; if (url.scheme().startsWith(QLatin1String("http"))) { const QString favIcon = KIO::favIconForUrl(url); if (!favIcon.isEmpty()) { iconName = favIcon; } else { downloadFavIcon = true; } } KDesktopFile linkDesktopFile(backingDesktopFile); auto desktopGroup = linkDesktopFile.desktopGroup(); desktopGroup.writeEntry(QStringLiteral("Name"), name); desktopGroup.writeEntry(QStringLiteral("Type"), QStringLiteral("Link")); desktopGroup.writeEntry(QStringLiteral("URL"), url); desktopGroup.writeEntry(QStringLiteral("Icon"), iconName); if (!genericName.isEmpty()) { desktopGroup.writeEntry(QStringLiteral("GenericName"), genericName); } linkDesktopFile.sync(); populateFromDesktopFile(backingDesktopFile); setLocalPath(backingDesktopFile); if (downloadFavIcon) { KIO::FavIconRequestJob *job = new KIO::FavIconRequestJob(m_url); connect(job, &KIO::FavIconRequestJob::result, this, [job, backingDesktopFile, this](KJob *){ if (!job->error()) { KDesktopFile(backingDesktopFile).desktopGroup().writeEntry(QStringLiteral("Icon"), job->iconFile()); m_iconName = job->iconFile(); emit iconNameChanged(m_iconName); } }); } }); } void IconApplet::populateFromDesktopFile(const QString &path) { // path empty? just set icon to "unknown" and call it a day if (path.isEmpty()) { setIconName({}); return; } KDesktopFile desktopFile(path); const QString &name = desktopFile.readName(); if (m_name != name) { m_name = name; emit nameChanged(name); } const QString &genericName = desktopFile.readGenericName(); if (m_genericName != genericName) { m_genericName = genericName; emit genericNameChanged(genericName); } setIconName(desktopFile.readIcon()); delete m_openContainingFolderAction; m_openContainingFolderAction = nullptr; m_openWithActions.clear(); m_jumpListActions.clear(); m_localPath = path; setBusy(false); } QUrl IconApplet::url() const { return m_url; } void IconApplet::setUrl(const QUrl &url) { if (m_url != url) { m_url = url; urlChanged(url); config().writeEntry(QStringLiteral("url"), url); populate(); } } void IconApplet::setIconName(const QString &iconName) { const QString newIconName = (!iconName.isEmpty() ? iconName : QStringLiteral("unknown")); if (m_iconName != newIconName) { m_iconName = newIconName; emit iconNameChanged(newIconName); } } QString IconApplet::name() const { return m_name; } QString IconApplet::iconName() const { return m_iconName; } QString IconApplet::genericName() const { return m_genericName; } QList IconApplet::contextualActions() { QList actions; if (m_localPath.isEmpty()) { return actions; } KDesktopFile desktopFile(m_localPath); if (m_jumpListActions.isEmpty()) { const QStringList actions = desktopFile.readActions(); for (const QString &actionName : actions) { const KConfigGroup &actionGroup = desktopFile.actionGroup(actionName); if (!actionGroup.isValid() || !actionGroup.exists()) { continue; } const QString name = actionGroup.readEntry(QStringLiteral("Name")); const QString exec = actionGroup.readEntry(QStringLiteral("Exec")); if (name.isEmpty() || exec.isEmpty()) { continue; } QAction *action = new QAction(QIcon::fromTheme(actionGroup.readEntry("Icon")), name, this); connect(action, &QAction::triggered, this, [this, exec] { KRun::run(exec, {}, nullptr, m_name, m_iconName); }); m_jumpListActions << action; } } actions << m_jumpListActions; if (!actions.isEmpty()) { if (!m_separatorAction) { m_separatorAction = new QAction(this); m_separatorAction->setSeparator(true); } actions << m_separatorAction; } if (desktopFile.hasLinkType()) { const QUrl linkUrl = QUrl(desktopFile.readUrl()); if (m_openWithActions.isEmpty()) { if (!m_fileItemActions) { m_fileItemActions = new KFileItemActions(this); } KFileItemListProperties itemProperties(KFileItemList({KFileItem(linkUrl)})); m_fileItemActions->setItemListProperties(itemProperties); if (!m_openWithMenu) { m_openWithMenu.reset(new QMenu()); } m_openWithMenu->clear(); m_fileItemActions->addOpenWithActionsTo(m_openWithMenu.data()); m_openWithActions = m_openWithMenu->actions(); } if (!m_openContainingFolderAction) { if (KProtocolManager::supportsListing(linkUrl)) { m_openContainingFolderAction = new QAction(QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("Open Containing Folder"), this); connect(m_openContainingFolderAction, &QAction::triggered, this, [ linkUrl] { KIO::highlightInFileManager({linkUrl}); }); } } } actions << m_openWithActions; if (m_openContainingFolderAction) { actions << m_openContainingFolderAction; } return actions; } void IconApplet::run() { if (!m_startupTasksModel) { m_startupTasksModel = new TaskManager::StartupTasksModel(this); auto handleRow = [this](bool busy, const QModelIndex &parent, int first, int last) { Q_UNUSED(parent); for (int i = first; i <= last; ++i) { const QModelIndex idx = m_startupTasksModel->index(i, 0); if (idx.data(TaskManager::AbstractTasksModel::LauncherUrlWithoutIcon).toUrl() == QUrl::fromLocalFile(m_localPath)) { setBusy(busy); break; } } }; using namespace std::placeholders; connect(m_startupTasksModel, &QAbstractItemModel::rowsInserted, this, std::bind(handleRow, true /*busy*/, _1, _2, _3)); connect(m_startupTasksModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, std::bind(handleRow, false /*busy*/, _1, _2, _3)); } new KRun(QUrl::fromLocalFile(m_localPath), QApplication::desktop()); } void IconApplet::processDrop(QObject *dropEvent) { Q_ASSERT(dropEvent); Q_ASSERT(isAcceptableDrag(dropEvent)); const auto &urls = urlsFromDrop(dropEvent); if (urls.isEmpty()) { return; } const QString &localPath = m_url.toLocalFile(); if (KDesktopFile::isDesktopFile(localPath)) { KRun::runService(KService(localPath), urls, nullptr); return; } QMimeDatabase db; const QMimeType mimeType = db.mimeTypeForUrl(m_url); if (isExecutable(mimeType)) { // isAcceptableDrag has the KAuthorized check for this QProcess::startDetached(m_url.toLocalFile(), QUrl::toStringList(urls)); return; } if (mimeType.inherits(QStringLiteral("inode/directory"))) { QMimeData mimeData; mimeData.setUrls(urls); // DeclarativeDropEvent isn't public QDropEvent de(QPointF(dropEvent->property("x").toInt(), dropEvent->property("y").toInt()), static_cast(dropEvent->property("proposedActions").toInt()), &mimeData, static_cast(dropEvent->property("buttons").toInt()), static_cast(dropEvent->property("modifiers").toInt())); KIO::DropJob *dropJob = KIO::drop(&de, m_url); KJobWidgets::setWindow(dropJob, QApplication::desktop()); return; } } bool IconApplet::isAcceptableDrag(QObject *dropEvent) { Q_ASSERT(dropEvent); const auto &urls = urlsFromDrop(dropEvent); if (urls.isEmpty()) { return false; } const QString &localPath = m_url.toLocalFile(); if (KDesktopFile::isDesktopFile(localPath)) { return true; } QMimeDatabase db; const QMimeType mimeType = db.mimeTypeForUrl(m_url); if (KAuthorized::authorize(QStringLiteral("shell_access")) && isExecutable(mimeType)) { return true; } if (mimeType.inherits(QStringLiteral("inode/directory"))) { return true; } return false; } QList IconApplet::urlsFromDrop(QObject *dropEvent) { // DeclarativeDropEvent and co aren't public const QObject *mimeData = qvariant_cast(dropEvent->property("mimeData")); Q_ASSERT(mimeData); const QJsonArray &droppedUrls = mimeData->property("urls").toJsonArray(); QList urls; urls.reserve(droppedUrls.count()); for (const QJsonValue &droppedUrl : droppedUrls) { const QUrl url(droppedUrl.toString()); if (url.isValid()) { urls.append(url); } } return urls; } bool IconApplet::isExecutable(const QMimeType &mimeType) { return (mimeType.inherits(QStringLiteral("application/x-executable")) || mimeType.inherits(QStringLiteral("application/x-shellscript"))); } void IconApplet::configure() { KPropertiesDialog *dialog = m_configDialog.data(); if (dialog) { dialog->show(); dialog->raise(); return; } dialog = new KPropertiesDialog(QUrl::fromLocalFile(m_localPath)); m_configDialog = dialog; connect(dialog, &KPropertiesDialog::applied, this, [this] { KDesktopFile desktopFile(m_localPath); if (desktopFile.hasLinkType()) { const QUrl newUrl(desktopFile.readUrl()); if (m_url != newUrl) { // make sure to fully repopulate in case the user changed the Link URL QFile::remove(m_localPath); setUrl(newUrl); // calls populate() itself, but only if it changed return; } } populate(); }); dialog->setAttribute(Qt::WA_DeleteOnClose, true); dialog->setFileNameReadOnly(true); dialog->setWindowTitle(i18n("Properties for %1", m_name)); dialog->setWindowIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); dialog->show(); } QString IconApplet::localPath() const { return config().readEntry(QStringLiteral("localPath")); } void IconApplet::setLocalPath(const QString &localPath) { m_localPath = localPath; config().writeEntry(QStringLiteral("localPath"), localPath); } K_EXPORT_PLASMA_APPLET_WITH_JSON(icon, IconApplet, "metadata.json") #include "iconapplet.moc" diff --git a/dataengines/geolocation/CMakeLists.txt b/dataengines/geolocation/CMakeLists.txt index c36f2ccb1..9ebde73af 100644 --- a/dataengines/geolocation/CMakeLists.txt +++ b/dataengines/geolocation/CMakeLists.txt @@ -1,76 +1,76 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.10.0") # CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros. # 3.10+ lets us provide more macro names that require automoc. list(APPEND CMAKE_AUTOMOC_MACRO_NAMES K_EXPORT_PLASMA_GEOLOCATIONPROVIDER) endif() set(plasma_geolocation_interface_SRCS geolocationprovider.cpp) add_library(plasma-geolocation-interface SHARED ${plasma_geolocation_interface_SRCS}) target_link_libraries(plasma-geolocation-interface PUBLIC Qt5::Core Qt5::Network KF5::Plasma PRIVATE KF5::KIOCore ) set_target_properties(plasma-geolocation-interface PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} ) install(TARGETS plasma-geolocation-interface ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES geolocationprovider.h ${CMAKE_CURRENT_BINARY_DIR}/geolocation_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/plasma/geolocation COMPONENT Devel) #install(FILES includes/Interface # DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KDE/Plasma/Geolocation # COMPONENT Devel) # ------------------------------------------------------------------------------------------------- add_library(plasma_engine_geolocation MODULE geolocation.cpp) target_compile_definitions(plasma_engine_geolocation PRIVATE -DQT_NO_KEYWORDS) generate_export_header(plasma_engine_geolocation EXPORT_FILE_NAME "geolocation_export.h" BASE_NAME "GEOLOCATION") target_link_libraries(plasma_engine_geolocation plasma-geolocation-interface KF5::Plasma KF5::CoreAddons KF5::KIOCore KF5::NetworkManagerQt KF5::Service KF5::Solid) kcoreaddons_desktop_to_json(plasma_engine_geolocation plasma-dataengine-geolocation.desktop) install(TARGETS plasma_engine_geolocation DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/dataengine) install(FILES plasma-dataengine-geolocation.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES plasma-geolocationprovider.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) # ------------------------------------------------------------------------------------------------- set(plasma_geolocation_ip_SRCS location_ip.cpp) add_library(plasma-geolocation-ip MODULE ${plasma_geolocation_ip_SRCS}) target_compile_definitions(plasma-geolocation-ip PRIVATE -DQT_NO_KEYWORDS) target_link_libraries(plasma-geolocation-ip plasma-geolocation-interface KF5::KIOCore KF5::NetworkManagerQt) install(FILES plasma-geolocation-ip.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(TARGETS plasma-geolocation-ip DESTINATION ${KDE_INSTALL_PLUGINDIR}) # ------------------------------------------------------------------------------------------------- set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) find_package(libgps) set_package_properties(libgps PROPERTIES DESCRIPTION "GPS support for geolocation" - URL "http://gpsd.berlios.de/" + URL "https://www.berlios.de/software/gpsd/" TYPE OPTIONAL ) if(LIBGPS_FOUND) include_directories(${LIBGPS_INCLUDES} ${LIBGPS_INCLUDE_DIR}) set(plasma_geolocation_gps_SRCS location_gps.cpp) add_library(plasma-geolocation-gps MODULE ${plasma_geolocation_gps_SRCS}) target_link_libraries(plasma-geolocation-gps plasma-geolocation-interface ${LIBGPS_LIBRARIES}) install(FILES plasma-geolocation-gps.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(TARGETS plasma-geolocation-gps DESTINATION ${KDE_INSTALL_PLUGINDIR}) endif() # ------------------------------------------------------------------------------------------------- diff --git a/dataengines/geolocation/plasma-dataengine-geolocation.desktop b/dataengines/geolocation/plasma-dataengine-geolocation.desktop index 10dcd4cc3..2c0b2d19c 100644 --- a/dataengines/geolocation/plasma-dataengine-geolocation.desktop +++ b/dataengines/geolocation/plasma-dataengine-geolocation.desktop @@ -1,148 +1,148 @@ [Desktop Entry] Name=Geolocation Name[ar]=الموقع الجغرافي Name[bg]=Геолокация Name[bs]=Geolokacija Name[ca]=Geolocalització Name[ca@valencia]=Geolocalització Name[cs]=Geolokace Name[csb]=Geògrafnô lokalizacëjô Name[da]=Geo-lokalisering Name[de]=Geolokalisierung Name[el]=Γεωτοποθέτηση Name[en_GB]=Geolocation Name[eo]=GeoLokado Name[es]=Geolocalización Name[et]=Geolokatsioon Name[eu]=Geokokapena Name[fi]=Paikkasijainti Name[fr]=Géo-localisation Name[fy]=Geolokaasje Name[ga]=Geolocation Name[gl]=Xeolocalización Name[he]=מציאת מיקום גאוגרפי Name[hr]=Geolociranje Name[hu]=Földrajzi helyzet Name[ia]=Geolocation Name[id]=Geolokasi Name[is]=Hnattstaðsetningar Name[it]=Geolocalizzazione Name[ja]=ジオロケーション Name[kk]=Жердегі орны Name[km]=ទីតាំង​ភូមិសាស្ដ្រ Name[kn]=ಭೂಪ್ರದೇಶ Name[ko]=위치 Name[lt]=Geografinės vietos nustatymas Name[lv]=Ģeolokācija Name[mk]=Геолоцирање Name[ml]=ഭൂസ്ഥാനങ്ങള്‍ Name[mr]=जिओलोकेशन Name[nb]=Geografisk plassering Name[nds]=Eersteden Name[nl]=Geolocatie Name[nn]=Geolocation Name[pa]=ਭੂਗੋਲਿਕ ਟਿਕਾਣਾ Name[pl]=Geolokalizacja Name[pt]=Geo-Localização Name[pt_BR]=Localização geográfica Name[ro]=Geolocație Name[ru]=Местоположение Name[si]=පිහිටුම Name[sk]=Geolokalizácia Name[sl]=Geolokacija Name[sr]=геолокација Name[sr@ijekavian]=геолокација Name[sr@ijekavianlatin]=geolokacija Name[sr@latin]=geolokacija Name[sv]=Geografisk lokalisering Name[tg]=Ҷойгиршавии ҷуғрофӣ Name[th]=การระบุพิกัดตำแหน่ง Name[tr]=Geolocation Name[ug]=جۇغراپىيىلىك ئورۇن Name[uk]=Геопозиціювання Name[vi]=Vị trí địa lý Name[wa]=Djeyoplaeçmint Name[x-test]=xxGeolocationxx Name[zh_CN]=地理位置 Name[zh_TW]=Geolocation Comment=Geolocation Data Engine Comment[ar]=محرّك بيانات الموقع الجغرافي Comment[bg]=Ядро с данни за геолокация Comment[bs]=Datomotor geolokacije Comment[ca]=Motor de dades de geolocalització Comment[ca@valencia]=Motor de dades de geolocalització Comment[cs]=Datový nástroj geolokace Comment[csb]=Czérownik pòdôwków geògrafny lokalizacëji Comment[da]=Datamotor til geo-lokalisering Comment[de]=Geolokalisierungs-Datentreiber Comment[el]=Μηχανή δεδομένων γεωτοποθέτησης Comment[en_GB]=Geolocation Data Engine Comment[eo]=Datuma motoro de GeoLokado Comment[es]=Motor de datos de geolocalización Comment[et]=Geolokatsiooni andmete mootor Comment[eu]=Geokokapen datuen motorra Comment[fi]=Paikkasijaintidatakone Comment[fr]=Moteur de données de géo-localisation Comment[fy]=Geolokaasje gegevens motor Comment[ga]=Inneall Sonraí Geolocation Comment[gl]=Motor de datos de xeolocalización Comment[he]=מנוע תוכן מציאת מיקום גאוגרפי Comment[hr]=Podatkovni mehanizam za geolociranje Comment[hu]=Kezelőmodul a földrajzi helyzet kiírásához Comment[ia]=Motor de datos de geolocation Comment[id]=Mesin Data Geolokasi Comment[is]=Gagnavél fyrir hnattstaðsetningu Comment[it]=Motore di dati per la geolocalizzazione Comment[ja]=ジオロケーション用データエンジン Comment[kk]=Жердегі орын туралы деректер тетігі Comment[km]=ម៉ាស៊ីន​ទិន្នន័យ​ Geolocation Comment[kn]=ಭೂಪ್ರದೇಶ ದತ್ತ ಯಂತ್ರ Comment[ko]=위치 데이터 엔진 Comment[lt]=Geografinės vietos nustatymo duomenų variklis Comment[lv]=Ģeolokācijas datu dzinējs Comment[mai]=भूअवस्थिति डाटा इंजिन Comment[mk]=Машина за податоци за геолоцирање Comment[ml]=ഭൂസ്ഥാനങ്ങള്‍ക്കുള്ള ഡേറ്റാ എഞ്ചിന്‍ Comment[mr]=जिओलोकेशन डेटा इंजिन Comment[nb]=Datamotor for geografisk plassering Comment[nds]=Eersteden-Datenkarn Comment[nl]=Geolocatie gegevensengine Comment[nn]=Geolocation-datamotor Comment[pa]=ਭੂਗੋਲਿਕ-ਟਿਕਾਣਾ ਡਾਟਾ ਇੰਜਣ Comment[pl]=Silnik danych geolokalizacji Comment[pt]=Motor de Dados de Geo-Localização Comment[pt_BR]=Mecanismo de dados de localização geográfica Comment[ro]=Motor de date Geolocație Comment[ru]=Источник данных о местоположении Comment[si]=භූපිහිටුම් දත්ත එන්ජිම Comment[sk]=Dátový nástroj geolokalizácie Comment[sl]=Podatkovni pogon s podatki o geolokaciji Comment[sr]=Датомотор геолокације Comment[sr@ijekavian]=Датомотор геолокације Comment[sr@ijekavianlatin]=Datomotor geolokacije Comment[sr@latin]=Datomotor geolokacije Comment[sv]=Datagränssnitt för geografisk lokalisering Comment[tg]=Низоми иттилоотии ҷойгиршавӣ ҷуғрофӣ Comment[th]=กลไกข้อมูลการระบุพิกัดตำแหน่ง Comment[tr]=Geolocation Veri Motoru Comment[ug]=جۇغراپىيىلىك ئورۇن سانلىق-مەلۇمات ماتورى Comment[uk]=Рушій даних геопозиціювання Comment[vi]=Cơ chế dữ liệu vị trí địa lý Comment[wa]=Éndjin di dnêyes di djeyoplaeçmint Comment[x-test]=xxGeolocation Data Enginexx Comment[zh_CN]=地理位置数据引擎 Comment[zh_TW]=Geolocation 資料引擎 Icon=applications-internet Type=Service X-KDE-ServiceTypes=Plasma/DataEngine X-KDE-Library=plasma_engine_geolocation X-KDE-PluginInfo-Author=Petri Damstén X-KDE-PluginInfo-Email=damu@iki.fi X-KDE-PluginInfo-Name=geolocation X-KDE-PluginInfo-Version=0.1 -X-KDE-PluginInfo-Website=http://plasma@kde.org +X-KDE-PluginInfo-Website=https://kde.org/plasma-desktop X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= diff --git a/dataengines/time/solarsystem.cpp b/dataengines/time/solarsystem.cpp index 5d5725922..7bc35f152 100644 --- a/dataengines/time/solarsystem.cpp +++ b/dataengines/time/solarsystem.cpp @@ -1,335 +1,335 @@ /* * Copyright (C) 2009 Petri Damsten * * 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, see . */ #include "solarsystem.h" #include #include /* * Mathematics, ideas, public domain code used for these classes from: - * http://www.stjarnhimlen.se/comp/tutorial.html - * http://www.stjarnhimlen.se/comp/riset.html - * http://www.srrb.noaa.gov/highlights/solarrise/azel.html - * http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html - * http://bodmas.org/astronomy/riset.html + * https://www.stjarnhimlen.se/comp/tutorial.html + * https://www.stjarnhimlen.se/comp/riset.html + * https://www.esrl.noaa.gov/gmd/grad/solcalc/azel.html + * https://www.esrl.noaa.gov/gmd/grad/solcalc/sunrise.html + * http://web.archive.org/web/20080309162302/http://bodmas.org/astronomy/riset.html * moontool.c by John Walker * Wikipedia */ Sun::Sun() : SolarSystemObject() { } void Sun::calcForDateTime(const QDateTime& local, int offset) { SolarSystemObject::calcForDateTime(local, offset); N = 0.0; i = 0.0; w = rev(282.9404 + 4.70935E-5 * m_day); a = 1.0; e = rev(0.016709 - 1.151E-9 * m_day); M = rev(356.0470 + 0.9856002585 * m_day); calc(); } void Sun::rotate(double* y, double* z) { *y *= cosd(m_obliquity); *z *= sind(m_obliquity); } Moon::Moon(Sun *sun) : m_sun(sun) { } void Moon::calcForDateTime(const QDateTime& local, int offset) { if (m_sun->dateTime() != local) { m_sun->calcForDateTime(local, offset); } SolarSystemObject::calcForDateTime(local, offset); N = rev(125.1228 - 0.0529538083 * m_day); i = 5.1454; w = rev(318.0634 + 0.1643573223 * m_day); a = 60.2666; e = 0.054900; M = rev(115.3654 + 13.0649929509 * m_day); calc(); } bool Moon::calcPerturbations(double *lo, double *la, double *r) { double Ms = m_sun->meanAnomaly(); double D = L - m_sun->meanLongitude(); double F = L - N; *lo += -1.274 * sind(M - 2 * D) +0.658 * sind(2 * D) -0.186 * sind(Ms) -0.059 * sind(2 * M - 2 * D) -0.057 * sind(M - 2 * D + Ms) +0.053 * sind(M + 2 * D) +0.046 * sind(2 * D - Ms) +0.041 * sind(M - Ms) -0.035 * sind(D) -0.031 * sind(M + Ms) -0.015 * sind(2 * F - 2 * D) +0.011 * sind(M - 4 * D); *la += -0.173 * sind(F - 2 * D) -0.055 * sind(M - F - 2 * D) -0.046 * sind(M + F - 2 * D) +0.033 * sind(F + 2 * D) +0.017 * sind(2 * M + F); *r += -0.58 * cosd(M - 2 * D) -0.46 * cosd(2 * D); return true; } void Moon::topocentricCorrection(double* RA, double* dec) { double HA = rev(siderealTime() - *RA); double gclat = m_latitude - 0.1924 * sind(2 * m_latitude); double rho = 0.99833 + 0.00167 * cosd(2 * m_latitude); double mpar = asind(1 / rad); double g = atand(tand(gclat) / cosd(HA)); *RA -= mpar * rho * cosd(gclat) * sind(HA) / cosd(*dec); *dec -= mpar * rho * sind(gclat) * sind(g - *dec) / sind(g); } double Moon::phase() { return rev(m_eclipticLongitude - m_sun->lambda()); } void Moon::rotate(double* y, double* z) { double t = *y; *y = t * cosd(m_obliquity) - *z * sind(m_obliquity); *z = t * sind(m_obliquity) + *z * cosd(m_obliquity); } void SolarSystemObject::calc() { double x, y, z; double la, r; L = rev(N + w + M); double E0 = 720.0; double E = M + (180.0 / M_PI) * e * sind(M) * (1.0 + e * cosd(M)); for (int j = 0; fabs(E0 - E) > 0.005 && j < 10; ++j) { E0 = E; E = E0 - (E0 - (180.0 / M_PI) * e * sind(E0) - M) / (1 - e * cosd(E0)); } x = a * (cosd(E) - e); y = a * sind(E) * sqrt(1.0 - e * e); r = sqrt(x * x + y * y); double v = rev(atan2d(y, x)); m_lambda = rev(v + w); x = r * (cosd(N) * cosd(m_lambda) - sind(N) * sind(m_lambda) * cosd(i)); y = r * (sind(N) * cosd(m_lambda) + cosd(N) * sind(m_lambda) * cosd(i)); z = r * sind(m_lambda); if (!qFuzzyCompare(i, 0.0)) { z *= sind(i); } toSpherical(x, y, z, &m_eclipticLongitude, &la, &r); if (calcPerturbations(&m_eclipticLongitude, &la, &r)) { toRectangular(m_eclipticLongitude, la, r, &x, &y, &z); } rotate(&y, &z); toSpherical(x, y, z, &RA, &dec, &rad); topocentricCorrection(&RA, &dec); HA = rev(siderealTime() - RA); x = cosd(HA) * cosd(dec) * sind(m_latitude) - sind(dec) * cosd(m_latitude); y = sind(HA) * cosd(dec); z = cosd(HA) * cosd(dec) * cosd(m_latitude) + sind(dec) * sind(m_latitude); m_azimuth = atan2d(y, x) + 180.0; m_altitude = asind(z); } double SolarSystemObject::siderealTime() { double UT = m_utc.time().hour() + m_utc.time().minute() / 60.0 + m_utc.time().second() / 3600.0; double GMST0 = rev(282.9404 + 4.70935E-5 * m_day + 356.0470 + 0.9856002585 * m_day + 180.0); return GMST0 + UT * 15.0 + m_longitude; } void SolarSystemObject::calcForDateTime(const QDateTime& local, int offset) { m_local = local; m_utc = local.addSecs(-offset); m_day = 367 * m_utc.date().year() - (7 * (m_utc.date().year() + ((m_utc.date().month() + 9) / 12))) / 4 + (275 * m_utc.date().month()) / 9 + m_utc.date().day() - 730530; m_day += m_utc.time().hour() / 24.0 + m_utc.time().minute() / (24.0 * 60.0) + m_utc.time().second() / (24.0 * 60.0 * 60.0); m_obliquity = 23.4393 - 3.563E-7 * m_day; } SolarSystemObject::SolarSystemObject() : m_latitude(0.0) , m_longitude(0.0) { } SolarSystemObject::~SolarSystemObject() { } void SolarSystemObject::setPosition(double latitude, double longitude) { m_latitude = latitude; m_longitude = longitude; } double SolarSystemObject::rev(double x) { return x - floor(x / 360.0) * 360.0; } double SolarSystemObject::asind(double x) { return asin(x) * 180.0 / M_PI; } double SolarSystemObject::sind(double x) { return sin(x * M_PI / 180.0); } double SolarSystemObject::cosd(double x) { return cos(x * M_PI / 180.0); } double SolarSystemObject::tand(double x) { return tan(x * M_PI / 180.0); } double SolarSystemObject::atan2d(double y, double x) { return atan2(y, x) * 180.0 / M_PI; } double SolarSystemObject::atand(double x) { return atan(x) * 180.0 / M_PI; } void SolarSystemObject::toRectangular(double lo, double la, double r, double *x, double *y, double *z) { *x = r * cosd(lo) * cosd(la); *y = r * sind(lo) * cosd(la); *z = r * sind(la); } void SolarSystemObject::toSpherical(double x, double y, double z, double *lo, double *la, double *r) { *r = sqrt(x * x + y * y + z * z); *la = asind(z / *r); *lo = rev(atan2d(y, x)); } QPair SolarSystemObject::zeroPoints(QPointF p1, QPointF p2, QPointF p3) { double a = ((p2.y() - p1.y()) * (p1.x() - p3.x()) + (p3.y() - p1.y()) * (p2.x() - p1.x())) / ((p1.x() - p3.x()) * (p2.x() * p2.x() - p1.x() * p1.x()) + (p2.x() - p1.x()) * (p3.x() * p3.x() - p1.x() * p1.x())); double b = ((p2.y() - p1.y()) - a * (p2.x() * p2.x() - p1.x() * p1.x())) / (p2.x() - p1.x()); double c = p1.y() - a * p1.x() * p1.x() - b * p1.x(); double discriminant = b * b - 4.0 * a * c; double z1 = -1.0, z2 = -1.0; if (discriminant >= 0.0) { z1 = (-b + sqrt(discriminant)) / (2 * a); z2 = (-b - sqrt(discriminant)) / (2 * a); } return QPair(z1, z2); } QList< QPair > SolarSystemObject::timesForAngles(const QList& angles, const QDateTime& dt, int offset) { QList altitudes; QDate d = dt.date(); QDateTime local(d, QTime(0, 0)); for (int j = 0; j <= 25; ++j) { calcForDateTime(local, offset); altitudes.append(altitude()); local = local.addSecs(60 * 60); } QList< QPair > result; QTime rise, set; foreach (double angle, angles) { for (int j = 3; j <= 25; j += 2) { QPointF p1((j - 2) * 60 * 60, altitudes[j - 2] - angle); QPointF p2((j - 1) * 60 * 60, altitudes[j - 1] - angle); QPointF p3(j * 60 * 60, altitudes[j] - angle); QPair z = zeroPoints(p1, p2, p3); if (z.first > p1.x() && z.first < p3.x()) { if (p1.y() < 0.0) { rise = QTime(0, 0).addSecs(z.first); } else { set = QTime(0, 0).addSecs(z.first); } } if (z.second > p1.x() && z.second < p3.x()) { if (p3.y() < 0.0) { set = QTime(0, 0).addSecs(z.second); } else { rise = QTime(0, 0).addSecs(z.second); } } } result.append(QPair(QDateTime(d, rise), QDateTime(d, set))); } return result; } double SolarSystemObject::calcElevation() { double refractionCorrection; if (m_altitude > 85.0) { refractionCorrection = 0.0; } else { double te = tand(m_altitude); if (m_altitude > 5.0) { refractionCorrection = 58.1 / te - 0.07 / (te * te * te) + 0.000086 / (te * te * te * te * te); } else if (m_altitude > -0.575) { refractionCorrection = 1735.0 + m_altitude * (-518.2 + m_altitude * (103.4 + m_altitude * (-12.79 + m_altitude * 0.711) ) ); } else { refractionCorrection = -20.774 / te; } refractionCorrection = refractionCorrection / 3600.0; } return m_altitude + refractionCorrection; } diff --git a/dataengines/time/solarsystem.h b/dataengines/time/solarsystem.h index 4e2dbb445..65bc1d554 100644 --- a/dataengines/time/solarsystem.h +++ b/dataengines/time/solarsystem.h @@ -1,128 +1,128 @@ /* * Copyright (C) 2009 Petri Damsten * * 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, see . */ #ifndef SOLARSYSTEM_H #define SOLARSYSTEM_H #include #include #include /* * Mathematics, ideas, public domain code used for these classes from: - * http://www.stjarnhimlen.se/comp/tutorial.html - * http://www.stjarnhimlen.se/comp/riset.html - * http://www.srrb.noaa.gov/highlights/solarrise/azel.html - * http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html - * http://bodmas.org/astronomy/riset.html + * https://www.stjarnhimlen.se/comp/tutorial.html + * https://www.stjarnhimlen.se/comp/riset.html + * https://www.esrl.noaa.gov/gmd/grad/solcalc/azel.html + * https://www.esrl.noaa.gov/gmd/grad/solcalc/sunrise.html + * http://web.archive.org/web/20080309162302/http://bodmas.org/astronomy/riset.html * moontool.c by John Walker * Wikipedia */ class SolarSystemObject { public: SolarSystemObject(); virtual ~SolarSystemObject(); double meanLongitude() const { return L; }; double meanAnomaly() const { return M; }; double siderealTime(); double altitude() const { return m_altitude; }; double azimuth() const { return m_azimuth; }; double calcElevation(); QDateTime dateTime() const { return m_local; }; double lambda() const { return m_lambda; }; double eclipticLongitude() const { return m_eclipticLongitude; }; void setPosition(double latitude, double longitude); virtual void calcForDateTime(const QDateTime& local, int offset); QList< QPair > timesForAngles(const QList& angles, const QDateTime& dt, int offset); protected: void calc(); virtual bool calcPerturbations(double*, double*, double*) { return false; }; virtual void rotate(double*, double*) { }; virtual void topocentricCorrection(double*, double*) { }; inline double rev(double x); inline double asind(double x); inline double sind(double x); inline double cosd(double x); inline double atand(double x); inline double tand(double x); inline double atan2d(double y, double x); void toRectangular(double lo, double la, double r, double *x, double *y, double *z); void toSpherical(double x, double y, double z, double *lo, double *la, double *r); QPair zeroPoints(QPointF p1, QPointF p2, QPointF p3); double N; double i; double w; double a; double e; double M; double m_obliquity; QDateTime m_utc; QDateTime m_local; double m_day; double m_latitude; double m_longitude; double L; double rad; double RA; double dec; double HA; double m_altitude; double m_azimuth; double m_eclipticLongitude; double m_lambda; }; class Sun : public SolarSystemObject { public: Sun(); void calcForDateTime(const QDateTime& local, int offset) override; protected: void rotate(double*, double*) override; }; class Moon : public SolarSystemObject { public: explicit Moon(Sun *sun); ~Moon() override {}; // to not delete the Sun void calcForDateTime(const QDateTime& local, int offset) override; double phase(); protected: bool calcPerturbations(double *RA, double *dec, double *r) override; void rotate(double*, double*) override; void topocentricCorrection(double*, double*) override; private: Sun *m_sun; }; #endif diff --git a/dataengines/weather/plasma-dataengine-weather.desktop b/dataengines/weather/plasma-dataengine-weather.desktop index 449ee8d0a..c69049808 100644 --- a/dataengines/weather/plasma-dataengine-weather.desktop +++ b/dataengines/weather/plasma-dataengine-weather.desktop @@ -1,154 +1,154 @@ [Desktop Entry] Name=Weather Name[ar]=الطقس Name[be@latin]=Nadvorje Name[bg]=Метеорологично време Name[bn]=আবহাওয়া Name[bn_IN]=আবহাওয়া Name[bs]=Vrijeme Name[ca]=Meteorologia Name[ca@valencia]=Meteorologia Name[cs]=Počasí Name[da]=Vejr Name[de]=Wetter Name[el]=Καιρός Name[en_GB]=Weather Name[eo]=Vetero Name[es]=Tiempo meteorológico Name[et]=Ilmateade Name[eu]=Eguraldia Name[fi]=Sää Name[fr]=Météo Name[fy]=It Waar Name[ga]=Aimsir Name[gl]=O tempo Name[gu]=હવામાન Name[he]=מזג אוויר Name[hi]=मौसम Name[hne]=मौसम Name[hr]=Vrijeme Name[hu]=Időjárás Name[ia]=Tempore meteorologic Name[id]=Cuaca Name[is]=Veður Name[it]=Tempo Name[ja]=気象 Name[kk]=Ауа райы Name[km]=អាកាសធាតុ Name[kn]=ಹವಾಮಾನ Name[ko]=날씨 Name[ku]=Hewa Name[lt]=Orai Name[lv]=Laikapstākļi Name[mai]=मौसम Name[mk]=Време Name[ml]=കാലാവസ്ഥ Name[mr]=हवामान Name[nb]=Været Name[nds]=Weder Name[nl]=Het weer Name[nn]=Vêr Name[or]=ପାଣିପାଗ Name[pa]=ਮੌਸਮ Name[pl]=Pogoda Name[pt]=Meteorologia Name[pt_BR]=Meteorologia Name[ro]=Vremea Name[ru]=Погода Name[si]=කාලගුණය Name[sk]=Počasie Name[sl]=Vreme Name[sr]=време Name[sr@ijekavian]=време Name[sr@ijekavianlatin]=vreme Name[sr@latin]=vreme Name[sv]=Väder Name[ta]= Name[te]=వాతావరణము Name[tg]=Обу Ҳаво Name[th]=พยากรณ์อากาศ Name[tr]=Hava Durumu Name[ug]=ھاۋا رايى Name[uk]=Погода Name[wa]=Meteyo Name[x-test]=xxWeatherxx Name[zh_CN]=天气 Name[zh_TW]=天氣 Comment=Weather data from multiple online sources Comment[ar]=بيانات الطقس من عدّة مصادر على الإنترنت Comment[bg]=Данни за метеорологичното време Comment[bs]=Meteorološki podaci iz više izvora na vezi Comment[ca]=Dades meteorològiques de múltiples fonts en línia Comment[ca@valencia]=Dades meteorològiques de múltiples fonts en línia Comment[cs]=Data o počasí z různých online zdrojů Comment[da]=Vejrdata fra flere online-kilder Comment[de]=Wetterdaten aus verschiedenen Online-Quellen Comment[el]=Δεδομένα καιρού από πολλαπλές δικτυακές πηγές Comment[en_GB]=Weather data from multiple online sources Comment[eo]=Veteraj datumoj el diversaj interretaj fontoj Comment[es]=Datos meteorológicos desde múltiples fuentes. Comment[et]=Ilmaandmed mitmest internetiallikast Comment[eu]=Eguraldiari buruzko informazioa hainbat iturritatik Comment[fi]=Säätietoja useasta lähteestä Comment[fr]=Données météorologiques depuis des sources multiples en ligne Comment[fy]=Waar gegevens fan ferskate ynternetboarnen Comment[ga]=Sonraí aimsire ó fhoinsí éagsúla ar líne Comment[gl]=Información meteorolóxica de varias fontes en Internet Comment[he]=מידע על מזג האוויר ממגוון מקורות מקוונים Comment[hi]=मोसम जानकारी अनेक ऑनलाईन स्रोतों से Comment[hr]=Podaci o vremenu iz raznih online izvora Comment[hu]=Időjárás-jelentés több forrásból Comment[ia]=Datos meteorologic ex multiple fontes in linea Comment[id]=Data cuaca dari berbagai sumber online Comment[is]=Veðurgögn frá ýmsum gagnabönkum á netinu Comment[it]=Dati meteorologici da varie fonti in rete Comment[ja]=複数のオンライン情報源からの気象データ Comment[kk]=Түрлі онлайн көздерден алынған ауа-райы Comment[km]=ទិន្នន័យ​អាកាសធាតុ​ពី​ប្រភព​លើបណ្ដាញ​ជា​ច្រើន Comment[kn]=ಅನೇಕ ಆನ್‌ಲೈನ್ ಮೂಲಗಳಿಂದ ಹವಾಮಾನ ಮಾಹಿತಿ Comment[ko]=온라인에서 온 다양한 날씨 데이터 Comment[lt]=Orų duomenys iš įvairių internetinių šaltinių Comment[lv]=Laikapstākļu dati no vairākiem tiešsaistes avotiem Comment[mk]=Метеоролошки податоци од разни интернет-извори Comment[ml]=പല സ്രോതസ്സുകളില്‍നിന്നുമുള്ള കാലാവസ്ഥാ സ്ഥിതിവിവരങ്ങള്‍ Comment[mr]=अनेक ऑनलाइन स्रोतांकडून हवामान माहिती Comment[nb]=Værdata fra mange nettverkskilder Comment[nds]=Wederdaten vun verscheden Tokoppelborns Comment[nl]=Weergegevens voor meervoudige online bronnen Comment[nn]=Vêrdata frå ulike nettkjelder Comment[pa]=ਕਈ ਆਨਲਾਈਨ ਸਰੋਤਾਂ ਤੋਂ ਮੌਸਮ ਡਾਟਾ Comment[pl]=Dane pogodowe z wielu internetowych źródeł Comment[pt]=Dados meteorológicos de várias fontes 'online' Comment[pt_BR]=Dados meteorológicos de múltiplas fontes online Comment[ro]=Date meteorologice din diferite surse online Comment[ru]=Информация о погоде из разных источников в Интернете Comment[si]=විවිධ මාර්‍ගගත මූල වලින් කාලගුණ දත්ත Comment[sk]=Dáta o počasí z rôznych online zdrojov Comment[sl]=Podatki o vremenu iz več spletnih virov Comment[sr]=Метеоролошки подаци из више извора на вези Comment[sr@ijekavian]=Метеоролошки подаци из више извора на вези Comment[sr@ijekavianlatin]=Meteorološki podaci iz više izvora na vezi Comment[sr@latin]=Meteorološki podaci iz više izvora na vezi Comment[sv]=Väderdata från flera olika nättjänster Comment[th]=ข้อมูลพยากรณ์อากาศจากแหล่งข้อมูลออนไลน์ต่าง ๆ Comment[tr]=Birden fazla çevrim içi kaynaktan hava durumu verisi Comment[ug]=توردىكى كۆپ مەنبەدىن كەلگەن ھاۋارايى سانلىق-مەلۇماتى Comment[uk]=Дані щодо погоди з декількох мережевих джерел Comment[wa]=Li meteyo a pårti di sacwants sourdants so fyis Comment[x-test]=xxWeather data from multiple online sourcesxx Comment[zh_CN]=来自多个在线信息源的天气数据 Comment[zh_TW]=不同線上來源的天氣資料 X-KDE-ServiceTypes=Plasma/DataEngine Type=Service Icon=weather-clear X-KDE-Library=plasma_engine_weather X-KDE-PluginInfo-Author=Shawn Starr X-KDE-PluginInfo-Email=shawn.starr@rogers.com X-KDE-PluginInfo-Name=weather X-KDE-PluginInfo-Version=1.0 -X-KDE-PluginInfo-Website=http://www.kde.org +X-KDE-PluginInfo-Website=https://www.kde.org X-KDE-PluginInfo-License=GPLv2+ X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= diff --git a/klipper/CMakeLists.txt b/klipper/CMakeLists.txt index f0474788b..5d400c61c 100644 --- a/klipper/CMakeLists.txt +++ b/klipper/CMakeLists.txt @@ -1,106 +1,106 @@ set(KLIPPER_VERSION_STRING ${PROJECT_VERSION}) add_definitions(-DTRANSLATION_DOMAIN=\"klipper\") add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII") add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) set(libklipper_common_SRCS klipper.cpp urlgrabber.cpp configdialog.cpp history.cpp historyitem.cpp historymodel.cpp historystringitem.cpp klipperpopup.cpp popupproxy.cpp historyimageitem.cpp historyurlitem.cpp actionstreewidget.cpp editactiondialog.cpp clipcommandprocess.cpp ) ecm_qt_declare_logging_category(libklipper_common_SRCS HEADER klipper_debug.h IDENTIFIER KLIPPER_LOG CATEGORY_NAME org.kde.klipper) find_package(KF5Prison ${KF5_MIN_VERSION}) set_package_properties(KF5Prison PROPERTIES DESCRIPTION "Prison library" - URL "http://projects.kde.org/prison" + URL "https://commits.kde.org/prison" TYPE OPTIONAL PURPOSE "Needed to create mobile barcodes from clipboard data" ) set(HAVE_PRISON ${KF5Prison_FOUND}) configure_file(config-klipper.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-klipper.h ) ki18n_wrap_ui(libklipper_common_SRCS generalconfig.ui actionsconfig.ui editactiondialog.ui) kconfig_add_kcfg_files(libklipper_common_SRCS klippersettings.kcfgc) set(klipper_KDEINIT_SRCS ${libklipper_common_SRCS} main.cpp tray.cpp) kf5_add_kdeinit_executable(klipper ${klipper_KDEINIT_SRCS}) target_link_libraries(kdeinit_klipper Qt5::Concurrent KF5::ConfigGui KF5::CoreAddons KF5::DBusAddons KF5::GlobalAccel KF5::KIOWidgets KF5::Notifications KF5::Service KF5::TextWidgets KF5::WindowSystem KF5::WidgetsAddons KF5::XmlGui ${ZLIB_LIBRARY} ) if (X11_FOUND) target_link_libraries(kdeinit_klipper XCB::XCB Qt5::X11Extras) endif() if (HAVE_PRISON) target_link_libraries(kdeinit_klipper KF5::Prison) endif () install(TARGETS kdeinit_klipper ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS klipper ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.klipper.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(PROGRAMS klipper.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) # Plasma Data Engine set(plasma_engine_clipboard_SRCS ${libklipper_common_SRCS} clipboardengine.cpp clipboardservice.cpp clipboardjob.cpp) add_library(plasma_engine_clipboard MODULE ${plasma_engine_clipboard_SRCS}) kcoreaddons_desktop_to_json(plasma_engine_clipboard plasma-dataengine-clipboard.desktop) target_link_libraries(plasma_engine_clipboard Qt5::Concurrent Qt5::DBus Qt5::Widgets # QAction KF5::ConfigGui KF5::CoreAddons # KUrlMimeData KF5::GlobalAccel KF5::KIOWidgets # PreviewJob KF5::Plasma KF5::Notifications KF5::Service KF5::TextWidgets # KTextEdit KF5::WidgetsAddons # KMessageBox KF5::WindowSystem KF5::XmlGui # KActionCollection ${ZLIB_LIBRARY} ) if (X11_FOUND) target_link_libraries(plasma_engine_clipboard XCB::XCB Qt5::X11Extras) endif() if (HAVE_PRISON) target_link_libraries(plasma_engine_clipboard KF5::Prison) endif () install(TARGETS plasma_engine_clipboard DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/dataengine) install(FILES plasma-dataengine-clipboard.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES org.kde.plasma.clipboard.operations DESTINATION ${PLASMA_DATA_INSTALL_DIR}/services) if(BUILD_TESTING) add_subdirectory(autotests) endif() install( FILES klipper.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) diff --git a/klipper/actionsconfig.ui b/klipper/actionsconfig.ui index 6c33e0275..dd3b3b220 100644 --- a/klipper/actionsconfig.ui +++ b/klipper/actionsconfig.ui @@ -1,118 +1,118 @@ ActionsWidget 0 0 458 360 Replay actions on an item selected from history Remove whitespace when executing actions Enable MIME-based actions Action list: Qt::CustomContextMenu Regular Expression Description Add Action... Edit Action... Delete Action Advanced... - Click on a highlighted item's column to change it. "%s" in a command will be replaced with the clipboard contents.<br>For more information about regular expressions, you could have a look at the <a href="http://en.wikipedia.org/wiki/Regular_expression">Wikipedia entry about this topic</a>. + Click on a highlighted item's column to change it. "%s" in a command will be replaced with the clipboard contents.<br>For more information about regular expressions, you could have a look at the <a href="https://en.wikipedia.org/wiki/Regular_expression">Wikipedia entry about this topic</a>. Qt::RichText true true ActionsTreeWidget QTreeWidget
actionstreewidget.h
diff --git a/klipper/autotests/modeltest.cpp b/klipper/autotests/modeltest.cpp index 41ee22eca..7bcc1a97b 100644 --- a/klipper/autotests/modeltest.cpp +++ b/klipper/autotests/modeltest.cpp @@ -1,600 +1,600 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see https://www.qt.io/licensing. For further information +** use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. +** met: https://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "modeltest.h" #include /*! Connect to all of the models signals. Whenever anything happens recheck everything. */ ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject ( parent ), model ( _model ), fetchingMore ( false ) { if (!model) qFatal("%s: model must not be null", Q_FUNC_INFO); connect(model, &QAbstractItemModel::columnsAboutToBeInserted, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::columnsAboutToBeRemoved, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::columnsInserted, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::columnsRemoved, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::dataChanged, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::headerDataChanged, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::modelReset, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::rowsInserted, this, &ModelTest::runAllTests ); connect(model, &QAbstractItemModel::rowsRemoved, this, &ModelTest::runAllTests ); // Special checks for changes connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::layoutAboutToBeChanged ); connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::layoutChanged ); connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, &ModelTest::rowsAboutToBeInserted ); connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ModelTest::rowsAboutToBeRemoved ); connect(model, &QAbstractItemModel::rowsInserted, this, &ModelTest::rowsInserted ); connect(model, &QAbstractItemModel::rowsRemoved, this, &ModelTest::rowsRemoved ); connect(model, &QAbstractItemModel::dataChanged, this, &ModelTest::dataChanged ); connect(model, &QAbstractItemModel::headerDataChanged, this, &ModelTest::headerDataChanged ); runAllTests(); } void ModelTest::runAllTests() { if ( fetchingMore ) return; nonDestructiveBasicTest(); rowCount(); columnCount(); hasIndex(); index(); parent(); data(); } /*! nonDestructiveBasicTest tries to call a number of the basic functions (not all) to make sure the model doesn't outright segfault, testing the functions that makes sense. */ void ModelTest::nonDestructiveBasicTest() { QVERIFY( model->buddy ( QModelIndex() ) == QModelIndex() ); model->canFetchMore ( QModelIndex() ); QVERIFY( model->columnCount ( QModelIndex() ) >= 0 ); QVERIFY( model->data ( QModelIndex() ) == QVariant() ); fetchingMore = true; model->fetchMore ( QModelIndex() ); fetchingMore = false; Qt::ItemFlags flags = model->flags ( QModelIndex() ); QVERIFY( flags == Qt::ItemIsDropEnabled || flags == 0 ); model->hasChildren ( QModelIndex() ); model->hasIndex ( 0, 0 ); model->headerData ( 0, Qt::Horizontal ); model->index ( 0, 0 ); model->itemData ( QModelIndex() ); QVariant cache; model->match ( QModelIndex(), -1, cache ); model->mimeTypes(); QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); QVERIFY( model->rowCount() >= 0 ); QVariant variant; model->setData ( QModelIndex(), variant, -1 ); model->setHeaderData ( -1, Qt::Horizontal, QVariant() ); model->setHeaderData ( 999999, Qt::Horizontal, QVariant() ); QMap roles; model->sibling ( 0, 0, QModelIndex() ); model->span ( QModelIndex() ); model->supportedDropActions(); } /*! Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() Models that are dynamically populated are not as fully tested here. */ void ModelTest::rowCount() { // qDebug() << "rc"; // check top row QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); int rows = model->rowCount ( topIndex ); QVERIFY( rows >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( topIndex ) ); QModelIndex secondLevelIndex = model->index ( 0, 0, topIndex ); if ( secondLevelIndex.isValid() ) { // not the top level // check a row count where parent is valid rows = model->rowCount ( secondLevelIndex ); QVERIFY( rows >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( secondLevelIndex ) ); } // The models rowCount() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() */ void ModelTest::columnCount() { // check top row QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); QVERIFY( model->columnCount ( topIndex ) >= 0 ); // check a column count where parent is valid QModelIndex childIndex = model->index ( 0, 0, topIndex ); if ( childIndex.isValid() ) QVERIFY( model->columnCount ( childIndex ) >= 0 ); // columnCount() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::hasIndex() */ void ModelTest::hasIndex() { // qDebug() << "hi"; // Make sure that invalid values returns an invalid index QVERIFY( !model->hasIndex ( -2, -2 ) ); QVERIFY( !model->hasIndex ( -2, 0 ) ); QVERIFY( !model->hasIndex ( 0, -2 ) ); int rows = model->rowCount(); int columns = model->columnCount(); // check out of bounds QVERIFY( !model->hasIndex ( rows, columns ) ); QVERIFY( !model->hasIndex ( rows + 1, columns + 1 ) ); if ( rows > 0 ) QVERIFY( model->hasIndex ( 0, 0 ) ); // hasIndex() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::index() */ void ModelTest::index() { // qDebug() << "i"; // Make sure that invalid values returns an invalid index QVERIFY( model->index ( -2, -2 ) == QModelIndex() ); QVERIFY( model->index ( -2, 0 ) == QModelIndex() ); QVERIFY( model->index ( 0, -2 ) == QModelIndex() ); int rows = model->rowCount(); int columns = model->columnCount(); if ( rows == 0 ) return; // Catch off by one errors QVERIFY( model->index ( rows, columns ) == QModelIndex() ); QVERIFY( model->index ( 0, 0 ).isValid() ); // Make sure that the same index is *always* returned QModelIndex a = model->index ( 0, 0 ); QModelIndex b = model->index ( 0, 0 ); QVERIFY( a == b ); // index() is tested more extensively in checkChildren(), // but this catches the big mistakes } /*! Tests model's implementation of QAbstractItemModel::parent() */ void ModelTest::parent() { // qDebug() << "p"; // Make sure the model won't crash and will return an invalid QModelIndex // when asked for the parent of an invalid index. QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() ); if ( model->rowCount() == 0 ) return; // Column 0 | Column 1 | // QModelIndex() | | // \- topIndex | topIndex1 | // \- childIndex | childIndex1 | // Common error test #1, make sure that a top level index has a parent // that is a invalid QModelIndex. QModelIndex topIndex = model->index ( 0, 0, QModelIndex() ); QVERIFY( model->parent ( topIndex ) == QModelIndex() ); // Common error test #2, make sure that a second level index has a parent // that is the first level index. if ( model->rowCount ( topIndex ) > 0 ) { QModelIndex childIndex = model->index ( 0, 0, topIndex ); QVERIFY( model->parent ( childIndex ) == topIndex ); } // Common error test #3, the second column should NOT have the same children // as the first column in a row. // Usually the second column shouldn't have children. QModelIndex topIndex1 = model->index ( 0, 1, QModelIndex() ); if ( model->rowCount ( topIndex1 ) > 0 ) { QModelIndex childIndex = model->index ( 0, 0, topIndex ); QModelIndex childIndex1 = model->index ( 0, 0, topIndex1 ); QVERIFY( childIndex != childIndex1 ); } // Full test, walk n levels deep through the model making sure that all // parent's children correctly specify their parent. checkChildren ( QModelIndex() ); } /*! Called from the parent() test. A model that returns an index of parent X should also return X when asking for the parent of the index. This recursive function does pretty extensive testing on the whole model in an effort to catch edge cases. This function assumes that rowCount(), columnCount() and index() already work. If they have a bug it will point it out, but the above tests should have already found the basic bugs because it is easier to figure out the problem in those tests then this one. */ void ModelTest::checkChildren ( const QModelIndex &parent, int currentDepth ) { // First just try walking back up the tree. QModelIndex p = parent; while ( p.isValid() ) p = p.parent(); // For models that are dynamically populated if ( model->canFetchMore ( parent ) ) { fetchingMore = true; model->fetchMore ( parent ); fetchingMore = false; } int rows = model->rowCount ( parent ); int columns = model->columnCount ( parent ); if ( rows > 0 ) QVERIFY( model->hasChildren ( parent ) ); // Some further testing against rows(), columns(), and hasChildren() QVERIFY( rows >= 0 ); QVERIFY( columns >= 0 ); if ( rows > 0 ) QVERIFY( model->hasChildren ( parent ) ); //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows // << "columns:" << columns << "parent column:" << parent.column(); const QModelIndex topLeftChild = model->index( 0, 0, parent ); QVERIFY( !model->hasIndex ( rows + 1, 0, parent ) ); for ( int r = 0; r < rows; ++r ) { if ( model->canFetchMore ( parent ) ) { fetchingMore = true; model->fetchMore ( parent ); fetchingMore = false; } QVERIFY( !model->hasIndex ( r, columns + 1, parent ) ); for ( int c = 0; c < columns; ++c ) { QVERIFY( model->hasIndex ( r, c, parent ) ); QModelIndex index = model->index ( r, c, parent ); // rowCount() and columnCount() said that it existed... QVERIFY( index.isValid() ); // index() should always return the same index when called twice in a row QModelIndex modifiedIndex = model->index ( r, c, parent ); QVERIFY( index == modifiedIndex ); // Make sure we get the same index if we request it twice in a row QModelIndex a = model->index ( r, c, parent ); QModelIndex b = model->index ( r, c, parent ); QVERIFY( a == b ); { const QModelIndex sibling = model->sibling( r, c, topLeftChild ); QVERIFY( index == sibling ); } { const QModelIndex sibling = topLeftChild.sibling( r, c ); QVERIFY( index == sibling ); } // Some basic checking on the index that is returned QVERIFY( index.model() == model ); QCOMPARE( index.row(), r ); QCOMPARE( index.column(), c ); // While you can technically return a QVariant usually this is a sign // of a bug in data(). Disable if this really is ok in your model. // QVERIFY( model->data ( index, Qt::DisplayRole ).isValid() ); // If the next test fails here is some somewhat useful debug you play with. if (model->parent(index) != parent) { qDebug() << r << c << currentDepth << model->data(index).toString() << model->data(parent).toString(); qDebug() << index << parent << model->parent(index); // And a view that you can even use to show the model. // QTreeView view; // view.setModel(model); // view.show(); } // Check that we can get back our real parent. QCOMPARE( model->parent ( index ), parent ); // recursively go down the children if ( model->hasChildren ( index ) && currentDepth < 10 ) { //qDebug() << r << c << "has children" << model->rowCount(index); checkChildren ( index, ++currentDepth ); }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ // make sure that after testing the children that the index doesn't change. QModelIndex newerIndex = model->index ( r, c, parent ); QVERIFY( index == newerIndex ); } } } /*! Tests model's implementation of QAbstractItemModel::data() */ void ModelTest::data() { // Invalid index should return an invalid qvariant QVERIFY( !model->data ( QModelIndex() ).isValid() ); if ( model->rowCount() == 0 ) return; // A valid index should have a valid QVariant data QVERIFY( model->index ( 0, 0 ).isValid() ); // shouldn't be able to set data on an invalid index QVERIFY( !model->setData ( QModelIndex(), QLatin1String ( "foo" ), Qt::DisplayRole ) ); // General Purpose roles that should return a QString QVariant variant = model->data ( model->index ( 0, 0 ), Qt::ToolTipRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } variant = model->data ( model->index ( 0, 0 ), Qt::StatusTipRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } variant = model->data ( model->index ( 0, 0 ), Qt::WhatsThisRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } // General Purpose roles that should return a QSize variant = model->data ( model->index ( 0, 0 ), Qt::SizeHintRole ); if ( variant.isValid() ) { QVERIFY( variant.canConvert() ); } // General Purpose roles that should return a QFont QVariant fontVariant = model->data ( model->index ( 0, 0 ), Qt::FontRole ); if ( fontVariant.isValid() ) { QVERIFY( fontVariant.canConvert() ); } // Check that the alignment is one we know about QVariant textAlignmentVariant = model->data ( model->index ( 0, 0 ), Qt::TextAlignmentRole ); if ( textAlignmentVariant.isValid() ) { unsigned int alignment = textAlignmentVariant.toUInt(); QCOMPARE( alignment, ( alignment & ( Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask ) ) ); } // General Purpose roles that should return a QColor QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } colorVariant = model->data ( model->index ( 0, 0 ), Qt::ForegroundRole ); if ( colorVariant.isValid() ) { QVERIFY( colorVariant.canConvert() ); } // Check that the "check state" is one we know about. QVariant checkStateVariant = model->data ( model->index ( 0, 0 ), Qt::CheckStateRole ); if ( checkStateVariant.isValid() ) { int state = checkStateVariant.toInt(); QVERIFY( state == Qt::Unchecked || state == Qt::PartiallyChecked || state == Qt::Checked ); } } /*! Store what is about to be inserted to make sure it actually happens \sa rowsInserted() */ void ModelTest::rowsAboutToBeInserted ( const QModelIndex &parent, int start, int /* end */) { // Q_UNUSED(end); // qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString() // << "current count of parent=" << model->rowCount ( parent ); // << "display of last=" << model->data( model->index(start-1, 0, parent) ); // qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) ); Changing c; c.parent = parent; c.oldSize = model->rowCount ( parent ); c.last = model->data ( model->index ( start - 1, 0, parent ) ); c.next = model->data ( model->index ( start, 0, parent ) ); insert.push ( c ); } /*! Confirm that what was said was going to happen actually did \sa rowsAboutToBeInserted() */ void ModelTest::rowsInserted ( const QModelIndex & parent, int start, int end ) { Changing c = insert.pop(); QVERIFY( c.parent == parent ); // qDebug() << "rowsInserted" << "start=" << start << "end=" << end << "oldsize=" << c.oldSize // << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent ); // for (int ii=start; ii <= end; ii++) // { // qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent )); // } // qDebug(); QVERIFY( c.oldSize + ( end - start + 1 ) == model->rowCount ( parent ) ); QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); if (c.next != model->data(model->index(end + 1, 0, c.parent))) { qDebug() << start << end; for (int i=0; i < model->rowCount(); ++i) qDebug() << model->index(i, 0).data().toString(); qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); } QVERIFY( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) ); } void ModelTest::layoutAboutToBeChanged() { for ( int i = 0; i < qBound ( 0, model->rowCount(), 100 ); ++i ) changing.append ( QPersistentModelIndex ( model->index ( i, 0 ) ) ); } void ModelTest::layoutChanged() { for ( int i = 0; i < changing.count(); ++i ) { QPersistentModelIndex p = changing[i]; QVERIFY( p == model->index ( p.row(), p.column(), p.parent() ) ); } changing.clear(); } /*! Store what is about to be inserted to make sure it actually happens \sa rowsRemoved() */ void ModelTest::rowsAboutToBeRemoved ( const QModelIndex &parent, int start, int end ) { qDebug() << "ratbr" << parent << start << end; Changing c; c.parent = parent; c.oldSize = model->rowCount ( parent ); c.last = model->data ( model->index ( start - 1, 0, parent ) ); c.next = model->data ( model->index ( end + 1, 0, parent ) ); remove.push ( c ); } /*! Confirm that what was said was going to happen actually did \sa rowsAboutToBeRemoved() */ void ModelTest::rowsRemoved ( const QModelIndex & parent, int start, int end ) { qDebug() << "rr" << parent << start << end; Changing c = remove.pop(); QVERIFY( c.parent == parent ); QVERIFY( c.oldSize - ( end - start + 1 ) == model->rowCount ( parent ) ); QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) ); QVERIFY( c.next == model->data ( model->index ( start, 0, c.parent ) ) ); } void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { QVERIFY(topLeft.isValid()); QVERIFY(bottomRight.isValid()); QModelIndex commonParent = bottomRight.parent(); QVERIFY(topLeft.parent() == commonParent); QVERIFY(topLeft.row() <= bottomRight.row()); QVERIFY(topLeft.column() <= bottomRight.column()); int rowCount = model->rowCount(commonParent); int columnCount = model->columnCount(commonParent); QVERIFY(bottomRight.row() < rowCount); QVERIFY(bottomRight.column() < columnCount); } void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end) { QVERIFY(start >= 0); QVERIFY(end >= 0); QVERIFY(start <= end); int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount(); QVERIFY(start < itemCount); QVERIFY(end < itemCount); } diff --git a/klipper/autotests/modeltest.h b/klipper/autotests/modeltest.h index 4e9253d12..3a7d83cd5 100644 --- a/klipper/autotests/modeltest.h +++ b/klipper/autotests/modeltest.h @@ -1,96 +1,96 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** conditions see https://qt.io/licensing. For further information +** use the contact form at https://qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. +** met: https://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef MODELTEST_H #define MODELTEST_H #include #include #include class ModelTest : public QObject { Q_OBJECT public: ModelTest( QAbstractItemModel *model, QObject *parent = nullptr ); private Q_SLOTS: void nonDestructiveBasicTest(); void rowCount(); void columnCount(); void hasIndex(); void index(); void parent(); void data(); protected Q_SLOTS: void runAllTests(); void layoutAboutToBeChanged(); void layoutChanged(); void rowsAboutToBeInserted( const QModelIndex &parent, int start, int end ); void rowsInserted( const QModelIndex & parent, int start, int end ); void rowsAboutToBeRemoved( const QModelIndex &parent, int start, int end ); void rowsRemoved( const QModelIndex & parent, int start, int end ); void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void headerDataChanged(Qt::Orientation orientation, int start, int end); private: void checkChildren( const QModelIndex &parent, int currentDepth = 0 ); QAbstractItemModel *model; struct Changing { QModelIndex parent; int oldSize; QVariant last; QVariant next; }; QStack insert; QStack remove; bool fetchingMore; QList changing; }; #endif diff --git a/ksplash/ksplashqml/themes/Minimalistic/Theme.rc b/ksplash/ksplashqml/themes/Minimalistic/Theme.rc index d9a48516e..2d8dd9b73 100644 --- a/ksplash/ksplashqml/themes/Minimalistic/Theme.rc +++ b/ksplash/ksplashqml/themes/Minimalistic/Theme.rc @@ -1,9 +1,9 @@ [KSplash Theme: Minimalistic] Name = Minimalistic splash screen Description = Animated KDE logo on a black background Version = 1.0 Author = Ivan Cukic -Homepage = http://www.kde.org +Homepage = https://www.kde.org # Theme behaviour settings. Engine = KSplashQML diff --git a/libcolorcorrect/suncalc.cpp b/libcolorcorrect/suncalc.cpp index 8bb8e8418..a4f24e88f 100644 --- a/libcolorcorrect/suncalc.cpp +++ b/libcolorcorrect/suncalc.cpp @@ -1,175 +1,175 @@ /******************************************************************** Copyright 2017 Roman Gilg 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, see . *********************************************************************/ #include "suncalc.h" #include "colorcorrectconstants.h" #include #include namespace ColorCorrect { static const double TWILIGHT_NAUT = -12.0; static const double TWILIGHT_CIVIL = -6.0; static const double SUN_RISE_SET = -0.833; static const double SUN_HIGH = 2.0; QVariantMap calculateSunTimings(double latitude, double longitude, bool morning) { - // calculations based on http://aa.quae.nl/en/reken/zonpositie.html + // calculations based on https://aa.quae.nl/en/reken/zonpositie.html // accuracy: +/- 5min // positioning const double rad = M_PI / 180.; const double earthObliquity = 23.4397; // epsilon const double lat = latitude; // phi const double lng = -longitude; // lw // times QDate prompt = QDate::currentDate(); const double juPrompt = prompt.toJulianDay(); // J const double ju2000 = 2451545.; // J2000 // geometry auto mod360 = [](double number) -> double { return std::fmod(number, 360.); }; auto sin = [&rad](double angle) -> double { return std::sin(angle * rad); }; auto cos = [&rad](double angle) -> double { return std::cos(angle * rad); }; auto asin = [&rad](double val) -> double { return std::asin(val) / rad; }; auto acos = [&rad](double val) -> double { return std::acos(val) / rad; }; auto anomaly = [&](const double date) -> double { // M return mod360(357.5291 + 0.98560028 * (date - ju2000)); }; auto center = [&sin](double anomaly) -> double { // C return 1.9148 * sin(anomaly) + 0.02 * sin(2 * anomaly) + 0.0003 * sin(3 * anomaly); }; auto ecliptLngMean = [](double anom) -> double { // Mean ecliptical longitude L_sun = Mean Anomaly + Perihelion + 180° return anom + 282.9372; // anom + 102.9372 + 180° }; auto ecliptLng = [&](double anom) -> double { // lambda = L_sun + C return ecliptLngMean(anom) + center(anom); }; auto declination = [&](const double date) -> double { // delta const double anom = anomaly(date); const double eclLng = ecliptLng(anom); return mod360(asin(sin(earthObliquity) * sin(eclLng))); }; // sun hour angle at specific angle auto hourAngle = [&](const double date, double angle) -> double { // H_t const double decl = declination(date); const double ret0 = (sin(angle) - sin(lat) * sin(decl)) / (cos(lat) * cos(decl)); double ret = mod360(acos( ret0 )); if (180. < ret) { ret = ret - 360.; } return ret; }; /* * Sun positions */ // transit is at noon auto getTransit = [&](const double date) -> double { // Jtransit const double juMeanSolTime = juPrompt - ju2000 - 0.0009 - lng / 360.; // n_x = J - J_2000 - J_0 - l_w / 360° const double juTrEstimate = date + qRound64(juMeanSolTime) - juMeanSolTime; // J_x = J + n - n_x const double anom = anomaly(juTrEstimate); // M const double eclLngM = ecliptLngMean(anom); // L_sun return juTrEstimate + 0.0053 * sin(anom) - 0.0068 * sin(2 * eclLngM); }; auto getSunMorning = [&hourAngle](const double angle, const double transit) -> double { return transit - hourAngle(transit, angle) / 360.; }; auto getSunEvening = [&hourAngle](const double angle, const double transit) -> double { return transit + hourAngle(transit, angle) / 360.; }; /* * Begin calculations */ // noon - sun at the highest point const double juNoon = getTransit(juPrompt); double begin, end; if (morning) { begin = getSunMorning(TWILIGHT_CIVIL, juNoon); end = getSunMorning(SUN_HIGH, juNoon); } else { begin = getSunEvening(SUN_HIGH, juNoon); end = getSunEvening(TWILIGHT_CIVIL, juNoon); } // transform to QDateTime begin += 0.5; end += 0.5; QTime timeBegin, timeEnd; if (std::isnan(begin)) { timeBegin = QTime(); } else { double timePart = begin - (int)begin; timeBegin = QTime::fromMSecsSinceStartOfDay((int)( timePart * MSC_DAY )); } if (std::isnan(end)) { timeEnd = QTime(); } else { double timePart = end - (int)end; timeEnd = QTime::fromMSecsSinceStartOfDay((int)( timePart * MSC_DAY )); } QDateTime dateTimeBegin(prompt, timeBegin, Qt::UTC); QDateTime dateTimeEnd(prompt, timeEnd, Qt::UTC); QVariantMap map; map.insert("begin", dateTimeBegin.toLocalTime()); map.insert("end", dateTimeEnd.toLocalTime()); return map; } QVariantMap SunCalc::getMorningTimings(double latitude, double longitude) { return calculateSunTimings(latitude, longitude, true); } QVariantMap SunCalc::getEveningTimings(double latitude, double longitude) { return calculateSunTimings(latitude, longitude, false); } } diff --git a/lookandfeel/metadata.desktop b/lookandfeel/metadata.desktop index 7ab895e32..c7a999667 100644 --- a/lookandfeel/metadata.desktop +++ b/lookandfeel/metadata.desktop @@ -1,129 +1,129 @@ [Desktop Entry] Comment=Breeze by the KDE VDG Comment[ca]=Brisa pel VDG del KDE Comment[ca@valencia]=Brisa per a VDG de KDE Comment[cs]=Breeze od KDE VDG Comment[da]=Breeze af KDE VDG Comment[de]=Breeze der KDE VG Comment[en_GB]=Breeze by the KDE VDG Comment[es]=Brisa por KDE VDG Comment[et]=Breeze KDE VDG-lt Comment[eu]=Breeze KDEren VDGk egina Comment[fi]=Breeze KDE VDG:ltä Comment[fr]=Breeze, par KDE VDG Comment[gl]=Breeze de KDE VDG Comment[hu]=Breeze a KDE VDG-től Comment[id]=Breeze oleh KDE VDG Comment[it]=Brezza a cura del VDG di KDE Comment[ko]=KDE 시각 디자인 그룹에서 제작한 Breeze Comment[lt]=Breeze pagal KDE VDG Comment[nl]=Breeze door de KDE VDG Comment[nn]=Breeze frå KDE VDG Comment[pl]=Bryza autorstwa KDE VDG Comment[pt]=Brisa da VDG do KDE Comment[pt_BR]=Breeze pelo KDE VDG Comment[ru]=Оформление рабочей среды Breeze от KDE VDG Comment[sk]=Vánok od KDE VDG Comment[sv]=Breeze av KDE:s visuella designgrupp Comment[uk]=Breeze, автори — KDE VDG Comment[x-test]=xxBreeze by the KDE VDGxx Comment[zh_CN]=微风,由 KDE VDG 创作 Comment[zh_TW]=由 KDE VDG 設計的 Breeze Keywords=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate; Keywords[ast]=Escritoriu;Estaya de trabayu;Aspeutu;Estilu;Aspeutu y Estilu;Zarrar sesión;Zarru de sesión;Bloquiar;Bloquéu;Suspender;Suspensión;Apagar;Apagáu;Ivernar;Ivernación;Hibernar;Hibernación; Keywords[ca]=Escriptori;Espai de treball;Aparença;Aspecte i comportament;Sortida;Bloqueig;Suspensió;Aturada;Hibernació; Keywords[ca@valencia]=Escriptori;Espai de treball;Aparença;Aspecte i comportament;Eixida;Bloqueig;Suspensió;Parada;Hibernació; Keywords[da]=Skrivebord;Desktop;Arbejdsområde;Udseende;log ud;Lås;Suspendér;Nedlukning;dvale; Keywords[de]=Desktop;Arbeitsfläche;Arbeitsbereich;Erscheinungsbild;Erscheinungsbild und Verhalten;Abmelden;Sperren;Standby;Ruhezustand;Tiefschlaf;Herunterfahren; Keywords[el]=Επιφάνεια εργασίας;Χώρος εργασίας;Εμφάνιση;Όψη και Αίσθηση;Αποσύνδεση;Κλείδωμα;Αναστολή;Τερματισμός;Νάρκη; Keywords[en_GB]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate; Keywords[es]=Escritorio;Espacio de trabajo;Apariencia;Aspecto visual;Cerrar sesión;Bloquear;Suspender;Apagar;Hibernar; Keywords[et]=töölaud;töötsoon;välimus;väljalogimine;lukustamine;seiskamine;väljalülitamine;talveuni;uni; Keywords[eu]=mahaigain;lan-eremu;lan-gune;itxura;itxura eta izaera;saioa-amaitu;giltzatu;blokeatu;eseki;itzali;hibernatu; Keywords[fi]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;Työpöytä;Työtila;Ulkoasu;Ulkoasu ja tuntuma;Kirjaudu ulos;Lukitse;Valmiustila;Sammuta;Lepotila; Keywords[fr]=bureau;espace de travail;apparence;déconnexion;verrouillage;suspension;arrêt;hibernation; Keywords[gl]=Escritorio;Espazo de traballo;Aparencia;Aparencia e Comportamento;Saír;Trancar;Bloquear;Suspender;Apagar;Hibernar; Keywords[hu]=Asztal;Munkaterület;Megjelenés;Kinézet;Kijelentkezés;Zárolás;Felfüggesztés;Leállítás;Hibernálás; Keywords[id]=Desktop;Ruangkerja;Penampilan;Nuansa dan Suasana,Look and Feel;Logout;Kunci;Suspensi;Mematikan;Hibernasi; Keywords[is]=skjáborð;vinnusvæði;útlit;ásýnd og hegðun;Útskráning;Læsing;setja í bið;slökkva;svæfa; Keywords[it]=desktop;spazio di lavoro;aspetto;uscita;blocco;sospensione;spegnimento;ibernazione; Keywords[ja]=デスクトップ;ワークスペース;外観;外観と挙動;ログアウト;ロック;サスペンド;シャットダウン;休止状態; Keywords[ko]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;데스크톱;작업공간;모양;로그아웃;잠금;대기모드;종료;끄기;최대절전모드; Keywords[lt]=Darbalaukis;Darbo sritis;Erdvė;Erdve;Isvaizda;Isvaizda ir turinys;Išvaizda;Išvaizda ir turinys;Atsijungti;Užrakinti;Uzrakinti;Pristabdyti;Sulaikyti;Užmigdyti;Uzmigdyti;Isjungti;Išjungti;Hibernuoti; Keywords[nl]=Bureaublad;Werkruimte;Uiterlijk;Uiterlijk en gedrag;Afmelden;Vergrendelen;Onderbreken;Afsluiten;Slapen naar schijf; Keywords[nn]=skrivebord;arbeidsområde;arbeidsflate;ustjånad;åtferd;utlogging;logga ut;låsa;låsing;pausemodus;kvilemodus;dvalemodus;avslutting; Keywords[pa]=ਡੈਸਕਟਾਪ;ਵਰਕਸਪੇਸ;ਦਿੱਖ;ਲਾਗਆਉਟ;ਲਾਕ;ਸਸਪੈਂਡ;ਬੰਦ ਕਰੋ;ਹਾਈਬਰਨੇਟ; Keywords[pl]=Pulpit;Przestrzeń robocza;Wygląd;Wygląd i Odczucia;Wylogowanie;Zablokowanie ;Wstrzymanie;Zamknięcie;Hibernowanie;Wrażenia; Keywords[pt]=Ecrã;Área de Trabalho;Aparência;Aparência e Comportamento;Encerrar;Bloquear;Suspender;Desligar;Hibernar; Keywords[pt_BR]=Área de trabalho;Espaço de trabalho;Aparência;Aparência e Comportamento;Encerrar sessão;Bloquear;Suspender;Desligar;Hibernar; Keywords[ru]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;рабочий стол;рабочая среда;внешний вид;визуальное представление;выход;завершение сеанса;блокировка;приостановка работы;завершение работы;выключение;спящий режим;ждущий режим; Keywords[sk]=Plocha;pracovná plocha;vzhľad;nastavenie;odhlásenie;zamknutie;uspanie;vypnutie;hibernácia; Keywords[sl]=Namizje;delovni prostor;videz;videz in občutek;odjava;zaklep;pripravljenost;izklop;mirovanje; Keywords[sr]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;површ;радни простор;изглед;осећај;одјављивање;закључавање;суспендовање;гашење;хибернисање; Keywords[sr@ijekavian]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;површ;радни простор;изглед;осећај;одјављивање;закључавање;суспендовање;гашење;хибернисање; Keywords[sr@ijekavianlatin]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;površ;radni prostor;izgled;osećaj;odjavljivanje;zaključavanje;suspendovanje;gašenje;hibernisanje; Keywords[sr@latin]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;površ;radni prostor;izgled;osećaj;odjavljivanje;zaključavanje;suspendovanje;gašenje;hibernisanje; Keywords[sv]=Skrivbord;Arbetsområde;Utseende;Utseende och känsla;Utloggning;Lås;Viloläge;Avstängning;Dvala; Keywords[tr]=Masaüstü;Çalışma Alanı;Görünüm;Görünüm ve Doku;Çık;Kilitle;Askıya Al;Kapat;Uyku; Keywords[uk]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;стільниця;робочий простір;воркспейс;вигляд;вигляд і поведінка;вихід;вийти;заблокувати;замкнути;призупинити;вимкнути;приспати; Keywords[x-test]=xxDesktopxx;xxWorkspacexx;xxAppearancexx;xxLook and Feelxx;xxLogoutxx;xxLockxx;xxSuspendxx;xxShutdownxx;xxHibernatexx; Keywords[zh_CN]=桌面;工作空间;外观;观感;注销;锁定;待机;关机;休眠; Keywords[zh_TW]=Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate; Name=Breeze Name[ar]=نسيم Name[ast]=Breeze Name[bs]=Breeze Name[ca]=Brisa Name[ca@valencia]=Brisa Name[cs]=Breeze Name[da]=Breeze Name[de]=Breeze Name[el]=Breeze Name[en_GB]=Breeze Name[es]=Brisa Name[et]=Breeze Name[eu]=Breeze Name[fi]=Breeze Name[fr]=Breeze Name[gl]=Breeze Name[hu]=Breeze Name[id]=Breeze Name[is]=Breeze Name[it]=Brezza Name[ja]=Breeze Name[ko]=Breeze Name[lt]=Breeze Name[nb]=Breeze Name[nds]=Breeze Name[nl]=Breeze Name[nn]=Breeze Name[pa]=ਬਰੀਜ਼ Name[pl]=Bryza Name[pt]=Brisa Name[pt_BR]=Breeze Name[ru]=Breeze Name[sk]=Vánok Name[sl]=Sapica Name[sr]=Поветарац Name[sr@ijekavian]=Поветарац Name[sr@ijekavianlatin]=Povetarac Name[sr@latin]=Povetarac Name[sv]=Breeze Name[tg]=Насим Name[tr]=Breeze Name[uk]=Breeze Name[x-test]=xxBreezexx Name[zh_CN]=微风 Name[zh_TW]=微風 Type=Service X-KDE-ServiceTypes=Plasma/LookAndFeel X-KDE-ParentApp= X-KDE-PluginInfo-Author=KDE Visual Design Group X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Email=plasma-devel@kde.org X-KDE-PluginInfo-License=GPLv2+ X-KDE-PluginInfo-Name=org.kde.breeze.desktop X-KDE-PluginInfo-Version=2.0 -X-KDE-PluginInfo-Website=http://www.kde.org +X-KDE-PluginInfo-Website=https://www.kde.org X-Plasma-MainScript=defaults diff --git a/runners/bookmarks/bookmarksrunner.cpp b/runners/bookmarks/bookmarksrunner.cpp index d48b68fbf..3ea649251 100644 --- a/runners/bookmarks/bookmarksrunner.cpp +++ b/runners/bookmarks/bookmarksrunner.cpp @@ -1,152 +1,152 @@ /* * Copyright 2007 Glenn Ergeerts * Copyright 2012 Glenn Ergeerts * * This program 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, 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 Library 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 "bookmarksrunner.h" #include "browser.h" #include #include #include #include #include #include #include #include #include #include #include "bookmarkmatch.h" #include "browserfactory.h" #include "bookmarksrunner_defs.h" K_EXPORT_PLASMA_RUNNER(bookmarksrunner, BookmarksRunner) BookmarksRunner::BookmarksRunner( QObject* parent, const QVariantList &args ) : Plasma::AbstractRunner(parent, args), m_browser(nullptr), m_browserFactory(new BrowserFactory(this)) { Q_UNUSED(args) //qDebug() << "Creating BookmarksRunner"; setObjectName( QStringLiteral("Bookmarks" )); addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Finds web browser bookmarks matching :q:."))); setDefaultSyntax(Plasma::RunnerSyntax(i18nc("list of all web browser bookmarks", "bookmarks"), i18n("List all web browser bookmarks"))); connect(this, &Plasma::AbstractRunner::prepare, this, &BookmarksRunner::prep); } BookmarksRunner::~BookmarksRunner() { } void BookmarksRunner::prep() { auto browser = m_browserFactory->find(findBrowserName(), this); if (m_browser != browser) { m_browser = browser; connect(this, &Plasma::AbstractRunner::teardown, dynamic_cast(m_browser), [this] () { m_browser->teardown(); }); } m_browser->prepare(); } void BookmarksRunner::match(Plasma::RunnerContext &context) { if(! m_browser) return; const QString term = context.query(); if ((term.length() < 3) && (!context.singleRunnerQueryMode())) { return; } bool allBookmarks = term.compare(i18nc("list of all konqueror bookmarks", "bookmarks"), Qt::CaseInsensitive) == 0; QList matches = m_browser->match(term, allBookmarks); foreach(BookmarkMatch match, matches) { if(!context.isValid()) return; context.addMatch(match.asQueryMatch(this)); } } QString BookmarksRunner::findBrowserName() { //HACK find the default browser KConfigGroup config(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), QStringLiteral("General") ); QString exec = config.readPathEntry(QStringLiteral("BrowserApplication"), QString()); //qDebug() << "Found exec string: " << exec; if (exec.isEmpty()) { KService::Ptr service = KMimeTypeTrader::self()->preferredService(QStringLiteral("text/html")); if (service) { exec = service->exec(); } } //qDebug() << "KRunner::Bookmarks: found executable " << exec << " as default browser"; return exec; } void BookmarksRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &action) { Q_UNUSED(context); const QString term = action.data().toString(); QUrl url = QUrl(term); - //support urls like "kde.org" by transforming them to http://kde.org + //support urls like "kde.org" by transforming them to https://kde.org if (url.scheme().isEmpty()) { const int idx = term.indexOf('/'); url.clear(); url.setHost(term.left(idx)); if (idx != -1) { //allow queries const int queryStart = term.indexOf('?', idx); int pathLength = -1; if ((queryStart > -1) && (idx < queryStart)) { pathLength = queryStart - idx; url.setQuery(term.mid(queryStart)); } url.setPath(term.mid(idx, pathLength)); } url.setScheme(QStringLiteral("http")); } QDesktopServices::openUrl(url); } QMimeData * BookmarksRunner::mimeDataForMatch(const Plasma::QueryMatch &match) { QMimeData * result = new QMimeData(); QList urls; urls << QUrl(match.data().toString()); result->setUrls(urls); result->setText(match.data().toString()); return result; } #include "bookmarksrunner.moc" diff --git a/runners/bookmarks/tests/testchromebookmarks.cpp b/runners/bookmarks/tests/testchromebookmarks.cpp index 53af5409f..6d288eb8d 100644 --- a/runners/bookmarks/tests/testchromebookmarks.cpp +++ b/runners/bookmarks/tests/testchromebookmarks.cpp @@ -1,125 +1,125 @@ /* * Copyright 2007 Glenn Ergeerts * Copyright 2012 Glenn Ergeerts * * This program 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, 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 Library 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 "testchromebookmarks.h" #include #include #include "browsers/chrome.h" #include "browsers/chromefindprofile.h" #include "favicon.h" using namespace Plasma; void TestChromeBookmarks::initTestCase() { m_findBookmarksInCurrentDirectory.reset(new FakeFindProfile(QList({Profile("chrome-config-home/Chrome-Bookmarks-Sample.json", new FallbackFavicon())}))); } void TestChromeBookmarks::bookmarkFinderShouldFindEachProfileDirectory() { FindChromeProfile findChrome("chromium", "./chrome-config-home"); QString profileTemplate = QString("./chrome-config-home/.config/%1/%2/Bookmarks"); QList profiles = findChrome.find(); QCOMPARE(profiles.size(), 2); QCOMPARE(profiles[0].path(), profileTemplate.arg("chromium").arg("Default")); QCOMPARE(profiles[1].path(), profileTemplate.arg("chromium").arg("Profile 1")); } void TestChromeBookmarks::bookmarkFinderShouldReportNoProfilesOnErrors() { FindChromeProfile findChrome("chromium", "./no-config-directory"); QList profiles = findChrome.find(); QCOMPARE(profiles.size(), 0); } void TestChromeBookmarks::itShouldFindNothingWhenPrepareIsNotCalled() { Chrome *chrome = new Chrome(m_findBookmarksInCurrentDirectory.data(), this); QCOMPARE(chrome->match("any", true).size(), 0); } void TestChromeBookmarks::itShouldGracefullyExitWhenFileIsNotFound() { FakeFindProfile finder(QList() << Profile("FileNotExisting.json", nullptr)); Chrome *chrome = new Chrome(&finder, this); chrome->prepare(); QCOMPARE(chrome->match("any", true).size(), 0); } void verifyMatch(BookmarkMatch &match, const QString &title, const QString &url, qreal relevance, QueryMatch::Type type) { QueryMatch queryMatch = match.asQueryMatch(nullptr); QCOMPARE(queryMatch.text(), title); QCOMPARE(queryMatch.data().toString(), url); QCOMPARE(queryMatch.relevance(), relevance); QVERIFY2(queryMatch.type() == type, QStringLiteral("Wrong query match type: expecting %1 but was %2").arg(type, queryMatch.type() ).toLatin1()); } void TestChromeBookmarks::itShouldFindAllBookmarks() { Chrome *chrome = new Chrome(m_findBookmarksInCurrentDirectory.data(), this); chrome->prepare(); QList matches = chrome->match("any", true); QCOMPARE(matches.size(), 3); - verifyMatch(matches[0], "some bookmark in bookmark bar", "http://somehost.com/", 0.18, QueryMatch::PossibleMatch); - verifyMatch(matches[1], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); - verifyMatch(matches[2], "bookmark in somefolder", "http://somefolder.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[0], "some bookmark in bookmark bar", "https://somehost.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[1], "bookmark in other bookmarks", "https://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[2], "bookmark in somefolder", "https://somefolder.com/", 0.18, QueryMatch::PossibleMatch); } void TestChromeBookmarks::itShouldFindOnlyMatches() { Chrome *chrome = new Chrome(m_findBookmarksInCurrentDirectory.data(), this); chrome->prepare(); QList matches = chrome->match("other", false); QCOMPARE(matches.size(), 1); - verifyMatch(matches[0], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.45, QueryMatch::PossibleMatch); + verifyMatch(matches[0], "bookmark in other bookmarks", "https://otherbookmarks.com/", 0.45, QueryMatch::PossibleMatch); } void TestChromeBookmarks::itShouldClearResultAfterCallingTeardown() { Chrome *chrome = new Chrome(m_findBookmarksInCurrentDirectory.data(), this); chrome->prepare(); QCOMPARE(chrome->match("any", true).size(), 3); chrome->teardown(); QCOMPARE(chrome->match("any", true).size(), 0); } void TestChromeBookmarks::itShouldFindBookmarksFromAllProfiles() { FakeFindProfile findBookmarksFromAllProfiles(QList() << Profile("chrome-config-home/Chrome-Bookmarks-Sample.json", new FallbackFavicon(this)) << Profile("chrome-config-home/Chrome-Bookmarks-SecondProfile.json", new FallbackFavicon(this)) ); Chrome *chrome = new Chrome(&findBookmarksFromAllProfiles, this); chrome->prepare(); QList matches = chrome->match("any", true); QCOMPARE(matches.size(), 4); - verifyMatch(matches[0], "some bookmark in bookmark bar", "http://somehost.com/", 0.18, QueryMatch::PossibleMatch); - verifyMatch(matches[1], "bookmark in other bookmarks", "http://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); - verifyMatch(matches[2], "bookmark in somefolder", "http://somefolder.com/", 0.18, QueryMatch::PossibleMatch); - verifyMatch(matches[3], "bookmark in secondProfile", "http://secondprofile.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[0], "some bookmark in bookmark bar", "https://somehost.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[1], "bookmark in other bookmarks", "https://otherbookmarks.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[2], "bookmark in somefolder", "https://somefolder.com/", 0.18, QueryMatch::PossibleMatch); + verifyMatch(matches[3], "bookmark in secondProfile", "https://secondprofile.com/", 0.18, QueryMatch::PossibleMatch); } QTEST_MAIN(TestChromeBookmarks); diff --git a/runners/calculator/CMakeLists.txt b/runners/calculator/CMakeLists.txt index 652a28a55..5bf76fd62 100644 --- a/runners/calculator/CMakeLists.txt +++ b/runners/calculator/CMakeLists.txt @@ -1,51 +1,51 @@ ########### next target ############### add_definitions(-DTRANSLATION_DOMAIN=\"plasma_runner_calculatorrunner\") find_package(Qalculate) set_package_properties(Qalculate PROPERTIES DESCRIPTION "Qalculate Library" - URL "http://qalculate.sourceforge.net" + URL "https://qalculate.github.io/" TYPE OPTIONAL PURPOSE "Needed to enable advanced features of the calculator runner" ) if ( QALCULATE_FOUND ) add_definitions(-DENABLE_QALCULATE) set(qalculate_engine_SRCS qalculate_engine.cpp ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated") kde_enable_exceptions() endif() set(krunner_calculatorrunner_SRCS calculatorrunner.cpp ) if ( QALCULATE_FOUND ) add_library(krunner_calculatorrunner MODULE ${qalculate_engine_SRCS} ${krunner_calculatorrunner_SRCS}) target_link_libraries(krunner_calculatorrunner ${QALCULATE_LIBRARIES} ${CLN_LIBRARIES} KF5::KIOCore KF5::Runner KF5::I18n Qt5::Network Qt5::Widgets ) else () add_library(krunner_calculatorrunner MODULE ${krunner_calculatorrunner_SRCS}) target_link_libraries(krunner_calculatorrunner KF5::Runner KF5::I18n Qt5::Gui Qt5::Qml ) endif () install(TARGETS krunner_calculatorrunner DESTINATION ${KDE_INSTALL_PLUGINDIR} ) ########### install files ############### install(FILES plasma-runner-calculator.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) diff --git a/runners/services/servicerunner.cpp b/runners/services/servicerunner.cpp index 636e674c7..6d9ffd80e 100644 --- a/runners/services/servicerunner.cpp +++ b/runners/services/servicerunner.cpp @@ -1,468 +1,468 @@ /* * Copyright (C) 2006 Aaron Seigo * Copyright (C) 2014 Vishesh Handa * Copyright (C) 2016 Harald Sitter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License version 2 as * published by the Free Software Foundation * * 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 Library 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 "servicerunner.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" namespace { int weightedLength(const QString &query) { return KStringHandler::logicalLength(query); } } // namespace /** * @brief Finds all KServices for a given runner query */ class ServiceFinder { public: ServiceFinder(ServiceRunner *runner) : m_runner(runner) {} void match(Plasma::RunnerContext &context) { if (!context.isValid()) { return; } term = context.query(); weightedTermLength = weightedLength(term); matchExectuables(); matchNameKeywordAndGenericName(); matchCategories(); matchJumpListActions(); context.addMatches(matches); } private: void seen(const KService::Ptr &service) { m_seen.insert(service->storageId()); m_seen.insert(service->exec()); } void seen(const KServiceAction &action) { m_seen.insert(action.exec()); } bool hasSeen(const KService::Ptr &service) { return m_seen.contains(service->storageId()) && m_seen.contains(service->exec()); } bool hasSeen(const KServiceAction &action) { return m_seen.contains(action.exec()); } bool disqualify(const KService::Ptr &service) { auto ret = hasSeen(service) || service->noDisplay(); qCDebug(RUNNER_SERVICES) << service->name() << "disqualified?" << ret; seen(service); return ret; } qreal increaseMatchRelavance(const KService::Ptr &service, QVector &strList, QString category) { //Increment the relevance based on all the words (other than the first) of the query list qreal relevanceIncrement = 0; for(int i=1; iname().contains(strList[i], Qt::CaseInsensitive)) { relevanceIncrement += 0.01; } } else if (category == QLatin1String("GenericName")) { if (service->genericName().contains(strList[i], Qt::CaseInsensitive)) { relevanceIncrement += 0.01; } } else if (category == QLatin1String("Exec")) { if (service->exec().contains(strList[i], Qt::CaseInsensitive)) { relevanceIncrement += 0.01; } } else if (category == QLatin1String("Comment")) { if (service->comment().contains(strList[i], Qt::CaseInsensitive)) { relevanceIncrement += 0.01; } } } return relevanceIncrement; } QString generateQuery(QVector &strList) { QString keywordTemplate = QStringLiteral("exist Keywords"); QString genericNameTemplate = QStringLiteral("exist GenericName"); QString nameTemplate = QStringLiteral("exist Name"); QString commentTemplate = QStringLiteral("exist Comment"); // Search for applications which are executable and the term case-insensitive matches any of // * a substring of one of the keywords // * a substring of the GenericName field // * a substring of the Name field // Note that before asking for the content of e.g. Keywords and GenericName we need to ask if // they exist to prevent a tree evaluation error if they are not defined. foreach (QStringRef str, strList) { keywordTemplate += QStringLiteral(" and '%1' ~subin Keywords").arg(str.toString()); genericNameTemplate += QStringLiteral(" and '%1' ~~ GenericName").arg(str.toString()); nameTemplate += QStringLiteral(" and '%1' ~~ Name").arg(str.toString()); commentTemplate += QStringLiteral(" and '%1' ~~ Comment").arg(str.toString()); } QString finalQuery = QStringLiteral("exist Exec and ( (%1) or (%2) or (%3) or ('%4' ~~ Exec) or (%5) )") .arg(keywordTemplate, genericNameTemplate, nameTemplate, strList[0].toString(), commentTemplate); qCDebug(RUNNER_SERVICES) << "Final query : " << finalQuery; return finalQuery; } void setupMatch(const KService::Ptr &service, Plasma::QueryMatch &match) { const QString name = service->name(); match.setText(name); match.setData(service->storageId()); if (!service->genericName().isEmpty() && service->genericName() != name) { match.setSubtext(service->genericName()); } else if (!service->comment().isEmpty()) { match.setSubtext(service->comment()); } if (!service->icon().isEmpty()) { match.setIconName(service->icon()); } } void matchExectuables() { if (weightedTermLength < 2) { return; } // Search for applications which are executable and case-insensitively match the search term - // See http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language + // See https://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language // if the following is unclear to you. query = QStringLiteral("exist Exec and ('%1' =~ Name)").arg(term); KService::List services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), query); if (services.isEmpty()) { return; } foreach (const KService::Ptr &service, services) { qCDebug(RUNNER_SERVICES) << service->name() << "is an exact match!" << service->storageId() << service->exec(); if (disqualify(service)) { continue; } Plasma::QueryMatch match(m_runner); match.setType(Plasma::QueryMatch::ExactMatch); setupMatch(service, match); match.setRelevance(1); matches << match; } } void matchNameKeywordAndGenericName() { //Splitting the query term to match using subsequences QVector queryList = term.splitRef(QLatin1Char(' ')); // If the term length is < 3, no real point searching the Keywords and GenericName if (weightedTermLength < 3) { query = QStringLiteral("exist Exec and ( (exist Name and '%1' ~~ Name) or ('%1' ~~ Exec) )").arg(term); } else { //Match using subsequences (Bug: 262837) query = generateQuery(queryList); } KService::List services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), query); services += KServiceTypeTrader::self()->query(QStringLiteral("KCModule"), query); qCDebug(RUNNER_SERVICES) << "got " << services.count() << " services from " << query; foreach (const KService::Ptr &service, services) { if (disqualify(service)) { continue; } const QString id = service->storageId(); const QString name = service->desktopEntryName(); const QString exec = service->exec(); Plasma::QueryMatch match(m_runner); match.setType(Plasma::QueryMatch::PossibleMatch); setupMatch(service, match); qreal relevance(0.6); // If the term was < 3 chars and NOT at the beginning of the App's name or Exec, then // chances are the user doesn't want that app. if (weightedTermLength < 3) { if (name.startsWith(term, Qt::CaseInsensitive) || exec.startsWith(term, Qt::CaseInsensitive)) { relevance = 0.9; } else { continue; } } else if (service->name().contains(queryList[0], Qt::CaseInsensitive)) { relevance = 0.8; relevance += increaseMatchRelavance(service, queryList, QStringLiteral("Name")); if (service->name().startsWith(queryList[0], Qt::CaseInsensitive)) { relevance += 0.1; } } else if (service->genericName().contains(queryList[0], Qt::CaseInsensitive)) { relevance = 0.65; relevance += increaseMatchRelavance(service, queryList, QStringLiteral("GenericName")); if (service->genericName().startsWith(queryList[0], Qt::CaseInsensitive)) { relevance += 0.05; } } else if (service->exec().contains(queryList[0], Qt::CaseInsensitive)) { relevance = 0.7; relevance += increaseMatchRelavance(service, queryList, QStringLiteral("Exec")); if (service->exec().startsWith(queryList[0], Qt::CaseInsensitive)) { relevance += 0.05; } } else if (service->comment().contains(queryList[0], Qt::CaseInsensitive)) { relevance = 0.5; relevance += increaseMatchRelavance(service, queryList, QStringLiteral("Comment")); if (service->comment().startsWith(queryList[0], Qt::CaseInsensitive)) { relevance += 0.05; } } if (service->categories().contains(QLatin1String("KDE")) || service->serviceTypes().contains(QLatin1String("KCModule"))) { qCDebug(RUNNER_SERVICES) << "found a kde thing" << id << match.subtext() << relevance; relevance += .09; } qCDebug(RUNNER_SERVICES) << service->name() << "is this relevant:" << relevance; match.setRelevance(relevance); if (service->serviceTypes().contains(QLatin1String("KCModule"))) { match.setMatchCategory(i18n("System Settings")); } matches << match; } } void matchCategories() { //search for applications whose categories contains the query query = QStringLiteral("exist Exec and (exist Categories and '%1' ~subin Categories)").arg(term); auto services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), query); foreach (const KService::Ptr &service, services) { qCDebug(RUNNER_SERVICES) << service->name() << "is an exact match!" << service->storageId() << service->exec(); if (disqualify(service)) { continue; } Plasma::QueryMatch match(m_runner); match.setType(Plasma::QueryMatch::PossibleMatch); setupMatch(service, match); qreal relevance = 0.6; if (service->categories().contains(QLatin1String("X-KDE-More")) || !service->showInCurrentDesktop()) { relevance = 0.5; } if (service->isApplication()) { relevance += .04; } match.setRelevance(relevance); matches << match; } } void matchJumpListActions() { if (weightedTermLength < 3) { return; } query = QStringLiteral("exist Actions"); // doesn't work auto services = KServiceTypeTrader::self()->query(QStringLiteral("Application"));//, query); foreach (const KService::Ptr &service, services) { if (service->noDisplay()) { continue; } foreach (const KServiceAction &action, service->actions()) { if (action.text().isEmpty() || action.exec().isEmpty() || hasSeen(action)) { continue; } seen(action); const int matchIndex = action.text().indexOf(term, 0, Qt::CaseInsensitive); if (matchIndex < 0) { continue; } Plasma::QueryMatch match(m_runner); match.setType(Plasma::QueryMatch::HelperMatch); if (!action.icon().isEmpty()) { match.setIconName(action.icon()); } else { match.setIconName(service->icon()); } match.setText(i18nc("Jump list search result, %1 is action (eg. open new tab), %2 is application (eg. browser)", "%1 - %2", action.text(), service->name())); match.setData(action.exec()); qreal relevance = 0.5; if (matchIndex == 0) { relevance += 0.05; } match.setRelevance(relevance); matches << match; } } } ServiceRunner *m_runner; QSet m_seen; QList matches; QString query; QString term; int weightedTermLength; }; ServiceRunner::ServiceRunner(QObject *parent, const QVariantList &args) : Plasma::AbstractRunner(parent, args) { Q_UNUSED(args) setObjectName( QStringLiteral("Application" )); setPriority(AbstractRunner::HighestPriority); addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Finds applications whose name or description match :q:"))); } ServiceRunner::~ServiceRunner() { } QStringList ServiceRunner::categories() const { QStringList cat; cat << i18n("Applications") << i18n("System Settings"); return cat; } QIcon ServiceRunner::categoryIcon(const QString& category) const { if (category == i18n("Applications")) { return QIcon::fromTheme(QStringLiteral("applications-other")); } else if (category == i18n("System Settings")) { return QIcon::fromTheme(QStringLiteral("preferences-system")); } return Plasma::AbstractRunner::categoryIcon(category); } void ServiceRunner::match(Plasma::RunnerContext &context) { // This helper class aids in keeping state across numerous // different queries that together form the matches set. ServiceFinder finder(this); finder.match(context); } void ServiceRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) { Q_UNUSED(context); if (match.type() == Plasma::QueryMatch::HelperMatch) { // Jump List Action KRun::run(match.data().toString(), {}, nullptr); return; } KService::Ptr service = KService::serviceByStorageId(match.data().toString()); if (service) { KActivities::ResourceInstance::notifyAccessed( QUrl(QStringLiteral("applications:") + service->storageId()), QStringLiteral("org.kde.krunner") ); KRun::runService(*service, {}, nullptr, true); } } QMimeData * ServiceRunner::mimeDataForMatch(const Plasma::QueryMatch &match) { KService::Ptr service = KService::serviceByStorageId(match.data().toString()); if (!service) { return nullptr; } QString path = service->entryPath(); if (!QDir::isAbsolutePath(path)) { path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kservices5/") + path); } if (path.isEmpty()) { return nullptr; } QMimeData *data = new QMimeData(); data->setUrls(QList{QUrl::fromLocalFile(path)}); return data; } K_EXPORT_PLASMA_RUNNER(services, ServiceRunner) #include "servicerunner.moc" diff --git a/sddm-theme/dummydata/screenModel.qml b/sddm-theme/dummydata/screenModel.qml index 74543416a..5e25019c8 100644 --- a/sddm-theme/dummydata/screenModel.qml +++ b/sddm-theme/dummydata/screenModel.qml @@ -1,32 +1,32 @@ import QtQuick 2.0 //NOTE: We do not implement a fully working dummy screenModel, //we only implement what's needed for a basic multi-monitor test ListModel { property int primary: 0 //Creating multiple ListElement objects doesn't work, because a ListElement can only take numbers, //strings, booleans or enums, but we need a rect (it stores the screen size/position). //We can insert rects into the ListModel by using this workaround - //It's taken from: http://stackoverflow.com/questions/20537417/add-statically-object-to-listmodel + //It's taken from: https://stackoverflow.com/questions/20537417/add-statically-object-to-listmodel //We create two monitors here, the left one 800x600 and the right one 800x400 pixels //To disable a screen delete one of the "append" function calls Component.onCompleted: { append({ name: "Screen 1", geometry: {x: 0, y: 0, width: 1600, height: 900}, }); append({ name: "Screen 2", geometry: {x: 1980, y: 0, width: 1600, height: 900}, }); } function geometry() { //return the primary monitor size return Qt.rect(800, 0, 800, 400); } } diff --git a/shell/packageplugins/lookandfeel/lookandfeel.cpp b/shell/packageplugins/lookandfeel/lookandfeel.cpp index 95088d2b6..af6e5d478 100644 --- a/shell/packageplugins/lookandfeel/lookandfeel.cpp +++ b/shell/packageplugins/lookandfeel/lookandfeel.cpp @@ -1,105 +1,105 @@ /****************************************************************************** * Copyright 2007-2009 by Aaron Seigo * * Copyright 2013 by Sebastian Kügler * * * * 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 "lookandfeel.h" #include #include #define DEFAULT_LOOKANDFEEL "org.kde.breeze.desktop" void LookAndFeelPackage::initPackage(KPackage::Package *package) { - // http://community.kde.org/Plasma/lookAndFeelPackage# + // https://community.kde.org/Plasma/lookAndFeelPackage# package->setDefaultPackageRoot(QStringLiteral("plasma/look-and-feel/")); //Defaults package->addFileDefinition("defaults", QStringLiteral("defaults"), i18n("Default settings for theme, etc.")); package->addDirectoryDefinition("plasmoidsetupscripts", QStringLiteral("plasmoidsetupscripts"), i18n("Script to tweak default configs of plasmoids")); //Colors package->addFileDefinition("colors", QStringLiteral("colors"), i18n("Color scheme to use for applications.")); //Directories package->addDirectoryDefinition("previews", QStringLiteral("previews"), i18n("Preview Images")); package->addFileDefinition("preview", QStringLiteral("previews/preview.png"), i18n("Preview for the whole style")); package->addFileDefinition("fullscreenpreview", QStringLiteral("previews/fullscreenpreview.jpg"), i18n("Full size preview for the whole style")); package->addFileDefinition("loginmanagerpreview", QStringLiteral("previews/loginmanager.png"), i18n("Preview for the Login Manager")); package->addFileDefinition("lockscreenpreview", QStringLiteral("previews/lockscreen.png"), i18n("Preview for the Lock Screen")); package->addFileDefinition("userswitcherpreview", QStringLiteral("previews/userswitcher.png"), i18n("Preview for the Userswitcher")); package->addFileDefinition("desktopswitcherpreview", QStringLiteral("previews/desktopswitcher.png"), i18n("Preview for the Virtual Desktop Switcher")); package->addFileDefinition("splashpreview", QStringLiteral("previews/splash.png"), i18n("Preview for Splash Screen")); package->addFileDefinition("runcommandpreview", QStringLiteral("previews/runcommand.png"), i18n("Preview for KRunner")); package->addFileDefinition("windowdecorationpreview", QStringLiteral("previews/windowdecoration.png"), i18n("Preview for the Window Decorations")); package->addFileDefinition("windowswitcherpreview", QStringLiteral("previews/windowswitcher.png"), i18n("Preview for Window Switcher")); package->addDirectoryDefinition("loginmanager", QStringLiteral("loginmanager"), i18n("Login Manager")); package->addFileDefinition("loginmanagermainscript", QStringLiteral("loginmanager/LoginManager.qml"), i18n("Main Script for Login Manager")); package->addDirectoryDefinition("logout", QStringLiteral("logout"), i18n("Logout Dialog")); package->addFileDefinition("logoutmainscript", QStringLiteral("logout/Logout.qml"), i18n("Main Script for Logout Dialog")); package->addDirectoryDefinition("lockscreen", QStringLiteral("lockscreen"), i18n("Screenlocker")); package->addFileDefinition("lockscreenmainscript", QStringLiteral("lockscreen/LockScreen.qml"), i18n("Main Script for Lock Screen")); package->addDirectoryDefinition("userswitcher", QStringLiteral("userswitcher"), i18n("UI for fast user switching")); package->addFileDefinition("userswitchermainscript", QStringLiteral("userswitcher/UserSwitcher.qml"), i18n("Main Script for User Switcher")); package->addDirectoryDefinition("desktopswitcher", QStringLiteral("desktopswitcher"), i18n("Virtual Desktop Switcher")); package->addFileDefinition("desktopswitchermainscript", QStringLiteral("desktopswitcher/DesktopSwitcher.qml"), i18n("Main Script for Virtual Desktop Switcher")); package->addDirectoryDefinition("osd", QStringLiteral("osd"), i18n("On-Screen Display Notifications")); package->addFileDefinition("osdmainscript", QStringLiteral("osd/Osd.qml"), i18n("Main Script for On-Screen Display Notifications")); package->addDirectoryDefinition("splash", QStringLiteral("splash"), i18n("Splash Screen")); package->addFileDefinition("splashmainscript", QStringLiteral("splash/Splash.qml"), i18n("Main Script for Splash Screen")); package->addDirectoryDefinition("runcommand", QStringLiteral("runcommand"), i18n("KRunner UI")); package->addFileDefinition("runcommandmainscript", QStringLiteral("runcommand/RunCommand.qml"), i18n("Main Script KRunner")); package->addDirectoryDefinition("windowdecoration", QStringLiteral("windowdecoration"), i18n("Window Decoration")); package->addFileDefinition("windowdecorationmainscript", QStringLiteral("windowdecoration/WindowDecoration.qml"), i18n("Main Script for Window Decoration")); package->addDirectoryDefinition("windowswitcher", QStringLiteral("windowswitcher"), i18n("Window Switcher")); package->addFileDefinition("windowswitchermainscript", QStringLiteral("windowswitcher/WindowSwitcher.qml"), i18n("Main Script for Window Switcher")); package->addDirectoryDefinition("layouts", QStringLiteral("layouts"), i18n("Default layout scripts")); package->setPath(DEFAULT_LOOKANDFEEL); } void LookAndFeelPackage::pathChanged(KPackage::Package *package) { if (!package->metadata().isValid()) { return; } const QString pluginName = package->metadata().pluginId(); if (!pluginName.isEmpty() && pluginName != DEFAULT_LOOKANDFEEL) { KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel"), DEFAULT_LOOKANDFEEL); package->setFallbackPackage(pkg); } else if (package->fallbackPackage().isValid() && pluginName == DEFAULT_LOOKANDFEEL) { package->setFallbackPackage(KPackage::Package()); } } K_EXPORT_KPACKAGE_PACKAGE_WITH_JSON(LookAndFeelPackage, "plasma-packagestructure-lookandfeel.json") #include "lookandfeel.moc" diff --git a/shell/panelview.cpp b/shell/panelview.cpp index a6c0610a1..f6f8b59ca 100644 --- a/shell/panelview.cpp +++ b/shell/panelview.cpp @@ -1,1332 +1,1332 @@ /* * Copyright 2013 Marco Martin * * 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 #include "panelview.h" #include "shellcorona.h" #include "panelshadows_p.h" #include "panelconfigview.h" #include "screenpool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_X11 #include #include #include #include #endif static const int MINSIZE = 10; PanelView::PanelView(ShellCorona *corona, QScreen *targetScreen, QWindow *parent) : PlasmaQuick::ContainmentView(corona, parent), m_offset(0), m_maxLength(0), m_minLength(0), m_contentLength(0), m_distance(0), m_thickness(30), m_initCompleted(false), m_alignment(Qt::AlignLeft), m_corona(corona), m_visibilityMode(NormalPanel), m_backgroundHints(Plasma::Types::StandardBackground), m_shellSurface(nullptr) { if (targetScreen) { setPosition(targetScreen->geometry().center()); setScreenToFollow(targetScreen); setScreen(targetScreen); } setResizeMode(QuickViewSharedEngine::SizeRootObjectToView); setClearBeforeRendering(true); setColor(QColor(Qt::transparent)); setFlags(Qt::FramelessWindowHint|Qt::WindowDoesNotAcceptFocus); connect(&m_theme, &Plasma::Theme::themeChanged, this, &PanelView::updateMask); connect(this, &PanelView::backgroundHintsChanged, this, &PanelView::updateMask); connect(this, &PanelView::backgroundHintsChanged, this, &PanelView::updateEnabledBorders); // TODO: add finished/componentComplete signal to QuickViewSharedEngine, // so we exactly know when rootobject is available connect(this, &QuickViewSharedEngine::statusChanged, this, &PanelView::handleQmlStatusChange); m_positionPaneltimer.setSingleShot(true); m_positionPaneltimer.setInterval(150); connect(&m_positionPaneltimer, &QTimer::timeout, this, &PanelView::restore); m_unhideTimer.setSingleShot(true); m_unhideTimer.setInterval(500); connect(&m_unhideTimer, &QTimer::timeout, this, &PanelView::restoreAutoHide); m_lastScreen = targetScreen; connect(this, SIGNAL(locationChanged(Plasma::Types::Location)), &m_positionPaneltimer, SLOT(start())); connect(this, SIGNAL(containmentChanged()), this, SLOT(containmentChanged())); if (!m_corona->kPackage().isValid()) { qWarning() << "Invalid home screen package"; } m_strutsTimer.setSingleShot(true); connect(&m_strutsTimer, &QTimer::timeout, this, &PanelView::updateStruts); qmlRegisterType(); rootContext()->setContextProperty(QStringLiteral("panel"), this); setSource(m_corona->kPackage().fileUrl("views", QStringLiteral("Panel.qml"))); } PanelView::~PanelView() { if (containment()) { m_corona->requestApplicationConfigSync(); } } KConfigGroup PanelView::panelConfig(ShellCorona *corona, Plasma::Containment *containment, QScreen *screen) { if (!containment || !screen) { return KConfigGroup(); } KConfigGroup views(corona->applicationConfig(), "PlasmaViews"); views = KConfigGroup(&views, QStringLiteral("Panel %1").arg(containment->id())); if (containment->formFactor() == Plasma::Types::Vertical) { return KConfigGroup(&views, QStringLiteral("Vertical") + QString::number(screen->size().height())); //treat everything else as horizontal } else { return KConfigGroup(&views, QStringLiteral("Horizontal") + QString::number(screen->size().width())); } } KConfigGroup PanelView::panelConfigDefaults(ShellCorona *corona, Plasma::Containment *containment, QScreen *screen) { if (!containment || !screen) { return KConfigGroup(); } KConfigGroup views(corona->applicationConfig(), "PlasmaViews"); views = KConfigGroup(&views, QStringLiteral("Panel %1").arg(containment->id())); return KConfigGroup(&views, QStringLiteral("Defaults")); } int PanelView::readConfigValueWithFallBack(const QString &key, int defaultValue) { int value = config().readEntry(key, configDefaults().readEntry(key, defaultValue)); return value; } KConfigGroup PanelView::config() const { return panelConfig(m_corona, containment(), m_screenToFollow); } KConfigGroup PanelView::configDefaults() const { return panelConfigDefaults(m_corona, containment(), m_screenToFollow); } Q_INVOKABLE QString PanelView::fileFromPackage(const QString &key, const QString &fileName) { return corona()->kPackage().filePath(key.toUtf8(), fileName); } void PanelView::maximize() { int length; if (containment()->formFactor() == Plasma::Types::Vertical) { length = m_screenToFollow->size().height(); } else { length = m_screenToFollow->size().width(); } setOffset(0); setMinimumLength(length); setMaximumLength(length); } Qt::Alignment PanelView::alignment() const { return m_alignment; } void PanelView::setAlignment(Qt::Alignment alignment) { if (m_alignment == alignment) { return; } m_alignment = alignment; //alignment is not resolution dependent, doesn't save to Defaults config().parent().writeEntry("alignment", (int)m_alignment); emit alignmentChanged(); positionPanel(); } int PanelView::offset() const { return m_offset; } void PanelView::setOffset(int offset) { if (m_offset == offset) { return; } if (formFactor() == Plasma::Types::Vertical) { if (offset + m_maxLength > m_screenToFollow->size().height()) { setMaximumLength( -m_offset + m_screenToFollow->size().height() ); } } else { if (offset + m_maxLength > m_screenToFollow->size().width()) { setMaximumLength( -m_offset + m_screenToFollow->size().width() ); } } m_offset = offset; config().writeEntry("offset", m_offset); configDefaults().writeEntry("offset", m_offset); positionPanel(); emit offsetChanged(); m_corona->requestApplicationConfigSync(); emit m_corona->availableScreenRegionChanged(); } int PanelView::thickness() const { return m_thickness; } void PanelView::setThickness(int value) { if (value == thickness()) { return; } m_thickness = value; emit thicknessChanged(); config().writeEntry("thickness", value); configDefaults().writeEntry("thickness", value); m_corona->requestApplicationConfigSync(); resizePanel(); } int PanelView::length() const { return qMax(1, m_contentLength); } void PanelView::setLength(int value) { if (value == m_contentLength) { return; } m_contentLength = value; resizePanel(); } int PanelView::maximumLength() const { return m_maxLength; } void PanelView::setMaximumLength(int length) { if (length == m_maxLength) { return; } if (m_minLength > length) { setMinimumLength(length); } config().writeEntry("maxLength", length); configDefaults().writeEntry("maxLength", length); m_maxLength = length; emit maximumLengthChanged(); m_corona->requestApplicationConfigSync(); resizePanel(); } int PanelView::minimumLength() const { return m_minLength; } void PanelView::setMinimumLength(int length) { if (length == m_minLength) { return; } if (m_maxLength < length) { setMaximumLength(length); } config().writeEntry("minLength", length); configDefaults().writeEntry("minLength", length); m_minLength = length; emit minimumLengthChanged(); m_corona->requestApplicationConfigSync(); resizePanel(); } int PanelView::distance() const { return m_distance; } void PanelView::setDistance(int dist) { if (m_distance == dist) { return; } m_distance = dist; emit distanceChanged(); positionPanel(); } Plasma::Types::BackgroundHints PanelView::backgroundHints() const { return m_backgroundHints; } void PanelView::setBackgroundHints(Plasma::Types::BackgroundHints hint) { if (m_backgroundHints == hint) { return; } m_backgroundHints = hint; emit backgroundHintsChanged(); } Plasma::FrameSvg::EnabledBorders PanelView::enabledBorders() const { return m_enabledBorders; } void PanelView::setVisibilityMode(PanelView::VisibilityMode mode) { if (m_visibilityMode == mode) { return; } m_visibilityMode = mode; disconnect(containment(), &Plasma::Applet::activated, this, &PanelView::showTemporarily); if (edgeActivated()) { connect(containment(), &Plasma::Applet::activated, this, &PanelView::showTemporarily); } if (config().isValid() && config().parent().isValid()) { //panelVisibility is not resolution dependent, don't write to Defaults config().parent().writeEntry("panelVisibility", (int)mode); m_corona->requestApplicationConfigSync(); } visibilityModeToWayland(); updateStruts(); emit visibilityModeChanged(); restoreAutoHide(); } void PanelView::visibilityModeToWayland() { if (!m_shellSurface) { return; } KWayland::Client::PlasmaShellSurface::PanelBehavior behavior; switch (m_visibilityMode) { case NormalPanel: behavior = KWayland::Client::PlasmaShellSurface::PanelBehavior::AlwaysVisible; break; case AutoHide: behavior = KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide; break; case LetWindowsCover: behavior = KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsCanCover; break; case WindowsGoBelow: behavior = KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow; break; default: Q_UNREACHABLE(); return; } m_shellSurface->setPanelBehavior(behavior); } PanelView::VisibilityMode PanelView::visibilityMode() const { return m_visibilityMode; } void PanelView::positionPanel() { if (!containment()) { return; } if (!m_initCompleted) { return; } KWindowEffects::SlideFromLocation slideLocation = KWindowEffects::NoEdge; switch (containment()->location()) { case Plasma::Types::TopEdge: containment()->setFormFactor(Plasma::Types::Horizontal); slideLocation = KWindowEffects::TopEdge; break; case Plasma::Types::LeftEdge: containment()->setFormFactor(Plasma::Types::Vertical); slideLocation = KWindowEffects::LeftEdge; break; case Plasma::Types::RightEdge: containment()->setFormFactor(Plasma::Types::Vertical); slideLocation = KWindowEffects::RightEdge; break; case Plasma::Types::BottomEdge: default: containment()->setFormFactor(Plasma::Types::Horizontal); slideLocation = KWindowEffects::BottomEdge; break; } const QPoint pos = geometryByDistance(m_distance).topLeft(); setPosition(pos); if (m_shellSurface) { m_shellSurface->setPosition(pos); } KWindowEffects::slideWindow(winId(), slideLocation, -1); } QRect PanelView::geometryByDistance(int distance) const { QScreen *s = m_screenToFollow; QPoint position; const QRect screenGeometry = s->geometry(); switch (containment()->location()) { case Plasma::Types::TopEdge: switch (m_alignment) { case Qt::AlignCenter: position = QPoint(QPoint(screenGeometry.center().x(), screenGeometry.top()) + QPoint(m_offset - width()/2, distance)); break; case Qt::AlignRight: position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y()) - QPoint(m_offset + width(), distance)); break; case Qt::AlignLeft: default: position = QPoint(screenGeometry.topLeft() + QPoint(m_offset, distance)); } break; case Plasma::Types::LeftEdge: switch (m_alignment) { case Qt::AlignCenter: position = QPoint(QPoint(screenGeometry.left(), screenGeometry.center().y()) + QPoint(distance, m_offset - height()/2)); break; case Qt::AlignRight: position = QPoint(QPoint(screenGeometry.left(), screenGeometry.y() + screenGeometry.height()) - QPoint(distance, m_offset + height())); break; case Qt::AlignLeft: default: position = QPoint(screenGeometry.topLeft() + QPoint(distance, m_offset)); } break; case Plasma::Types::RightEdge: switch (m_alignment) { case Qt::AlignCenter: - // Never use rect.right(); for historical reasons it returns left() + width() - 1; see http://doc.qt.io/qt-5/qrect.html#right + // Never use rect.right(); for historical reasons it returns left() + width() - 1; see https://doc.qt.io/qt-5/qrect.html#right position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.center().y()) - QPoint(thickness() + distance, 0) + QPoint(0, m_offset - height()/2)); break; case Qt::AlignRight: position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y() + screenGeometry.height()) - QPoint(thickness() + distance, 0) - QPoint(0, m_offset + height())); break; case Qt::AlignLeft: default: position = QPoint(QPoint(screenGeometry.x() + screenGeometry.width(), screenGeometry.y()) - QPoint(thickness() + distance, 0) + QPoint(0, m_offset)); } break; case Plasma::Types::BottomEdge: default: switch (m_alignment) { case Qt::AlignCenter: position = QPoint(QPoint(screenGeometry.center().x(), screenGeometry.bottom() - thickness() - distance) + QPoint(m_offset - width()/2, 1)); break; case Qt::AlignRight: position = QPoint(screenGeometry.bottomRight() - QPoint(0, thickness() + distance) - QPoint(m_offset + width(), -1)); break; case Qt::AlignLeft: default: position = QPoint(screenGeometry.bottomLeft() - QPoint(0, thickness() + distance) + QPoint(m_offset, 1)); } } QRect ret = formFactor() == Plasma::Types::Vertical ? QRect(position, QSize(thickness(), height())) : QRect(position, QSize(width(), thickness())); ret = ret.intersected(screenGeometry); return ret; } void PanelView::resizePanel() { if (!m_initCompleted) { return; } QSize targetSize; QSize targetMinSize; QSize targetMaxSize; if (formFactor() == Plasma::Types::Vertical) { const int minSize = qMax(MINSIZE, m_minLength); const int maxSize = qMin(m_maxLength, m_screenToFollow->size().height() - m_offset); targetMinSize = QSize(thickness(), minSize); targetMaxSize = QSize(thickness(), maxSize); targetSize = QSize(thickness(), qBound(minSize, m_contentLength, maxSize)); } else { const int minSize = qMax(MINSIZE, m_minLength); const int maxSize = qMin(m_maxLength, m_screenToFollow->size().width() - m_offset); targetMinSize = QSize(minSize, thickness()); targetMaxSize = QSize(maxSize, thickness()); targetSize = QSize(qBound(minSize, m_contentLength, maxSize), thickness()); } if (minimumSize() != targetMinSize) { setMinimumSize(targetMinSize); } if (maximumSize() != targetMaxSize) { setMaximumSize(targetMaxSize); } if (size() != targetSize) { resize(targetSize); } //position will be updated implicitly from resizeEvent } void PanelView::restore() { if (!containment()) { return; } // All the defaults are based on whatever are the current values // so won't be weirdly reset after screen resolution change //alignment is not resolution dependent //but if fails read it from the resolution dependent one as //the place for this config key is changed in Plasma 5.9 //Do NOT use readConfigValueWithFallBack setAlignment((Qt::Alignment)config().parent().readEntry("alignment", config().readEntry("alignment", m_alignment))); // All the other values are read from screen independent values, // but fallback on the screen independent section, as is the only place // is safe to directly write during plasma startup, as there can be // resolution changes m_offset = readConfigValueWithFallBack("offset", m_offset); if (m_alignment != Qt::AlignCenter) { m_offset = qMax(0, m_offset); } setThickness(readConfigValueWithFallBack("thickness", m_thickness)); const QSize screenSize = m_screenToFollow->size(); setMinimumSize(QSize(-1, -1)); //FIXME: an invalid size doesn't work with QWindows setMaximumSize(screenSize); const int side = containment()->formFactor() == Plasma::Types::Vertical ? screenSize.height() : screenSize.width(); const int maxSize = side - m_offset; m_maxLength = qBound(MINSIZE, readConfigValueWithFallBack("maxLength", side), maxSize); m_minLength = qBound(MINSIZE, readConfigValueWithFallBack("minLength", side), maxSize); //panelVisibility is not resolution dependent //but if fails read it from the resolution dependent one as //the place for this config key is changed in Plasma 5.9 //Do NOT use readConfigValueWithFallBack setVisibilityMode((VisibilityMode)config().parent().readEntry("panelVisibility", config().readEntry("panelVisibility", (int)NormalPanel))); m_initCompleted = true; resizePanel(); positionPanel(); emit maximumLengthChanged(); emit minimumLengthChanged(); emit offsetChanged(); emit alignmentChanged(); //::restore might have been called directly before the timer fires // at which point we don't still need the timer m_positionPaneltimer.stop(); } void PanelView::showConfigurationInterface(Plasma::Applet *applet) { if (!applet || !applet->containment()) { return; } Plasma::Containment *cont = qobject_cast(applet); const bool isPanelConfig = (cont && cont == containment() && cont->isContainment()); if (m_panelConfigView) { if (m_panelConfigView->applet() == applet) { if (isPanelConfig) { // toggles panel controller, whereas applet config is always brought to front if (m_panelConfigView->isVisible()) { m_panelConfigView->hide(); } else { m_panelConfigView->show(); } return; } m_panelConfigView->show(); m_panelConfigView->requestActivate(); return; } m_panelConfigView->hide(); m_panelConfigView->deleteLater(); } if (isPanelConfig) { m_panelConfigView = new PanelConfigView(cont, this); } else { m_panelConfigView = new PlasmaQuick::ConfigView(applet); } m_panelConfigView.data()->init(); m_panelConfigView.data()->show(); m_panelConfigView.data()->requestActivate(); if (isPanelConfig) { KWindowSystem::setState(m_panelConfigView.data()->winId(), NET::SkipTaskbar | NET::SkipPager); } } void PanelView::restoreAutoHide() { bool autoHide = true; disconnect(m_transientWindowVisibleWatcher); if (!edgeActivated()) { autoHide = false; } else if (m_containsMouse) { autoHide = false; } else if (containment() && containment()->isUserConfiguring()) { autoHide = false; } else if (containment() && containment()->status() >= Plasma::Types::NeedsAttentionStatus && containment()->status() != Plasma::Types::HiddenStatus) { autoHide = false; } else { for(QWindow *window: qApp->topLevelWindows()) { if (window->transientParent() == this && window->isVisible()) { m_transientWindowVisibleWatcher = connect(window, &QWindow::visibleChanged, this, &PanelView::restoreAutoHide); autoHide = false; break; //if multiple are open, we will re-evaluate this expression after the first closes } } } setAutoHideEnabled(autoHide); } void PanelView::setAutoHideEnabled(bool enabled) { #if HAVE_X11 if (KWindowSystem::isPlatformX11()) { xcb_connection_t *c = QX11Info::connection(); const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_SCREEN_EDGE_SHOW"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } if (!enabled) { xcb_delete_property(c, winId(), atom->atom); return; } KWindowEffects::SlideFromLocation slideLocation = KWindowEffects::NoEdge; uint32_t value = 0; switch (location()) { case Plasma::Types::TopEdge: value = 0; slideLocation = KWindowEffects::TopEdge; break; case Plasma::Types::RightEdge: value = 1; slideLocation = KWindowEffects::RightEdge; break; case Plasma::Types::BottomEdge: value = 2; slideLocation = KWindowEffects::BottomEdge; break; case Plasma::Types::LeftEdge: value = 3; slideLocation = KWindowEffects::LeftEdge; break; case Plasma::Types::Floating: default: value = 4; break; } int hideType = 0; if (m_visibilityMode == LetWindowsCover) { hideType = 1; } value |= hideType << 8; xcb_change_property(c, XCB_PROP_MODE_REPLACE, winId(), atom->atom, XCB_ATOM_CARDINAL, 32, 1, &value); KWindowEffects::slideWindow(winId(), slideLocation, -1); } #endif if (m_shellSurface && m_visibilityMode == PanelView::AutoHide) { if (enabled) { m_shellSurface->requestHideAutoHidingPanel(); } else { m_shellSurface->requestShowAutoHidingPanel(); } } } void PanelView::resizeEvent(QResizeEvent *ev) { updateEnabledBorders(); //don't setGeometry() to make really sure we aren't doing a resize loop const QPoint pos = geometryByDistance(m_distance).topLeft(); setPosition(pos); if (m_shellSurface) { m_shellSurface->setPosition(pos); } m_strutsTimer.start(STRUTSTIMERDELAY); emit m_corona->availableScreenRegionChanged(); PlasmaQuick::ContainmentView::resizeEvent(ev); #if PLASMA_VERSION < QT_VERSION_CHECK(5,59,0) updateMask(); #endif } void PanelView::moveEvent(QMoveEvent *ev) { updateEnabledBorders(); m_strutsTimer.start(STRUTSTIMERDELAY); PlasmaQuick::ContainmentView::moveEvent(ev); #if PLASMA_VERSION < QT_VERSION_CHECK(5,59,0) updateMask(); #endif } void PanelView::integrateScreen() { connect(m_screenToFollow.data(), &QScreen::geometryChanged, this, &PanelView::restore); updateMask(); KWindowSystem::setOnAllDesktops(winId(), true); KWindowSystem::setType(winId(), NET::Dock); #if HAVE_X11 QXcbWindowFunctions::setWmWindowType(this, QXcbWindowFunctions::Dock); #endif if (m_shellSurface) { m_shellSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::Panel); m_shellSurface->setSkipTaskbar(true); } setVisibilityMode(m_visibilityMode); if (containment()) { containment()->reactToScreenChange(); } } void PanelView::showEvent(QShowEvent *event) { PlasmaQuick::ContainmentView::showEvent(event); integrateScreen(); } void PanelView::setScreenToFollow(QScreen *screen) { if (screen == m_screenToFollow) { return; } if (!screen) { return; } /*connect(screen, &QObject::destroyed, this, [this]() { if (PanelView::screen()) { m_screenToFollow = PanelView::screen(); adaptToScreen(); } });*/ m_screenToFollow = screen; setScreen(screen); adaptToScreen(); } QScreen *PanelView::screenToFollow() const { return m_screenToFollow; } void PanelView::adaptToScreen() { emit screenToFollowChanged(m_screenToFollow); m_lastScreen = m_screenToFollow; if (!m_screenToFollow) { return; } integrateScreen(); showTemporarily(); m_positionPaneltimer.start(); } bool PanelView::event(QEvent *e) { switch (e->type()) { case QEvent::Enter: m_containsMouse = true; if (edgeActivated()) { m_unhideTimer.stop(); } break; case QEvent::Leave: m_containsMouse = false; if (edgeActivated()) { m_unhideTimer.start(); } break; /*Fitt's law: if the containment has margins, and the mouse cursor clicked * on the mouse edge, forward the click in the containment boundaries */ case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast(e); //first, don't mess with position if the cursor is actually outside the view: //somebody is doing a click and drag that must not break when the cursor i outside if (geometry().contains(QCursor::pos(screenToFollow()))) { if (!containmentContainsPosition(me->windowPos())) { auto me2 = new QMouseEvent(me->type(), positionAdjustedForContainment(me->windowPos()), positionAdjustedForContainment(me->windowPos()), positionAdjustedForContainment(me->windowPos()) + position(), me->button(), me->buttons(), me->modifiers()); QCoreApplication::postEvent(this, me2); return true; } } else { // default handling if current mouse position is outside the panel return ContainmentView::event(e); } break; } case QEvent::Wheel: { QWheelEvent *we = static_cast(e); if (!containmentContainsPosition(we->pos())) { auto we2 = new QWheelEvent(positionAdjustedForContainment(we->pos()), positionAdjustedForContainment(we->pos()) + position(), we->pixelDelta(), we->angleDelta(), we->angleDelta().y(), we->orientation(), we->buttons(), we->modifiers(), we->phase()); QCoreApplication::postEvent(this, we2); return true; } break; } case QEvent::DragEnter: { QDragEnterEvent *de = static_cast(e); if (!containmentContainsPosition(de->pos())) { auto de2 = new QDragEnterEvent(positionAdjustedForContainment(de->pos()).toPoint(), de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers()); QCoreApplication::postEvent(this, de2); return true; } break; } //DragLeave just works case QEvent::DragLeave: break; case QEvent::DragMove: { QDragMoveEvent *de = static_cast(e); if (!containmentContainsPosition(de->pos())) { auto de2 = new QDragMoveEvent(positionAdjustedForContainment(de->pos()).toPoint(), de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers()); QCoreApplication::postEvent(this, de2); return true; } break; } case QEvent::Drop: { QDropEvent *de = static_cast(e); if (!containmentContainsPosition(de->pos())) { auto de2 = new QDropEvent(positionAdjustedForContainment(de->pos()).toPoint(), de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers()); QCoreApplication::postEvent(this, de2); return true; } break; } case QEvent::Hide: { if (m_panelConfigView && m_panelConfigView.data()->isVisible()) { m_panelConfigView.data()->hide(); } m_containsMouse = false; break; } case QEvent::PlatformSurface: switch (static_cast(e)->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: setupWaylandIntegration(); PanelShadows::self()->addWindow(this, enabledBorders()); break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: delete m_shellSurface; m_shellSurface = nullptr; PanelShadows::self()->removeWindow(this); break; } break; default: break; } return ContainmentView::event(e); } bool PanelView::containmentContainsPosition(const QPointF &point) const { QQuickItem *containmentItem = containment()->property("_plasma_graphicObject").value(); if (!containmentItem) { return false; } return QRectF(containmentItem->mapToScene(QPoint(0,0)), QSizeF(containmentItem->width(), containmentItem->height())).contains(point); } QPointF PanelView::positionAdjustedForContainment(const QPointF &point) const { QQuickItem *containmentItem = containment()->property("_plasma_graphicObject").value(); if (!containmentItem) { return point; } QRectF containmentRect(containmentItem->mapToScene(QPoint(0,0)), QSizeF(containmentItem->width(), containmentItem->height())); return QPointF(qBound(containmentRect.left() + 2, point.x(), containmentRect.right() - 2), qBound(containmentRect.top() + 2, point.y(), containmentRect.bottom() - 2)); } void PanelView::updateMask() { if (m_backgroundHints == Plasma::Types::NoBackground) { KWindowEffects::enableBlurBehind(winId(), false); KWindowEffects::enableBackgroundContrast(winId(), false); setMask(QRegion()); } else { QRegion mask; QQuickItem *rootObject = this->rootObject(); if (rootObject) { const QVariant maskProperty = rootObject->property("panelMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { mask = maskProperty.value(); } } KWindowEffects::enableBlurBehind(winId(), m_theme.blurBehindEnabled(), mask); KWindowEffects::enableBackgroundContrast(winId(), m_theme.backgroundContrastEnabled(), m_theme.backgroundContrast(), m_theme.backgroundIntensity(), m_theme.backgroundSaturation(), mask); if (KWindowSystem::compositingActive()) { setMask(QRegion()); } else { setMask(mask); } } } bool PanelView::canSetStrut() const { #if HAVE_X11 if (!KWindowSystem::isPlatformX11()) { return true; } // read the wm name, need to do this every time which means a roundtrip unfortunately // but WM might have changed NETRootInfo rootInfo(QX11Info::connection(), NET::Supported | NET::SupportingWMCheck); if (qstricmp(rootInfo.wmName(), "KWin") == 0) { // KWin since 5.7 can handle this fine, so only exclude for other window managers return true; } const QRect thisScreen = screen()->geometry(); const int numScreens = corona()->numScreens(); if (numScreens < 2) { return true; } //Extended struts against a screen edge near to another screen are really harmful, so windows maximized under the panel is a lesser pain //TODO: force "windows can cover" in those cases? const auto screenIds = m_corona->screenIds(); for (int id : screenIds) { if (id == containment()->screen()) { continue; } const QRect otherScreen = corona()->screenGeometry(id); if (!otherScreen.isValid()) { continue; } switch (location()) { case Plasma::Types::TopEdge: if (otherScreen.bottom() <= thisScreen.top()) { return false; } break; case Plasma::Types::BottomEdge: if (otherScreen.top() >= thisScreen.bottom()) { return false; } break; case Plasma::Types::RightEdge: if (otherScreen.left() >= thisScreen.right()) { return false; } break; case Plasma::Types::LeftEdge: if (otherScreen.right() <= thisScreen.left()) { return false; } break; default: return false; } } return true; #else return true; #endif } void PanelView::updateStruts() { if (!containment() || containment()->isUserConfiguring() || !m_screenToFollow) { return; } NETExtendedStrut strut; if (m_visibilityMode == NormalPanel) { const QRect thisScreen = m_screenToFollow->geometry(); // QScreen::virtualGeometry() is very unreliable (Qt 5.5) const QRect wholeScreen = QRect(QPoint(0, 0), m_screenToFollow->virtualSize()); if (!canSetStrut()) { KWindowSystem::setExtendedStrut(winId(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return; } // extended struts are to the combined screen geoms, not the single screen int leftOffset = thisScreen.x(); int rightOffset = wholeScreen.right() - thisScreen.right(); int bottomOffset = wholeScreen.bottom() - thisScreen.bottom(); // qDebug() << "screen l/r/b/t offsets are:" << leftOffset << rightOffset << bottomOffset << topOffset << location(); int topOffset = thisScreen.top(); switch (location()) { case Plasma::Types::TopEdge: strut.top_width = thickness() + topOffset; strut.top_start = x(); strut.top_end = x() + width() - 1; // qDebug() << "setting top edge to" << strut.top_width << strut.top_start << strut.top_end; break; case Plasma::Types::BottomEdge: strut.bottom_width = thickness() + bottomOffset; strut.bottom_start = x(); strut.bottom_end = x() + width() - 1; // qDebug() << "setting bottom edge to" << strut.bottom_width << strut.bottom_start << strut.bottom_end; break; case Plasma::Types::RightEdge: strut.right_width = thickness() + rightOffset; strut.right_start = y(); strut.right_end = y() + height() - 1; // qDebug() << "setting right edge to" << strut.right_width << strut.right_start << strut.right_end; break; case Plasma::Types::LeftEdge: strut.left_width = thickness() + leftOffset; strut.left_start = y(); strut.left_end = y() + height() - 1; // qDebug() << "setting left edge to" << strut.left_width << strut.left_start << strut.left_end; break; default: //qDebug() << "where are we?"; break; } } KWindowSystem::setExtendedStrut(winId(), strut.left_width, strut.left_start, strut.left_end, strut.right_width, strut.right_start, strut.right_end, strut.top_width, strut.top_start, strut.top_end, strut.bottom_width, strut.bottom_start, strut.bottom_end); } void PanelView::containmentChanged() { restore(); connect(containment(), &Plasma::Containment::userConfiguringChanged, this, [this](bool configuring){ if (configuring) { showTemporarily(); } else { m_unhideTimer.start(); updateStruts(); } }); connect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus))); connect(containment(), &Plasma::Applet::appletDeleted, this, [this] { //containment()->destroyed() is true only when the user deleted it //so the config is to be thrown away, not during shutdown if (containment()->destroyed()) { KConfigGroup views(m_corona->applicationConfig(), "PlasmaViews"); for (auto grp : views.groupList()) { if (grp.contains(QRegExp(QStringLiteral("Panel ") + QString::number(containment()->id()) + QStringLiteral("$")))) { qDebug() << "Panel" << containment()->id() << "removed by user"; views.deleteGroup(grp); } views.sync(); } } }); } void PanelView::handleQmlStatusChange(QQmlComponent::Status status) { if (status != QQmlComponent::Ready) { return; } QQuickItem *rootObject = this->rootObject(); if (rootObject) { disconnect(this, &QuickViewSharedEngine::statusChanged, this, &PanelView::handleQmlStatusChange); const QVariant maskProperty = rootObject->property("panelMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { connect(rootObject, SIGNAL(panelMaskChanged()), this, SLOT(updateMask())); updateMask(); } } } void PanelView::statusChanged(Plasma::Types::ItemStatus status) { if (status == Plasma::Types::NeedsAttentionStatus) { showTemporarily(); setFlags(flags() | Qt::WindowDoesNotAcceptFocus); } else if (status == Plasma::Types::AcceptingInputStatus) { setFlags(flags() & ~Qt::WindowDoesNotAcceptFocus); KWindowSystem::forceActiveWindow(winId()); } else { restoreAutoHide(); setFlags(flags() | Qt::WindowDoesNotAcceptFocus); } } void PanelView::showTemporarily() { setAutoHideEnabled(false); QTimer * t = new QTimer(this); t->setSingleShot(true); t->setInterval(3000); connect(t, &QTimer::timeout, this, &PanelView::restoreAutoHide); connect(t, &QTimer::timeout, t, &QObject::deleteLater); t->start(); } void PanelView::screenDestroyed(QObject* ) { // NOTE: this is overriding the screen destroyed slot, we need to do this because // otherwise Qt goes mental and starts moving our panels. See: // https://codereview.qt-project.org/#/c/88351/ // if(screen == this->m_screenToFollow) { // DO NOTHING, panels are moved by ::readaptToScreen // } } void PanelView::setupWaylandIntegration() { if (m_shellSurface) { // already setup return; } if (ShellCorona *c = qobject_cast(corona())) { using namespace KWayland::Client; PlasmaShell *interface = c->waylandPlasmaShellInterface(); if (!interface) { return; } Surface *s = Surface::fromWindow(this); if (!s) { return; } m_shellSurface = interface->createSurface(s, this); } } bool PanelView::edgeActivated() const { return m_visibilityMode == PanelView::AutoHide || m_visibilityMode == LetWindowsCover; } void PanelView::updateEnabledBorders() { Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; if (m_backgroundHints == Plasma::Types::NoBackground) { borders = Plasma::FrameSvg::NoBorder; } else { switch (location()) { case Plasma::Types::TopEdge: borders &= ~Plasma::FrameSvg::TopBorder; break; case Plasma::Types::LeftEdge: borders &= ~Plasma::FrameSvg::LeftBorder; break; case Plasma::Types::RightEdge: borders &= ~Plasma::FrameSvg::RightBorder; break; case Plasma::Types::BottomEdge: borders &= ~Plasma::FrameSvg::BottomBorder; break; default: break; } if (x() <= m_screenToFollow->geometry().x()) { borders &= ~Plasma::FrameSvg::LeftBorder; } if (x() + width() >= m_screenToFollow->geometry().x() + m_screenToFollow->geometry().width()) { borders &= ~Plasma::FrameSvg::RightBorder; } if (y() <= m_screenToFollow->geometry().y()) { borders &= ~Plasma::FrameSvg::TopBorder; } if (y() + height() >= m_screenToFollow->geometry().y() + m_screenToFollow->geometry().height()) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_enabledBorders != borders) { PanelShadows::self()->setEnabledBorders(this, borders); m_enabledBorders = borders; emit enabledBordersChanged(); } } #include "moc_panelview.cpp" diff --git a/startkde/kcminit/CMakeLists.txt b/startkde/kcminit/CMakeLists.txt index 00f024e9c..366b0e426 100644 --- a/startkde/kcminit/CMakeLists.txt +++ b/startkde/kcminit/CMakeLists.txt @@ -1,42 +1,42 @@ find_package(XCB OPTIONAL_COMPONENTS XCB) set_package_properties(XCB PROPERTIES DESCRIPTION "Xcb libraries" - URL "http://www.x.org" + URL "https://www.x.org" TYPE OPTIONAL PURPOSE "Required for enabling special X11 multihead mode") configure_file(config-xcb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-xcb.h) ########### next target ############### set(kcminit_KDEINIT_SRCS main.cpp) set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml) qt5_add_dbus_interface(kcminit_KDEINIT_SRCS ${klauncher_xml} klauncher_iface) kf5_add_kdeinit_executable( kcminit ${kcminit_KDEINIT_SRCS}) target_link_libraries(kdeinit_kcminit Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n PW::KWorkspace) if (XCB_XCB_FOUND) target_link_libraries(kdeinit_kcminit XCB::XCB) endif() install(TARGETS kdeinit_kcminit ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) install(TARGETS kcminit ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) ########### next target ############### # TODO might be simpler to make _startup to be a symlink to set(kcminit_startup_KDEINIT_SRCS main.cpp) qt5_add_dbus_interface(kcminit_startup_KDEINIT_SRCS ${klauncher_xml} klauncher_iface) kf5_add_kdeinit_executable( kcminit_startup ${kcminit_startup_KDEINIT_SRCS}) target_link_libraries(kdeinit_kcminit_startup Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n PW::KWorkspace) if (XCB_XCB_FOUND) target_link_libraries(kdeinit_kcminit_startup XCB::XCB) endif() install(TARGETS kdeinit_kcminit_startup ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) install(TARGETS kcminit_startup ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} )