on e4400a2 help sign in
.bazaar/Makefilenew file+6
since splitsnapshots
unifiedsplit
@@ -0,0 +1,6 @@
1+install:
2+ mkdir -p ~/.bazaar/plugins
3+ cp plugins/* ~/.bazaar/plugins
4+
5+uninstall:
6+ rm ~/.bazaar/plugins/makecheck_unity_phablet.py*
.bazaar/plugins/makecheck_unity_phablet.pynew file+51
@@ -0,0 +1,51 @@
1+#!/usr/bin/python
2+# Copyright 2013, 2014 Canonical Ltd.
3+#
4+# This program is free software; you can redistribute it and/or modify
5+# it under the terms of the GNU Lesser General Public License as published by
6+# the Free Software Foundation; version 3.
7+#
8+# This program is distributed in the hope that it will be useful,
9+# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+# GNU Lesser General Public License for more details.
12+#
13+# You should have received a copy of the GNU Lesser General Public License
14+# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+import os
17+import subprocess
18+from bzrlib import branch
19+from bzrlib.urlutils import local_path_from_url
20+
21+
22+def execute_makecheck(
23+ local_branch, master_branch, old_revision_number, old_revision_id,
24+ future_revision_number, future_revision_id, tree_delta, future_tree):
25+ if not master_branch.basis_tree().has_filename("qml/Shell.qml"):
26+ return
27+
28+ os.chdir(local_path_from_url(master_branch.base))
29+
30+ print "Executing 'make -C builddir test'.."
31+ os.environ['CTEST_OUTPUT_ON_FAILURE'] = "1"
32+ if (subprocess.call("make -C builddir test", shell=True) != 0):
33+
34+ print("\n\n*** Warning ***\n\n"
35+ "Basic tests failed. This commit will not pass continuous "
36+ "integration.")
37+
38+ branch = local_branch or master_branch
39+ revision = branch.repository.get_revision(future_revision_id)
40+ msg_file = open('message.txt', 'w')
41+ msg_file.write(revision.message)
42+ msg_file.close()
43+
44+ print("\n\nSaved commit message to $SRC_DIR/message.txt.")
45+ print("You can uncommit this revision, fix the tests and reuse your "
46+ "message running:\n\nbzr commit -F message.txt\n\n")
47+ elif os.path.isfile("message.txt"):
48+ os.remove("message.txt")
49+
50+branch.Branch.hooks.install_named_hook(
51+ 'pre_commit', execute_makecheck, 'make check pre-commit')
.bzr-builddeb/default.confnew file+2
@@ -0,0 +1,2 @@
1+[BUILDDEB]
2+split = True
.bzrignorenew file+7
@@ -0,0 +1,7 @@
1+# default build dir
2+/builddir
3+# QtCreator project files
4+/*.user
5+# Eclipse project files
6+.settings
7+message.txt
.gitignore−7
@@ -2,15 +2,8 @@
2/builddir
2/builddir
3# QtCreator project files
3# QtCreator project files
4/*.user
4/*.user
5−*.qmlc
6−*.jsc
7# Eclipse project files
5# Eclipse project files
8/.project
6/.project
9/.cproject
7/.cproject
10/.settings
8/.settings
11/.pydevproject
9/.pydevproject
12−# KDevelop project Files
13−/.kdev4/
14−/build/
15−/*.kdev4
16−.clickable/
CMakeLists.txt+3−10
@@ -69,24 +69,15 @@ find_package(Qt5Gui 5.6 REQUIRED)
69find_package(Qt5DBus 5.6 REQUIRED)
69find_package(Qt5DBus 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
72−find_package(Qt5Test 5.6 REQUIRED)
73−find_package(Qt5Svg 5.6 REQUIRED)
74−find_package(Qt5Network 5.6 REQUIRED)
75−find_package(Qt5Xml 5.6 REQUIRED)
76
72
77−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=27)
73+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=23)
78pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
74pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
79pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
75pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
80pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
76pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
81−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=13)
82pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
77pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
83pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
78pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
84pkg_check_modules(UAL REQUIRED ubuntu-app-launch-2)
79pkg_check_modules(UAL REQUIRED ubuntu-app-launch-2)
85pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
80pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
86−pkg_check_modules(QTDBUSTEST REQUIRED
87− libqtdbustest-1
88− libqtdbusmock-1
89− )
90
81
91### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
82### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
92find_path(UBUNTUGESTUREPRIV
83find_path(UBUNTUGESTUREPRIV
@@ -148,6 +139,8 @@ include(autopilot)
148declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
139declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
149
140
150set(SHELL_APP unity8)
141set(SHELL_APP unity8)
142+set(DASH_APP unity8-dash)
143+set(SCOPE_TOOL unity-scope-tool)
151set(INDICATORS_CLIENT_APP indicators-client)
144set(INDICATORS_CLIENT_APP indicators-client)
152set(GREETER_APP unity8-greeter)
145set(GREETER_APP unity8-greeter)
153set(MOCK_INDICATOR_SERVICE_APP unity-mock-indicator-service)
146set(MOCK_INDICATOR_SERVICE_APP unity-mock-indicator-service)
Jenkinsfiledeleted−2
@@ -1,2 +0,0 @@
1−@Library('ubports-build-tools') _
2−buildAndProvideDebianPackage()
README.mddeleted−31
@@ -1,31 +0,0 @@
1−# Lomiri
2−
3−Lomiri is the operating environment for everywhere. It is able to span the gaps between touch, mouse, and keyboard; between phones, tablets, and workstations; and look good doing it.
4−
5−If you want to contribute to Lomiri on Ubuntu Touch, you've come to the right place. If you want to package Lomiri for other operating systems, you'll be better served by the main branch on the repository that we're migrating to: https://gitlab.com/ubports/core/lomiri
6−
7−Lomiri has been renamed from Unity8. Most of the software on-device in Ubuntu Touch based on Ubuntu 16.04 is still called `unity8`.
8−
9−## Where to report issues
10−
11−Issues related to the version of Lomiri that currently runs on Ubuntu Touch devices may still be reported on this repository. We will move these reports to the GitLab repository as part of our final migration.
12−
13−## Developing Lomiri on Ubuntu Touch
14−
15−This repository contains the code for Lomiri currently running on Ubuntu Touch. If you would like to modify this version of Lomiri, follow the steps below. If you would like to modify Lomiri in another operating system, check out our new repository: https://gitlab.com/ubports/core/lomiri
16−
17−Lomiri can be built and its test suite run using [`clickable`](https://clickable-ut.dev). This is a convenient method to try out most graphical changes to Lomiri without an annoying redeployment process. If you wish to test your changes on your device or make changes that are more difficult to test without real hardware, check out [Making changes and testing locally on the UBports documentation](https://docs.ubports.com/en/latest/systemdev/testing-locally.html). If not, read on.
18−
19−Before you start, [install Clickable](https://clickable-ut.dev/en/latest/install.html).
20−
21−Now, clone this repository to your computer: `git clone https://github.com/ubports/unity8.git`
22−
23−Move into this directory: `cd unity8`
24−
25−Now you can use the full suite of tools provided by this repository's [clickable.yaml](clickable.yaml). For example:
26−
27−* `clickable ide qtcreator` will open QtCreator with this repository open as a project. You can edit and build the project this way, but running the tests will be a bit difficult.
28−* `clickable build --libs --verbose` will build Lomiri in the same environment as it would receive in Ubuntu Touch.
29−* `clickable test --libs` will run the entire Lomiri test suite. This test suite includes graphical tests (which are run on a virtual, invisible desktop) and non-graphical unit tests. These tests make sure Lomiri functions as prescribed and prevents new bugs from being added. You should run them before you create a PR on this repository. This command takes about 7 minutes on an Intel i7-8550U, so plan your time accordingly and use the next two options to reduce the number of times you need to run the whole test suite...
30−* `clickable ide 'cd build/x86_64-linux-gnu/unity8/ && make tryShell'` and similar commands that replace the `Shell` with another test target defined in [tests/qmltests/CMakeLists.txt](tests/qmltests/CMakeLists.txt) allow trying out some Lomiri components in a mock environment. You can use this to try out your changes to Lomiri as you develop.
31−* `clickable ide 'cd build/x86_64-linux-gnu/unity8/ && make xvfbtestShell'` and similar commands that replace the `Shell` with another test target defined in [tests/qmltests/CMakeLists.txt](tests/qmltests/CMakeLists.txt) allow running a single TestCase. You can remove the `xvfb` part of the make target to run the test case graphically, which might help you see what is causing the test to fail.
build.sh−16
@@ -1,21 +1,5 @@
1#!/bin/sh
1#!/bin/sh
2
2
3−#
4−# Copyright (C) 2017 Canonical Ltd
5−#
6−# This program is free software: you can redistribute it and/or modify
7−# it under the terms of the GNU General Public License version 3 as
8−# published by the Free Software Foundation.
9−#
10−# This program is distributed in the hope that it will be useful,
11−# but WITHOUT ANY WARRANTY; without even the implied warranty of
12−# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13−# GNU General Public License for more details.
14−#
15−# You should have received a copy of the GNU General Public License
16−# along with this program. If not, see <http://www.gnu.org/licenses/>.
17−#
18−
19SETUP=false
3SETUP=false
20CLEAN=false
4CLEAN=false
21NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
5NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
clickable.yamldeleted−153
@@ -1,153 +0,0 @@
1−clickable_minimum_required: '7'
2−builder: custom
3−build: echo Run \'clickable build --libs --verbose\' to build && false
4−restrict_arch: amd64
5−libraries:
6− unity8:
7− builder: cmake
8− src_dir: "${ROOT}"
9− test: make xvfballtests -j${NUM_PROCS}
10− dependencies_host:
11− - android-headers
12− - cmake
13− - cmake-extras
14− - dbus-test-runner
15− - debhelper
16− - dh-apparmor
17− - doxyqml
18− - g++:native
19− - gdb
20− - graphviz
21− - gsettings-ubuntu-schemas
22− - libandroid-properties-dev
23− - libconnectivity-qt1-dev
24− - libevdev-dev
25− - libgeonames-dev
26− - libgl1-mesa-dev
27− - libgl1-mesa-dri
28− - libgles2-mesa-dev
29− - libglib2.0-dev
30− - libgnome-desktop-3-12
31− - libgnome-desktop-3-dev
32− - libgsettings-qt-dev
33− - libhardware-dev
34− - liblightdm-qt5-3-dev
35− - libpam0g-dev
36− - libpulse-dev
37− - libqmenumodel-dev
38− - libqt5sql5-sqlite
39− - libqt5svg5-dev
40− - libqt5xmlpatterns5-dev
41− - libqtdbusmock1-dev
42− - libqtdbustest1-dev
43− - libsystemsettings-dev
44− - libubuntu-app-launch2-dev
45− - libubuntu-download-manager-common-dev
46− - libubuntugestures5-dev
47− - libubuntugestures5-private-dev
48− - libudev-dev
49− - libudm-common-dev
50− - libunity-api-dev
51− - libusermetricsoutput1-dev
52− - libx11-dev
53− - libxcb1-dev
54− - libxi-dev
55− - pkg-config
56− - python3-all:any
57− - python3-setuptools:native
58− - qml-module-qt-labs-folderlistmodel
59− - qml-module-qt-labs-settings
60− - qml-module-qtmultimedia
61− - qml-module-qtqml-statemachine
62− - qml-module-qtquick-layouts
63− - qml-module-qtquick-xmllistmodel
64− - qml-module-qtquick2
65− - qml-module-qtsysteminfo
66− - qml-module-qttest
67− - qml-module-ubuntu-components
68− - qml-module-ubuntu-layouts
69− - qml-module-ubuntu-settings-components
70− - qml-module-ubuntu-test
71− - qtbase5-dev
72− - qtbase5-dev-tools
73− - qtbase5-private-dev
74− - qtdbustest-runner
75− - qtdeclarative5-dev
76− - qtdeclarative5-dev-tools
77− - qtdeclarative5-private-dev
78− - qtdeclarative5-ubuntu-content1
79− - ttf-ubuntu-font-family
80− - ubports-wallpapers
81− - xvfb
82−dependencies_target:
83− - android-headers
84− - cmake
85− - cmake-extras
86− - dbus-test-runner
87− - debhelper
88− - dh-apparmor
89− - doxyqml
90− - g++:native
91− - gdb
92− - graphviz
93− - gsettings-ubuntu-schemas
94− - libandroid-properties-dev
95− - libconnectivity-qt1-dev
96− - libevdev-dev
97− - libgeonames-dev
98− - libgl1-mesa-dev
99− - libgl1-mesa-dri
100− - libgles2-mesa-dev
101− - libglib2.0-dev
102− - libgnome-desktop-3-12
103− - libgnome-desktop-3-dev
104− - libgsettings-qt-dev
105− - libhardware-dev
106− - liblightdm-qt5-3-dev
107− - libpam0g-dev
108− - libpulse-dev
109− - libqmenumodel-dev
110− - libqt5sql5-sqlite
111− - libqt5svg5-dev
112− - libqt5xmlpatterns5-dev
113− - libqtdbusmock1-dev
114− - libqtdbustest1-dev
115− - libsystemsettings-dev
116− - libubuntu-app-launch2-dev
117− - libubuntu-download-manager-common-dev
118− - libubuntugestures5-dev
119− - libubuntugestures5-private-dev
120− - libudev-dev
121− - libudm-common-dev
122− - libunity-api-dev
123− - libusermetricsoutput1-dev
124− - libx11-dev
125− - libxcb1-dev
126− - libxi-dev
127− - pkg-config
128− - python3-all:any
129− - python3-setuptools:native
130− - qml-module-qt-labs-folderlistmodel
131− - qml-module-qt-labs-settings
132− - qml-module-qtmultimedia
133− - qml-module-qtqml-statemachine
134− - qml-module-qtquick-layouts
135− - qml-module-qtquick-xmllistmodel
136− - qml-module-qtquick2
137− - qml-module-qtsysteminfo
138− - qml-module-qttest
139− - qml-module-ubuntu-components
140− - qml-module-ubuntu-layouts
141− - qml-module-ubuntu-settings-components
142− - qml-module-ubuntu-test
143− - qtbase5-dev
144− - qtbase5-dev-tools
145− - qtbase5-private-dev
146− - qtdbustest-runner
147− - qtdeclarative5-dev
148− - qtdeclarative5-dev-tools
149− - qtdeclarative5-private-dev
150− - qtdeclarative5-ubuntu-content1
151− - ttf-ubuntu-font-family
152− - ubports-wallpapers
153− - xvfb
cmake/modules/QmlPlugins.cmakenew file+148
@@ -0,0 +1,148 @@
1+# If you need to override the qmlplugindump binary, create the qmlplugin executable
2+# target before loading this plugin.
3+
4+if(NOT TARGET qmlplugindump)
5+ find_program(qmlplugindump_exe qmlplugindump)
6+
7+ if(NOT qmlplugindump_exe)
8+ msg(FATAL_ERROR "Could not locate qmlplugindump.")
9+ endif()
10+
11+ add_executable(qmlplugindump IMPORTED)
12+ set_target_properties(qmlplugindump PROPERTIES IMPORTED_LOCATION ${qmlplugindump_exe})
13+endif()
14+
15+#
16+# A custom target for building the qmltypes files manually.
17+#
18+if (NOT TARGET qmltypes)
19+ add_custom_target(qmltypes)
20+endif()
21+
22+# Creates a target for copying resource files into build dir and optionally installing them.
23+#
24+# Files will be copied into ${BINARY_DIR}/${path} or ${CMAKE_CURRENT_BINARY_DIR} and installed
25+# into ${DESTINATION}/${path}.
26+#
27+# Resource file names are matched against {*.{qml,js,jpg,png,sci,svg},qmldir}.
28+#
29+# export_qmlfiles(plugin path
30+# [SEARCH_PATH path] # Path to search for resources in (defaults to ${CMAKE_CURRENT_SOURCE_DIR})
31+# [BINARY_DIR path]
32+# [DESTINATION path]
33+# [TARGET_PREFIX string] # Will be prefixed to the target name
34+# )
35+#
36+# Created target:
37+# - ${TARGET_PREFIX}${plugin}-qmlfiles - Copies resources into the binary dir.
38+
39+macro(export_qmlfiles PLUGIN PATH)
40+ set(single SEARCH_PATH BINARY_DIR DESTINATION TARGET_PREFIX)
41+ cmake_parse_arguments(QMLFILES "" "${single}" "" ${ARGN})
42+
43+ if(NOT QMLFILES_SEARCH_PATH)
44+ set(QMLFILES_SEARCH_PATH ${CMAKE_CURRENT_SOURCE_DIR})
45+ endif()
46+
47+ if(QMLFILES_BINARY_DIR)
48+ set(qmlfiles_dir ${QMLFILES_BINARY_DIR}/${PATH})
49+ else()
50+ set(qmlfiles_dir ${CMAKE_CURRENT_BINARY_DIR})
51+ endif()
52+
53+ file(GLOB QMLFILES
54+ ${QMLFILES_SEARCH_PATH}/*.qml
55+ ${QMLFILES_SEARCH_PATH}/*.js
56+ ${QMLFILES_SEARCH_PATH}/*.jpg
57+ ${QMLFILES_SEARCH_PATH}/*.png
58+ ${QMLFILES_SEARCH_PATH}/*.sci
59+ ${QMLFILES_SEARCH_PATH}/*.svg
60+ ${QMLFILES_SEARCH_PATH}/*.qmltypes
61+ ${QMLFILES_SEARCH_PATH}/qmldir
62+ )
63+
64+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${qmlfiles_dir})
65+
66+ # copy the files
67+ add_custom_target(${QMLFILES_TARGET_PREFIX}${PLUGIN}-qmlfiles ALL
68+ COMMAND cp ${QMLFILES} ${qmlfiles_dir}
69+ DEPENDS ${QMLFILES}
70+ SOURCES ${QMLFILES}
71+ )
72+
73+ if(QMLFILES_DESTINATION)
74+ # install the qmlfiles file.
75+ install(FILES ${QMLFILES}
76+ DESTINATION ${QMLFILES_DESTINATION}/${PATH}
77+ )
78+ endif()
79+endmacro()
80+
81+
82+# Creates a target for generating the typeinfo file for a QML plugin and/or installs the plugin
83+# targets.
84+#
85+# Files will be copied into ${BINARY_DIR}/${path} or ${CMAKE_CURRENT_BINARY_DIR} and installed
86+# into ${DESTINATION}/${path}. If you don't pass BINARY_DIR, it's assumed that current source
87+# path ends with ${path}.
88+#
89+# The generated file will be named after the last segment of the plugin name, e.g. Foo.qmltypes.
90+#
91+# export_qmlplugin(plugin version path
92+# [BINARY_DIR path]
93+# [DESTINATION path]
94+# [TARGET_PREFIX string] # Will be prefixed to the target name
95+# [ENVIRONMENT string] # Will be added to qmlplugindump's env
96+# [TARGETS target1 [target2 ...]] # Targets to depend on and install (e.g. the plugin shared object)
97+# [NO_TYPES] # Do not create the qmltypes target
98+# )
99+#
100+# Created target:
101+# - ${TARGET_PREFIX}${plugin}-qmltypes - Generates the qmltypes file in the source dir.
102+# It will be made a dependency of the "qmltypes" target.
103+
104+macro(export_qmlplugin PLUGIN VERSION PATH)
105+ set(options NO_TYPES)
106+ set(single BINARY_DIR DESTINATION TARGET_PREFIX ENVIRONMENT)
107+ set(multi TARGETS)
108+ cmake_parse_arguments(QMLPLUGIN "${options}" "${single}" "${multi}" ${ARGN})
109+
110+ if(QMLPLUGIN_BINARY_DIR)
111+ set(qmlplugin_dir ${QMLPLUGIN_BINARY_DIR}/${PATH})
112+ else()
113+ # Find import path to point qmlplugindump at
114+ string(REGEX REPLACE "/${PATH}$" "" QMLPLUGIN_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
115+ set(qmlplugin_dir ${CMAKE_CURRENT_BINARY_DIR})
116+ endif()
117+
118+ if(NOT QMLPLUGIN_NO_TYPES)
119+ # Relative path for the module
120+ string(REPLACE "${CMAKE_BINARY_DIR}/" "" QMLPLUGIN_MODULE_DIR "${QMLPLUGIN_BINARY_DIR}")
121+
122+ # Find the last segment of the plugin name to use as qmltypes basename
123+ string(REGEX MATCH "[^.]+$" plugin_suffix ${PLUGIN})
124+ set(target_prefix ${QMLPLUGIN_TARGET_PREFIX}${PLUGIN})
125+ set(qmltypes_path ${CMAKE_CURRENT_SOURCE_DIR}/${plugin_suffix}.qmltypes)
126+
127+ add_custom_target(${target_prefix}-qmltypes
128+ COMMAND env ${QMLPLUGIN_ENVIRONMENT} $<TARGET_FILE:qmlplugindump> -notrelocatable
129+ ${PLUGIN} ${VERSION} ${QMLPLUGIN_MODULE_DIR} > ${qmltypes_path}
130+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
131+ )
132+ add_dependencies(${target_prefix}-qmltypes ${target_prefix}-qmlfiles ${QMLPLUGIN_TARGETS})
133+ add_dependencies(qmltypes ${target_prefix}-qmltypes)
134+ endif()
135+
136+ set_target_properties(${QMLPLUGIN_TARGETS} PROPERTIES
137+ ARCHIVE_OUTPUT_DIRECTORY ${qmlplugin_dir}
138+ LIBRARY_OUTPUT_DIRECTORY ${qmlplugin_dir}
139+ RUNTIME_OUTPUT_DIRECTORY ${qmlplugin_dir}
140+ )
141+
142+ if (QMLPLUGIN_DESTINATION)
143+ # Install additional targets
144+ install(TARGETS ${QMLPLUGIN_TARGETS}
145+ DESTINATION ${QMLPLUGIN_DESTINATION}/${PATH}
146+ )
147+ endif()
148+endmacro()
cmake/modules/QmlTest.cmake+4−9
@@ -201,7 +201,7 @@ function(add_executable_test COMPONENT_NAME TARGET)
201 add_qmltest_target(xvfbtest${COMPONENT_NAME} ${TARGET}
201 add_qmltest_target(xvfbtest${COMPONENT_NAME} ${TARGET}
202 COMMAND $<TARGET_FILE:xvfb-run> --server-args "-screen 0 1024x768x24" --auto-servernum ${qmltest_command}
202 COMMAND $<TARGET_FILE:xvfb-run> --server-args "-screen 0 1024x768x24" --auto-servernum ${qmltest_command}
203 ${depends}
203 ${depends}
204− ENVIRONMENT QT_QPA_PLATFORM=xcb QML2_IMPORT_PATH=${imports} LD_PRELOAD=/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/mesa/libGL.so.1 ${QMLTEST_ENVIRONMENT}
204+ ENVIRONMENT QML2_IMPORT_PATH=${imports} ${QMLTEST_ENVIRONMENT} LD_PRELOAD=/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/mesa/libGL.so.1
205 TARGETS ${xvfb_targets}
205 TARGETS ${xvfb_targets}
206 )
206 )
207 endif()
207 endif()
@@ -264,16 +264,12 @@ endfunction()
264# installed system.
264# installed system.
265
265
266function(add_meta_test TARGET_NAME)
266function(add_meta_test TARGET_NAME)
267− cmake_parse_arguments(TEST "SERIAL" "" "DEPENDS" ${ARGN})
267+ cmake_parse_arguments(TEST "" "" "DEPENDS" ${ARGN})
268
268
269 add_custom_target(${TARGET_NAME})
269 add_custom_target(${TARGET_NAME})
270
270
271 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
271 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
272− if(TEST_SERIAL)
273− file(WRITE "${filename}" "#!/bin/sh\n\n")
274− else()
275− file(WRITE "${filename}" "#!/usr/bin/parallel --shebang --no-notice\n\n")
272+ file(WRITE "${filename}" "#!/usr/bin/parallel --shebang --no-notice\n\n")
276− endif()
277
273
278 add_meta_dependencies(${TARGET_NAME} DEPENDS ${TEST_DEPENDS})
274 add_meta_dependencies(${TARGET_NAME} DEPENDS ${TEST_DEPENDS})
279 # else we will write the rest of the script as we add cmake targets
275 # else we will write the rest of the script as we add cmake targets
@@ -311,7 +307,6 @@ function(install_test_script TARGET_NAME)
311 foreach(ONE_CMD ${TEST_COMMAND})
307 foreach(ONE_CMD ${TEST_COMMAND})
312 set(script "${script}'${ONE_CMD}' ")
308 set(script "${script}'${ONE_CMD}' ")
313 endforeach()
309 endforeach()
314− set(script "${script}\"\$@\"") # Allow passing arguments if desired
315
310
316 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
311 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${TARGET_NAME}.sh")
317
312
@@ -375,7 +370,7 @@ function(add_meta_dependencies UPSTREAM_TARGET)
375 # add depend to the meta test script that we will install on system
370 # add depend to the meta test script that we will install on system
376 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${UPSTREAM_TARGET}.sh")
371 set(filename "${CMAKE_BINARY_DIR}/tests/scripts/${UPSTREAM_TARGET}.sh")
377 if (EXISTS "${filename}")
372 if (EXISTS "${filename}")
378− file(APPEND "${filename}" "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/scripts/${depend}.sh \"\$@\" 2>&1\n")
373+ file(APPEND "${filename}" "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}/tests/scripts/${depend}.sh\n")
379 endif()
374 endif()
380 endforeach()
375 endforeach()
381endfunction()
376endfunction()
data/CMakeLists.txt+9−1
@@ -1,11 +1,13 @@
1# generate desktop files
1# generate desktop files
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3+configure_file(${DASH_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop @ONLY)
3configure_file(${INDICATORS_CLIENT_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop @ONLY)
4configure_file(${INDICATORS_CLIENT_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop @ONLY)
4configure_file(${GREETER_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop @ONLY)
5configure_file(${GREETER_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${GREETER_APP}.desktop @ONLY)
5
6
6# install desktop files
7# install desktop files
7install(FILES
8install(FILES
8 ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
9 ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
10+ ${CMAKE_CURRENT_BINARY_DIR}/${DASH_APP}.desktop
9 ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop
11 ${CMAKE_CURRENT_BINARY_DIR}/${INDICATORS_CLIENT_APP}.desktop
10 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
12 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
11 )
13 )
@@ -20,8 +22,14 @@ install(FILES
20 DESTINATION ${CMAKE_INSTALL_DATADIR}/lightdm/lightdm.conf.d
22 DESTINATION ${CMAKE_INSTALL_DATADIR}/lightdm/lightdm.conf.d
21 )
23 )
22
24
25+# install dash icon
26+install(FILES
27+ ${CMAKE_CURRENT_SOURCE_DIR}/${DASH_APP}.png
28+ DESTINATION ${SHELL_APP_DIR}/Dash/
29+ )
30+
23add_custom_target(pkgversion ALL COMMAND dpkg-parsechangelog -l${CMAKE_SOURCE_DIR}/debian/changelog --show-field version > ${CMAKE_CURRENT_BINARY_DIR}/version)
31add_custom_target(pkgversion ALL COMMAND dpkg-parsechangelog -l${CMAKE_SOURCE_DIR}/debian/changelog --show-field version > ${CMAKE_CURRENT_BINARY_DIR}/version)
24
32
25install(FILES com.canonical.Unity8.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
33install(FILES com.canonical.Unity8.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
26−install(FILES com.canonical.Unity.gschema.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/glib-2.0/schemas)
34+install(FILES unity8-dash.url-dispatcher DESTINATION ${CMAKE_INSTALL_DATADIR}/url-dispatcher/urls)
27install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version DESTINATION ${CMAKE_INSTALL_LOCALSTATEDIR}/lib/unity8)
35install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version DESTINATION ${CMAKE_INSTALL_LOCALSTATEDIR}/lib/unity8)
data/com.canonical.Unity.gschema.xmldeleted−255
@@ -1,255 +0,0 @@
1−<schemalist>
2− <enum id="form-factor-enum">
3− <value nick="Automatic" value="0" />
4− <value nick="Desktop" value="1" />
5− <value nick="Netbook" value="2" />
6− <value nick="TV" value="3" />
7− </enum>
8− <enum id="home-expanded-enum">
9− <value nick="Not Expanded" value="0" />
10− <value nick="Expanded" value="1" />
11− </enum>
12− <enum id="launcher-position-enum">
13− <value nick="Left" value="0" />
14− <value nick="Bottom" value="1" />
15− </enum>
16− <enum id="desktop-type-enum">
17− <value nick="Ubuntu" value="0" />
18− <value nick="UbuntuKylin" value="1" />
19− </enum>
20−
21− <schema path="/com/canonical/unity/" id="com.canonical.Unity" gettext-domain="unity">
22− <key enum="form-factor-enum" name="form-factor">
23− <default>"Automatic"</default>
24− <summary>The form factor Unity should target.</summary>
25− <description>The form factor chosen will affect the size and appearance of the Dash, Launcher and also the Window Management behaviour.</description>
26− </key>
27− <key enum="home-expanded-enum" name="home-expanded">
28− <default>"Expanded"</default>
29− <summary>Whether the home screen should be expanded.</summary>
30− <description>Whether the home screen should be expanded.</description>
31− </key>
32− <key enum="desktop-type-enum" name="desktop-type">
33− <default>"Ubuntu"</default>
34− <summary>The current desktop name.</summary>
35− <description>The current desktop name.</description>
36− </key>
37− <key type="i" name="minimize-count">
38− <default>0</default>
39− <summary>Number of times a normal window has been minimized.</summary>
40− <description>This is used to adjust the animation speed by making it progressively faster the more it is used.</description>
41− </key>
42− <key type="i" name="minimize-fast-duration">
43− <default>300</default>
44− <summary>The duration for the minimize animation when it is at its fastest setting.</summary>
45− <description>This is the duration that the minimize animation will have when it has been used more than an number of times equal minimize-speed-threshold.</description>
46− </key>
47− <key type="i" name="minimize-slow-duration">
48− <default>800</default>
49− <summary>The duration for the minimize animation when it is at its slowest setting.</summary>
50− <description>This is the duration that the minimize animation will have when it has never been used.</description>
51− </key>
52− <key type="i" name="minimize-speed-threshold">
53− <default>100</default>
54− <summary>The number of minimizations required to reach maximum speed.</summary>
55− <description>The speed of the minimize animation will progressively get faster as minimize-count approaches this value.</description>
56− </key>
57− <key type="b" name="double-click-activate">
58− <default>true</default>
59− <summary>Enable/Disable dash result double-click activation.</summary>
60− <description>This is used to enable/disable double-click result activation in the dash. Double-click to activate, single click preview</description>
61− </key>
62− <key type="b" name="integrated-menus">
63− <default>false</default>
64− <summary>Enable/Disable the integrated menus in Unity.</summary>
65− <description>When this is enabled, the application menus will be shown
66− on the window decoration, otherwise they will be always shown on the
67− unity top panel</description>
68− </key>
69− <key type="u" name="show-menus-now-delay">
70− <default>180</default>
71− <range min="0" max="5000"/>
72− <summary>Delay (in ms) before showing the menus when pressing Alt</summary>
73− <description>This allows tune the delay before presenting unity menus
74− (in non always-show-menus mode).</description>
75− </key>
76− <key type="b" name="always-show-menus">
77− <default>false</default>
78− <summary>Toggle the menu visibility based on mouse hovering.</summary>
79− <description>When this is enabled, the application menus will be always
80− shown (on the window decoration or in the unity panel, depending whether
81− integrated menus are enabled), otherwise they will be shown only when
82− the mouse cursor is over the relative mouse area.</description>
83− </key>
84− <key type="as" name="whitelist-repeated-keys">
85− <default>[
86− 'XF86KbdBrightnessUp',
87− 'XF86KbdBrightnessDown',
88− 'XF86MonBrightnessUp',
89− 'XF86MonBrightnessDown',
90− 'XF86AudioRaiseVolume',
91− 'XF86AudioLowerVolume'
92− ]</default>
93− <summary>List of keycodes that should be processed even if auto-repated.</summary>
94− <description>These keycodes are processed even if they are auto-repeated.</description>
95− </key>
96− <key type="b" name="pam-check-account-type">
97− <default>false</default>
98− <summary>Enable/Disable PAM account checking</summary>
99− <description>Whether PAM should check the result of account modules
100− when authenticating. Only do this if you have account
101− configured properly on your system.</description>
102− </key>
103− <key type="b" name="lowgfx">
104− <default>false</default>
105− <summary>Enable/Disable Low Graphics Mode</summary>
106− <description>Whether Unity runs in Low Graphics Mode.</description>
107− </key>
108− </schema>
109− <schema path="/com/canonical/unity/interface/" id="com.canonical.Unity.Interface" gettext-domain="unity">
110− <key type="d" name="text-scale-factor">
111− <default>1.0</default>
112− <range min="0.5" max="3.0"/>
113− <summary>Font scaling for unity and applications.</summary>
114− <description>This value defines the global font scaling used by both
115− unity and applications. It will match the current system font scaling.</description>
116− </key>
117− <key type="d" name="cursor-scale-factor">
118− <default>1.0</default>
119− <range min="0.5" max="3.0"/>
120− <summary>Mouse cursor scaling.</summary>
121− <description>This value defines the global mouse cursor scaling used by both
122− unity and applications. Changing this value allows to use a custom scaling
123− for the mouse cursor.</description>
124− </key>
125− <key type="s" name="app-scale-factor-monitor">
126− <default>''</default>
127− <summary>The name of the monitor that controls the global app scaling factor.</summary>
128− <description>This value defines the monitor that unity will use (if found) as reference
129− for scaling all the applications.</description>
130− </key>
131− <key type="b" name="app-fallback-to-maximum-scale-factor">
132− <default>true</default>
133− <summary>Use the maximum per-monitor scale-factor as application scale factor if no target monitor is found.</summary>
134− <description>When this is enabled, the applications scale factor will match
135− the scale factor of the monitor with the greater value, in case the monitor
136− defined in 'app-scale-factor-monitor' is not provided or available.</description>
137− </key>
138− </schema>
139− <schema path="/com/canonical/unity/launcher/" id="com.canonical.Unity.Launcher" gettext-domain="unity">
140− <key type="as" name="favorites">
141− <default>[
142− 'application://ubiquity.desktop',
143− 'application://org.gnome.Nautilus.desktop',
144− 'application://firefox.desktop',
145− 'application://libreoffice-writer.desktop',
146− 'application://libreoffice-calc.desktop',
147− 'application://libreoffice-impress.desktop',
148− 'application://org.gnome.Software.desktop',
149− 'application://ubuntu-amazon-default.desktop',
150− 'application://unity-control-center.desktop',
151− 'unity://running-apps',
152− 'unity://expo-icon',
153− 'unity://devices'
154− ]</default>
155− <summary>List of items that should be shown by default in the launcher</summary>
156− <description>These items can be: application://desktop-id.desktop, device://uiid and unity://special-id (including: unity://running-apps (icons of running applications) unity://devices (icons of attached devices), unity://expo-icon (icon of the workspace switcher) and unity://desktop-icon (the show-desktop icon)); the order of this list determines the launcher item's position.</description>
157− </key>
158− <key type="as" name="items">
159− <default>[
160− 'application:///dialer-app.desktop',
161− 'application:///messaging-app.desktop',
162− 'application:///address-book-app.desktop',
163− 'application:///ubuntu-system-settings.desktop',
164− 'appid://openstore.openstore-team/openstore/current-user-version',
165− 'appid://com.ubuntu.camera/camera/current-user-version',
166− 'appid://com.ubuntu.gallery/gallery/current-user-version',
167− 'application:///morph-browser.desktop'
168− ]</default>
169− <summary>List of items that should be shown by default in the launcher</summary>
170− <description>These items can be: application:///desktop-id.desktop or appid://package/app/current-user-version.</description>
171− </key>
172− <key type="s" name="favorite-migration">
173− <default>''</default>
174− <summary>Version of last migration done</summary>
175− <description>This is a detection key for the favorite migration script to know whether the needed migration is done or not.</description>
176− </key>
177− <key enum="launcher-position-enum" name="launcher-position">
178− <default>"Left"</default>
179− <summary>The position of launcher.</summary>
180− <description>The position of launcher.</description>
181− </key>
182− </schema>
183− <schema path="/com/canonical/unity/devices/" id="com.canonical.Unity.Devices" gettext-domain="unity">
184− <key type="as" name="blacklist">
185− <default>[]</default>
186− <summary>List of device uuid blacklist from the launcher.</summary>
187− <description>These devices are not shown in the launcher by default.</description>
188− </key>
189− </schema>
190− <schema path="/com/canonical/unity/dash/" id="com.canonical.Unity.Dash" gettext-domain="unity">
191− <key type="as" name="scopes">
192− <default>[ 'home.scope', 'applications.scope', 'files.scope', 'video.scope', 'music.scope', 'photos.scope', 'social.scope' ]</default>
193− <summary>List of scope ids specifying which scopes should be created and the order to display them in.</summary>
194− <description>The scopes listed in the scope bar will be ordered according to this list.</description>
195− </key>
196− <key type="as" name="favorite-scopes">
197− <default>[ 'scope://clickscope', 'scope://musicaggregator', 'scope://videoaggregator' ]</default>
198− <summary>List of scope queries specifying what should be displayed in the dash.</summary>
199− <description>List of favorite scopes displayed in the dash.</description>
200− </key>
201− </schema>
202− <schema path="/com/canonical/unity/decorations/" id="com.canonical.Unity.Decorations" gettext-domain="unity">
203− <key type="u" name="grab-wait">
204− <default>175</default>
205− <range min="0" max="1000"/>
206− <summary>Milliseconds to wait before considering a mouse pressure a grab</summary>
207− <description>The number of ms to wait before starting the window movement (and then
208− showing the proper mouse cursor, and grabbing the window)</description>
209− </key>
210− </schema>
211− <schema path="/com/canonical/unity/integrated-menus/" id="com.canonical.Unity.IntegratedMenus" gettext-domain="unity">
212− <key type="u" name="click-movement-threshold">
213− <default>15</default>
214− <range min="0" max="30"/>
215− <summary>Number of pixels to ignore on mouse pressure</summary>
216− <description>This value define how many pixels the user can move the mouse
217− when holding the mouse button, before we consider his action a movement
218− (to grab the window).</description>
219− </key>
220− <key type="u" name="double-click-wait">
221− <default>0</default>
222− <range min="0" max="300"/>
223− <summary>Milliseconds to wait before activating a menu after mouse release</summary>
224− <description>The number of ms to wait after a mouse button release event before considering
225− it a click. When this value is greater than 0, then it's possible to maximize
226− a window by double-clicking on its menus if the second click happens before the
227− specified value of ms is elapsed</description>
228− </key>
229− <key type="b" name="unfocused-windows-popup">
230− <default>true</default>
231− <summary>Whether to pop-up a menu when clicking over unfocused windows entries</summary>
232− <description>By disabling this setting you can make unity to only focus a window
233− when clicking over unfocused menu entries</description>
234− </key>
235− </schema>
236− <schema path="/com/canonical/unity/gestures/" id="com.canonical.Unity.Gestures" gettext-domain="unity">
237− <key type="b" name="launcher-drag">
238− <default>true</default>
239− <summary>Multi-touch gesture to reveal the launcher.</summary>
240− <description>When this is enabled, a 4 finger swipe from left to right will reveal launcher,
241− provided that the launcher is set to auto-hide.</description>
242− </key>
243− <key type="b" name="dash-tap">
244− <default>true</default>
245− <summary>Multi-touch gesture to open the dash.</summary>
246− <description>When this is enabled, a 4 finger tap will open the dash.</description>
247− </key>
248− <key type="b" name="windows-drag-pinch">
249− <default>true</default>
250− <summary>Multi-touch gestures to manage the windows.</summary>
251− <description>When this is enabled, 3 finger gestures such as drag, and pinch, will
252− help manage the windows.</description>
253− </key>
254− </schema>
255−</schemalist>
data/com.canonical.Unity8.gschema.xml+7−17
@@ -11,7 +11,7 @@
11 <summary>The usage mode.</summary>
11 <summary>The usage mode.</summary>
12 <description>The usage mode chosen will affect the Window Management behaviour.</description>
12 <description>The usage mode chosen will affect the Window Management behaviour.</description>
13 </key>
13 </key>
14− <key type="u" name="edge-barrier-sensitivity">
14+ <key type="y" name="edge-barrier-sensitivity">
15 <default>50</default>
15 <default>50</default>
16 <range min="1" max="100"/>
16 <range min="1" max="100"/>
17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
@@ -33,7 +33,7 @@
33 <description>How big (in grid units) the edge-drag sensitive area should be.</description>
33 <description>How big (in grid units) the edge-drag sensitive area should be.</description>
34 </key>
34 </key>
35 <key type="b" name="autohide-launcher">
35 <key type="b" name="autohide-launcher">
36− <default>false</default>
36+ <default>true</default>
37 <summary>Autohide the launcher</summary>
37 <summary>Autohide the launcher</summary>
38 <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
38 <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
39 </key>
39 </key>
@@ -43,26 +43,16 @@
43 <summary>Width of the launcher in grid units.</summary>
43 <summary>Width of the launcher in grid units.</summary>
44 <description>Changes the width of the launcher in all usage modes.</description>
44 <description>Changes the width of the launcher in all usage modes.</description>
45 </key>
45 </key>
46+ <key type="b" name="enable-launcher">
47+ <default>true</default>
48+ <summary>Enable or disable the launcher</summary>
49+ <description>Toggle the availability of the launcher</description>
50+ </key>
46 <key type="b" name="enable-indicator-menu">
51 <key type="b" name="enable-indicator-menu">
47 <default>true</default>
52 <default>true</default>
48 <summary>Enable or disable the indicator pull down menus</summary>
53 <summary>Enable or disable the indicator pull down menus</summary>
49 <description>Toggle the availability of the indicator pull down menus</description>
54 <description>Toggle the availability of the indicator pull down menus</description>
50 </key>
55 </key>
51− <key type="s" name="appstore-uri">
52− <default>'appid://openstore.openstore-team/openstore/current-user-version'</default>
53− <summary>The uri to the app store</summary>
54− <description>This will be used whenever the user triggers an action to open the app store.</description>
55− </key>
56− <key type="b" name="always-show-osk">
57− <default>false</default>
58− <summary>Force showing/hiding the OSK</summary>
59− <description>Toggle the visibility of the On Screen Keyboard unconditionally</description>
60− </key>
61− <key type="b" name="osk-switch-visible">
62− <default>false</default>
63− <summary>Whether the OSK switch should be visible</summary>
64− <description>Toggle the visibility of the OSK switch</description>
65− </key>
66 </schema>
56 </schema>
67
57
68 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
58 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
data/test.sensorsdeleted−12
@@ -1,12 +0,0 @@
1−create light 0 10 1
2−create accel 0 1000 0.1
3−create proximity
4−
5−200 proximity near
6−500 light 5
7−# simulate crash on the ground
8−500 accel 0.2 0.1 10
9−100 accel 0.2 0.2 1000
10−20 accel 0 0 0
11−10 proximity far
12−10 light 10
data/unity8-dash.confnew file+25
@@ -0,0 +1,25 @@
1+description "Unity Shell v8 Dash"
2+author "Michael Zanetti <michael.zanetti@canonical.com>"
3+
4+emits scope-ui-starting
5+
6+start on started unity8
7+stop on stopping unity8
8+
9+kill timeout 120
10+
11+# Focused app is 100 so we want to be less likely to get
12+# killed than the focused app but more than Unity8
13+
14+oom score 50
15+
16+respawn
17+respawn limit unlimited
18+
19+env APP_ID=unity8-dash
20+
21+pre-start script
22+ initctl emit scope-ui-starting
23+end script
24+
25+exec ${BINARY:-unity8-dash} $ARGS --desktop_file_hint=unity8-dash.desktop
data/unity8-dash.desktop.innew file+9
@@ -0,0 +1,9 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Scopes
4+Comment=An interface for using the Scopes system
5+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity8-dash
6+Terminal=false
7+Icon=@CMAKE_INSTALL_PREFIX@/@SHELL_APP_DIR@/Dash/unity8-dash.png
8+NoDisplay=true
9+X-Ubuntu-Touch=true
data/unity8-dash.pngnew file

Binary file not shown.

data/unity8-dash.svgnew file+326
@@ -0,0 +1,326 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:xlink="http://www.w3.org/1999/xlink"
11+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13+ viewBox="0 0 512 512"
14+ style="enable-background:new"
15+ inkscape:export-ydpi="180"
16+ inkscape:export-xdpi="180"
17+ inkscape:export-filename="app_shape02.png"
18+ sodipodi:docname="apps-scope.svg"
19+ inkscape:version="0.91+devel r"
20+ version="1.1"
21+ id="svg3336"
22+ height="512"
23+ width="512">
24+ <sodipodi:namedview
25+ inkscape:snap-global="false"
26+ fit-margin-bottom="18"
27+ fit-margin-right="0"
28+ fit-margin-left="0"
29+ fit-margin-top="18"
30+ inkscape:snap-grids="true"
31+ inkscape:guide-bbox="true"
32+ showguides="false"
33+ inkscape:snap-center="true"
34+ inkscape:snap-object-midpoints="true"
35+ inkscape:snap-midpoints="true"
36+ inkscape:snap-smooth-nodes="true"
37+ inkscape:snap-intersection-paths="true"
38+ inkscape:object-nodes="true"
39+ inkscape:object-paths="true"
40+ inkscape:snap-bbox-midpoints="true"
41+ inkscape:snap-bbox-edge-midpoints="true"
42+ inkscape:bbox-nodes="true"
43+ inkscape:bbox-paths="true"
44+ inkscape:snap-bbox="true"
45+ showborder="true"
46+ inkscape:showpageshadow="false"
47+ inkscape:snap-page="true"
48+ inkscape:window-maximized="1"
49+ inkscape:window-y="24"
50+ inkscape:window-x="0"
51+ inkscape:window-height="1029"
52+ inkscape:window-width="1920"
53+ showgrid="false"
54+ inkscape:current-layer="layer3"
55+ inkscape:document-units="px"
56+ inkscape:cy="204.04409"
57+ inkscape:cx="-384.5809"
58+ inkscape:zoom="0.64"
59+ inkscape:pageshadow="2"
60+ inkscape:pageopacity="0"
61+ borderopacity="1.0"
62+ bordercolor="#666666"
63+ pagecolor="#4f4f4f"
64+ id="base">
65+ <inkscape:grid
66+ type="xygrid"
67+ id="grid811"
68+ originx="0"
69+ originy="15.999999"
70+ visible="true"
71+ enabled="true" />
72+ <sodipodi:guide
73+ orientation="1,0"
74+ position="104,176"
75+ id="guide819" />
76+ <sodipodi:guide
77+ orientation="1,0"
78+ position="120,160"
79+ id="guide821" />
80+ <sodipodi:guide
81+ orientation="1,0"
82+ position="392,144"
83+ id="guide823" />
84+ <sodipodi:guide
85+ orientation="1,0"
86+ position="408,144"
87+ id="guide825" />
88+ <sodipodi:guide
89+ orientation="0,1"
90+ position="328,408"
91+ id="guide827" />
92+ <sodipodi:guide
93+ orientation="0,1"
94+ position="336,392"
95+ id="guide829" />
96+ <sodipodi:guide
97+ orientation="0,1"
98+ position="176,120"
99+ id="guide831" />
100+ <sodipodi:guide
101+ orientation="0,1"
102+ position="216,104"
103+ id="guide833" />
104+ <inkscape:grid
105+ type="axonomgrid"
106+ id="grid835"
107+ units="px"
108+ empspacing="60"
109+ gridanglex="42.9"
110+ gridanglez="42.9"
111+ spacingy="3.522px"
112+ enabled="false"
113+ originx="0"
114+ originy="16.999996" />
115+ <sodipodi:guide
116+ orientation="0,1"
117+ position="344,376"
118+ id="guide4126" />
119+ <sodipodi:guide
120+ orientation="0,1"
121+ position="160,136"
122+ id="guide4128" />
123+ <sodipodi:guide
124+ orientation="1,0"
125+ position="136,96"
126+ id="guide4130" />
127+ <sodipodi:guide
128+ orientation="1,0"
129+ position="376,136"
130+ id="guide4134" />
131+ <sodipodi:guide
132+ orientation="-0.70710678,0.70710678"
133+ position="544,544"
134+ id="guide4136" />
135+ <sodipodi:guide
136+ orientation="1,0"
137+ position="256,-32.000001"
138+ id="guide4138" />
139+ <sodipodi:guide
140+ orientation="0,1"
141+ position="544,256"
142+ id="guide4140" />
143+ <sodipodi:guide
144+ orientation="0.70710678,0.70710678"
145+ position="544,-32.000001"
146+ id="guide4142" />
147+ <sodipodi:guide
148+ orientation="0,1"
149+ position="248,15.999999"
150+ id="guide4152" />
151+ <sodipodi:guide
152+ orientation="0,1"
153+ position="336,496"
154+ id="guide4154" />
155+ <sodipodi:guide
156+ position="344,96"
157+ orientation="1,0"
158+ id="guide4361" />
159+ <sodipodi:guide
160+ position="576,168"
161+ orientation="0,1"
162+ id="guide4363" />
163+ <sodipodi:guide
164+ position="168,192"
165+ orientation="1,0"
166+ id="guide4229" />
167+ <sodipodi:guide
168+ position="312,344"
169+ orientation="0,1"
170+ id="guide4233" />
171+ <sodipodi:guide
172+ position="180.48,-96"
173+ orientation="0,1"
174+ id="guide4235" />
175+ </sodipodi:namedview>
176+ <defs
177+ id="defs3338">
178+ <linearGradient
179+ inkscape:collect="always"
180+ id="linearGradient4203">
181+ <stop
182+ style="stop-color:#ea5420;stop-opacity:1"
183+ offset="0"
184+ id="stop4205" />
185+ <stop
186+ style="stop-color:#f37e40;stop-opacity:1"
187+ offset="1"
188+ id="stop4207" />
189+ </linearGradient>
190+ <clipPath
191+ clipPathUnits="userSpaceOnUse"
192+ id="clipPath4755">
193+ <path
194+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.24899998;fill:#5e2c73;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
195+ d="M 360,50 594,284 V 215.89844 C 594,70.73665 573.2426,50 427.94531,50 Z"
196+ id="path4757"
197+ inkscape:connector-curvature="0" />
198+ </clipPath>
199+ <clipPath
200+ clipPathUnits="userSpaceOnUse"
201+ id="clipPath4767">
202+ <path
203+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f6f6f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
204+ d="M 543.8125,454.1875 312.18945,685.81055 367.94531,681 C 512.70468,668.50896 526.55393,654.72881 539,510.10156 Z"
205+ id="path4769"
206+ inkscape:connector-curvature="0" />
207+ </clipPath>
208+ <linearGradient
209+ inkscape:collect="always"
210+ xlink:href="#linearGradient4203"
211+ id="linearGradient4209"
212+ x1="167.5"
213+ y1="17.25"
214+ x2="343.25"
215+ y2="491"
216+ gradientUnits="userSpaceOnUse" />
217+ <filter
218+ inkscape:collect="always"
219+ style="color-interpolation-filters:sRGB"
220+ id="filter4220"
221+ x="-0.012"
222+ width="1.024"
223+ y="-0.012"
224+ height="1.024">
225+ <feGaussianBlur
226+ inkscape:collect="always"
227+ stdDeviation="1.4390401"
228+ id="feGaussianBlur4222" />
229+ </filter>
230+ <linearGradient
231+ inkscape:collect="always"
232+ xlink:href="#linearGradient4226"
233+ id="linearGradient4232"
234+ x1="255.99998"
235+ y1="-255.99998"
236+ x2="405.35773"
237+ y2="-255.99998"
238+ gradientUnits="userSpaceOnUse"
239+ spreadMethod="reflect" />
240+ <linearGradient
241+ inkscape:collect="always"
242+ id="linearGradient4226">
243+ <stop
244+ style="stop-color:#a73812;stop-opacity:1"
245+ offset="0"
246+ id="stop4228" />
247+ <stop
248+ style="stop-color:#973310;stop-opacity:0"
249+ offset="1"
250+ id="stop4230" />
251+ </linearGradient>
252+ <filter
253+ inkscape:collect="always"
254+ style="color-interpolation-filters:sRGB"
255+ id="filter4234"
256+ x="-0.096000001"
257+ width="1.192"
258+ y="-0.096000001"
259+ height="1.192">
260+ <feGaussianBlur
261+ inkscape:collect="always"
262+ stdDeviation="11.512321"
263+ id="feGaussianBlur4236" />
264+ </filter>
265+ </defs>
266+ <metadata
267+ id="metadata3341">
268+ <rdf:RDF>
269+ <cc:Work
270+ rdf:about="">
271+ <dc:format>image/svg+xml</dc:format>
272+ <dc:type
273+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
274+ <dc:title></dc:title>
275+ </cc:Work>
276+ </rdf:RDF>
277+ </metadata>
278+ <g
279+ inkscape:groupmode="layer"
280+ id="layer3"
281+ inkscape:label="Background">
282+ <path
283+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient4209);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
284+ d="M 0 0 L 0 183.89844 L 0 328.10156 L 0 512 L 512 512 L 512 328.10156 L 512 183.89844 L 512 0 L 0 0 z "
285+ id="rect4158" />
286+ <path
287+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
288+ d="M 0 256 L 0 328.10156 L 0 462.53516 C 0 479.69677 0.052846476 496.03174 0.13085938 512 L 511.86914 512 C 511.94715 496.03174 512 479.69677 512 462.53516 L 512 256 L 0 256 z "
289+ id="rect4286" />
290+ </g>
291+ <g
292+ inkscape:groupmode="layer"
293+ id="layer1"
294+ inkscape:label="Pictogram"
295+ style="display:inline"
296+ transform="translate(-32,-32)">
297+ <circle
298+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.4;fill:#d04616;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.99999952;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter:url(#filter4220);enable-background:accumulate"
299+ id="circle4218"
300+ cx="258"
301+ cy="-256"
302+ r="143.90401"
303+ transform="rotate(90,-7.1132638e-7,31.999996)" />
304+ <circle
305+ transform="rotate(90,-7.1132638e-7,31.999996)"
306+ r="143.90401"
307+ cy="-256"
308+ cx="258"
309+ id="circle4224"
310+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient4232);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.99999952;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter:url(#filter4234);enable-background:accumulate" />
311+ <circle
312+ transform="rotate(90)"
313+ r="143.90401"
314+ cy="-288"
315+ cx="288"
316+ id="circle4206"
317+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.99999952;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
318+ <path
319+ style="display:inline;fill:#ea5420;fill-opacity:1;stroke-width:2.9398191;enable-background:new"
320+ id="path4258"
321+ d="m 193.9963,269.54024 c -10.19878,0 -18.46137,8.2634 -18.46137,18.46139 0,10.19309 8.26259,18.45568 18.46137,18.45568 10.19311,0 18.45569,-8.26259 18.45569,-18.45568 0,-10.19799 -8.26258,-18.46139 -18.45569,-18.46139 z m 131.78525,83.88906 c -8.82832,5.09898 -11.85536,16.38129 -6.75557,25.20475 5.0933,8.82834 16.37561,11.85455 25.20393,6.75556 8.82752,-5.0933 11.85457,-16.37561 6.75559,-25.20475 -5.0933,-8.82263 -16.38212,-11.84887 -25.20395,-6.75556 z m -91.69319,-65.42767 c 0,-18.24028 9.05999,-34.35498 22.92309,-44.11321 l -13.49406,-22.6012 c -16.14883,10.79461 -28.16435,27.28971 -33.15766,46.60863 5.82648,4.75434 9.55584,11.99194 9.55584,20.10497 0,8.10813 -3.72936,15.34572 -9.55584,20.10006 4.98681,19.32463 17.00232,35.82055 33.15766,46.61514 l 13.49406,-22.60689 c -13.8631,-9.75253 -22.92309,-25.86641 -22.92309,-44.1075 z m 53.91207,-53.91776 c 28.16514,0 51.27274,21.59491 53.69828,49.13495 l 26.30048,-0.38772 c -1.29405,-20.33173 -10.17604,-38.58421 -23.82372,-52.00594 -7.01814,2.65149 -15.12464,2.2459 -22.13139,-1.79314 -7.01894,-4.0504 -11.41969,-10.88319 -12.62271,-18.30044 -6.8214,-1.88254 -14.00046,-2.91323 -21.42257,-2.91323 -12.75925,0 -24.82271,2.99695 -35.53359,8.29836 l 12.82509,22.98243 c 6.89944,-3.21075 14.5963,-5.01526 22.71013,-5.01526 z m 0,107.82982 c -8.11383,0 -15.81069,-1.80533 -22.70931,-5.01528 l -12.82511,22.98163 c 10.71088,5.3079 22.77434,8.30568 35.53442,8.30568 7.42211,0 14.60118,-1.0315 21.42177,-2.91975 1.20301,-7.41724 5.60537,-14.24352 12.6227,-18.30125 7.01161,-4.04555 15.11326,-4.44382 22.13137,-1.79232 13.64769,-13.42174 22.52968,-31.67421 23.82372,-52.00595 l -26.30696,-0.38772 c -2.41986,27.54738 -25.52665,49.13496 -53.6926,49.13496 z m 37.77461,-119.35113 c 8.82834,5.09818 20.11145,2.07845 25.20475,-6.74987 5.099,-8.82833 2.07928,-20.11145 -6.74988,-25.21126 -8.82832,-5.0933 -20.11063,-2.06705 -25.21125,6.76127 -5.09247,8.82345 -2.06625,20.10657 6.75638,25.19986 z"
322+ inkscape:connector-curvature="0"
323+ inkscape:transform-center-x="16.232534"
324+ inkscape:transform-center-y="-0.0024900663" />
325+ </g>
326+</svg>
data/unity8-dash.url-dispatchernew file+6
@@ -0,0 +1,6 @@
1+[
2+ {
3+ "protocol": "scope"
4+ }
5+]
6+
data/unity8-greeter-wrapper+4−7
@@ -49,12 +49,9 @@ if which ubuntu-touch-session >/dev/null; then
49 TOUCH_WRAPPER=ubuntu-touch-session
49 TOUCH_WRAPPER=ubuntu-touch-session
50fi
50fi
51
51
52−# Advertise as a unity8 session, so that indicator-network will start.
52+# Pretend that we're in an ubuntu-touch session, so that indicator-network
53−export XDG_SESSION_DESKTOP=unity8
53+# will start.
54−export DESKTOP_SESSION=$XDG_SESSION_DESKTOP
54+export DESKTOP_SESSION=ubuntu-touch
55−
56−set_greeter_var QT_IM_MODULE maliitphablet
57−set_greeter_var QT_QPA_PLATFORM ubuntumirclient
58
55
59# We disable ofono using pulse. It causes problems with racing with the user's
56# We disable ofono using pulse. It causes problems with racing with the user's
60# pulse. We need to come up with a better long-term fix for this, because we
57# pulse. We need to come up with a better long-term fix for this, because we
@@ -103,7 +100,7 @@ if [ "$(id -u phablet 2>/dev/null)" = "32011" ]; then
103fi
100fi
104
101
105# And finally actually start the greeter
102# And finally actually start the greeter
106−exec env MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
103+exec env QT_QPA_PLATFORM=ubuntumirclient MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
107CMD_PID=$!
104CMD_PID=$!
108wait $CMD_PID
105wait $CMD_PID
109CMD_PID=
106CMD_PID=
data/unity8.conf+34−35
@@ -2,7 +2,6 @@ description "Unity Shell v8"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
2author "Ricardo Mendoza <ricmm@ubuntu.com>"
3
3
4emits indicator-services-start
4emits indicator-services-start
5−emits indicator-services-end
6
5
7start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=unity8-mir) or (xsession SESSION=unity8)) and started dbus
6start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=unity8-mir) or (xsession SESSION=unity8)) and started dbus
8stop on desktop-end
7stop on desktop-end
@@ -21,32 +20,28 @@ env QML_NO_TOUCH_COMPRESSION=1
21respawn
20respawn
22expect stop
21expect stop
23
22
24−# FIXME Create an autopilot test that makes sure start+stop and restart
25−# work fine at least 2 times
26−
27pre-start script
23pre-start script
28 # Tell unity-mir to raise SIGSTOP after we start
24 # Tell unity-mir to raise SIGSTOP after we start
29 initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
25 initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
30
26
27+ if [ -n "$MIR_SOCKET" ]; then
28+ # FIXME Create an autopilot test that makes sure start+stop and restart
29+ # work fine at least 2 times
31− # Save original value of MIR_SOCKET so that we can restore it when stopped,
30+ # Save original value of MIR_SOCKET in case we are stopped,
32− # as we modify the variable for future jobs, including ourself.
31+ # as we modify the variable for future jobs, including ourself.
32+ UNITY_MIR_SOCKET=$(initctl get-env --global MIR_SOCKET)
33− initctl set-env UNITY_MIR_SOCKET=$MIR_SOCKET
33+ initctl set-env --global UNITY_MIR_SOCKET=$UNITY_MIR_SOCKET
34
34
35− # Decide where we are going to put our own socket file
35+ # Point unity8 at unity-system-compositor
36− if [ -n "$SNAP" ]; then
37− # In snappy, we want to hard code our path because our apparmor profile
38− # only lets us put the socket in one place. And consumers expect it
39− # there.
40− MIR_SERVER_FILE=/run/user/$(id -u)/mir_socket
41− else
42 MIR_SERVER_FILE=$XDG_RUNTIME_DIR/mir_socket
36 MIR_SERVER_FILE=$XDG_RUNTIME_DIR/mir_socket
43− fi
37+ initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
44− initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
38+ initctl set-env MIR_SERVER_HOST_SOCKET=$UNITY_MIR_SOCKET
45
39
46− # Point all future jobs in this session to our Mir socket instead of
40+ # Point all future jobs in this session to our Mir socket instead of
47− # unity-system-compositor's socket.
41+ # unity-system-compositor's socket.
48− initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
42+ initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
49− gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
43+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
44+ fi
50
45
51 # Remove the normal and trusted sockets if still there
46 # Remove the normal and trusted sockets if still there
52 if [ -S "$MIR_SERVER_FILE" ]; then
47 if [ -S "$MIR_SERVER_FILE" ]; then
@@ -59,14 +54,11 @@ pre-start script
59
54
60 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
55 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
61
56
62− # Disable Qt's stuttering 'touch compression' to fix scrolling smoothness
57+ #
63− # issues (LP: #1486341, LP: #1556763). As a bonus, this eliminates most of
58+ # Mir's input resampling is deprecated and going away soon. Turn it off
64− # the lag seen in the indicator panel pull-down (LP: #1488327) and also
59+ # so we don't get a surprise change in behaviour when that happens.
65− # reduces lag seen in apps:
60+ #
66− initctl set-env --global QML_NO_TOUCH_COMPRESSION=1
67−
68− # Workaround for text not rendering correctly
69− initctl set-env --global QT_ENABLE_GLYPH_CACHE_WORKAROUND=1
61+ initctl set-env --global MIR_CLIENT_INPUT_RATE=0
70
62
71 if [ "$XDG_SESSION_DESKTOP" = "ubuntu-touch" ]; then
63 if [ "$XDG_SESSION_DESKTOP" = "ubuntu-touch" ]; then
72 # On Ubuntu Touch, we currently use a trick where we auto-login the
64 # On Ubuntu Touch, we currently use a trick where we auto-login the
@@ -77,23 +69,30 @@ pre-start script
77 else
69 else
78 initctl set-env MODE=full-shell
70 initctl set-env MODE=full-shell
79 fi
71 fi
80−
81− # HACK! WORKAROUND FOR HALIUM MISSING UBUNTU_PLATFORM_API
82− if [ ! -f /system/lib/libubuntu_application_api.so ]; then
83− initctl set-env --global UBUNTU_PLATFORM_API_BACKEND=test.so.3
84− initctl set-env --global UBUNTU_PLATFORM_API_SENSOR_TEST=/etc/ubuntusensors/test.sensors
85− fi
86end script
72end script
87
73
88exec ${BINARY:-unity8} --mode=$MODE $ARGS
74exec ${BINARY:-unity8} --mode=$MODE $ARGS
89
75
90post-start script
76post-start script
77+ # If no MIR_SOCKET was defined on launch, we try to set one here
78+ if [ -z "$(initctl get-env --global UNITY_MIR_SOCKET)" ]; then
79+ if [ -S "$XDG_RUNTIME_DIR/mir_socket" ]; then
80+ mir_socket=$XDG_RUNTIME_DIR/mir_socket
81+ elif [ -S "/tmp/mir_socket" ]; then
82+ mir_socket=/tmp/mir_socket
83+ fi
84+
85+ if [ -n "$mir_socket" ]; then
86+ initctl set-env --global MIR_SOCKET="$mir_socket"
87+ fi
88+ fi
89+
91 initctl emit --no-wait indicator-services-start
90 initctl emit --no-wait indicator-services-start
92end script
91end script
93
92
94post-stop script
93post-stop script
95 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
94 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
95+ initctl unset-env --global UNITY_MIR_SOCKET
96 initctl unset-env --global MIR_SERVER_PROMPT_FILE
96 initctl unset-env --global MIR_SERVER_PROMPT_FILE
97 initctl emit application-end
97 initctl emit application-end
98− initctl emit indicator-services-end
99end script
98end script
debian/changelog+20−341
@@ -1,319 +1,3 @@
1−unity8 (8.20+ubports) xenial; urgency=medium
2−
3− * Replace dependency on ubuntu-wallpapers with ubports-wallpapers
4−
5− -- Dalton Durst <dalton@ubports.com> Fri, 5 Oct 2018 13:28:20 -0500
6−
7−unity8 (8.17+ubports3) xenial; urgency=medium
8−
9− * Imported to UBports
10−
11− -- UBports auto importer <infra@ubports.com> Mon, 31 Jul 2017 03:12:43 +0200
12−
13−unity8 (8.15+17.04.20170404.7-0ubuntu2) zesty; urgency=medium
14−
15− [ Michael Zanetti ]
16− * Make the default store uri point to gnome software center
17−
18− -- Timo Jyrinki <timo-jyrinki@ubuntu.com> Thu, 06 Apr 2017 10:49:29 +0300
19−
20−unity8 (8.15+17.04.20170404.7-0ubuntu1) zesty; urgency=medium
21−
22− [ Albert Astals Cid ]
23− * Tweak app drawer a bit (LP: #1667570)
24−
25− [ Josh Arenson ]
26− * Make some small changes to the greeter's session list
27− * Handle a user in the greeter having never selected a session better
28− (LP: #1673199)
29−
30− [ Lukáš Tinkl ]
31− * Do not occlude windows with an ongoing unmaximize transition (LP:
32− #1666363)
33− * Show and implement close buttons for child windows (LP: #1668053)
34− * Sanitize the logic for pointer vs. touch menus, fixes hiding the
35− window title in staged mode, when hovering the panel with mouse and
36− no menus available.
37−
38− [ Michael Zanetti ]
39− * Don't hide the launcher on super press if it's locked visible (LP:
40− #1675373)
41− * fix searchfield selection in drawer (LP: #1677259)
42− * make sure the stage has focus when going to spread (LP: #1672053,
43− #1672673, #1676995)
44− * don't autostart the dash app, but show its .desktop file instead
45−
46− -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 04 Apr 2017 22:56:06 +0000
47−
48−unity8 (8.15+17.04.20170328.3-0ubuntu1) zesty; urgency=medium
49−
50− [ Albert Astals Cid ]
51− * mock: Remove empty property and move invokable
52− * Tune quicklist item selection
53− * Fix unminimizing going to the wrong position the second time (LP:
54− #1671458)
55− * Remove unclickable gaps on the menubar (LP: #1672722)
56− * indicators client is a tool
57− * Make sure we destroy the popups when the item goes away (LP:
58− #1670338)
59− * UnityApplicationMocks: Initialize m_state and m_requestedState
60− * Don't use appInfo after checking it if is null
61− * Initialize m_privateMode
62− * Hook up aboutToShow for overflow menus (LP: #1676016)
63−
64− [ Daniel d'Andrada ]
65− * Give active focus to child surface qml items (LP: #1671072)
66− * Satellite child windows (LP: #1673415)
67− * Tell qtmir/miral about the available desktop area
68−
69− [ Florian Boucault ]
70− * WindowStateStorage: use a private QThreadPool to ensure that
71− WindowStateStorage::saveValue always has a thread available to
72− execute the query in. (LP: #1675424)
73−
74− [ Lukáš Tinkl ]
75− * Protect against loading invalid window geometry (LP: #1674262)
76− * Remove usage of the deprecated (and non-functional) system-image-
77− dbus service.
78− * Implement Ctrl+Alt+T to launch the terminal app (LP: #1673500)
79− * Only take normal and dialog surface types into account for launcher
80− items (LP: #1669047)
81− * Fix the shutdown dialog after recent refactoring in
82− DBusUnitySessionService (LP: #1676426)
83−
84− [ Michael Zanetti ]
85− * drop the grey background behind icons in the drawer (LP: #1675688)
86−
87− [ Pete Woods ]
88− * Fix Unity/Platform::isPC, and add tests (LP: #1670657)
89−
90− -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 28 Mar 2017 21:50:20 +0000
91−
92−unity8 (8.15+17.04.20170321-0ubuntu1) zesty; urgency=medium
93−
94− [ Albert Astals Cid ]
95− * Signal aboutToShow (LP: #1664578)
96− * Support Panel top level items to be disabled (LP: #1670694)
97− * Improve Launcher ←→ touch menu interaction (LP: #1667620, #1671069)
98− * Fix real world submenus (e.g. kate) not getting their first item
99− selected on open (LP: #1666859)
100−
101− [ Daniel d'Andrada ]
102− * Really disable the window decoration when in staged mode (LP:
103− #1670361)
104− * Don't let clients resize their surfaces while in staged
105− (phone/tablet) mode (LP: #1670390)
106− * TopLevelWindowModel: don't put hidden windows in the model (LP:
107− #1665286)
108−
109− [ Lukáš Tinkl ]
110− * Reset always-show-osk gsetting on startup to default value (false
111− atm)
112− * Fix the restored-to position with Miral due to the state changes
113− being async (LP: #1669819)
114− * Add a cursor name fallback mapping "grabbing" -> "closedhand" for
115− Breeze
116− * Fix unsnapping a maximized window from the panel (LP: #1671721)
117− * Disable altDrag feature outside windowed mode
118−
119− [ Michael Terry ]
120− * Don't lock the screen for guest users or users in the nopasswdlogin
121− group. (LP: #1644237)
122− * Support GNOME-style logout DBus API (making the Logout, Reboot, and
123− Shutdown launcher commands work) (LP: #1673229)
124−
125− [ Michael Zanetti ]
126− * Add support for closing apps from the spread with "Q" (LP: #1670327)
127− * hide "private" launcher quicklist entries when the greeter is locked
128− (LP: #1667649)
129− * add surface titles to launcher's quicklist (LP: #1661668)
130− * properly reset the drawer state when cancelling a horizontal drag
131− (LP: #1669536)
132− * fix the focus moving correctly between launcher and drawer (LP:
133− #1669880)
134− * unfocus the drawer's textfield when it is moved (LP: #1669839)
135−
136− [ Pete Woods ]
137− * Fix up indicators-client after refactoring (LP: #1672797)
138−
139− -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 21 Mar 2017 10:58:13 +0000
140−
141−unity8 (8.15+17.04.20170308-0ubuntu1) zesty; urgency=medium
142−
143− [ Albert Astals Cid ]
144− * Let's follow the keyboard order
145− * Enable the license check (LP: #1590044)
146− * Show a barebones error message if loading the QML doesn't work
147− * Make sure cursor is back to normal when closing the window (LP:
148− #1666158)
149− * Fix small warning when sensitive is undefined
150− * Remove unused member variable
151− * Initialize m_msecsSinceReference
152− * Add warning if registerService fails
153− * Move menus Component {} out of the repeater
154− * Add tool to browse menus of a running app
155−
156− [ Daniel d'Andrada ]
157− * Drag child windows with Alt+LeftMouseButton (LP: #1664947)
158−
159− [ Gerry Boland ]
160− * TopLevelWindowModel: connect to the OSK surface to know when it goes
161− away so we can clean up after it. (LP: #1670681)
162−
163− [ Josh Arenson ]
164− * Initialize sessionMode to single when mock is reset (LP: #1667463)
165−
166− [ Lukáš Tinkl ]
167− * Make the menu string "Back" translatable
168− * Let the OSK be driven by a switch in indicator-keyboard (LP:
169− #1521518)
170− * Disable the tutorial when there's no touchscreen (LP: #1661557)
171− * Shell chrome fixes (LP: #1658117, #1665723, #1665724, #1669010)
172− * Cancel the drag as soon as we're entering the spread (LP: #1668642)
173− * Fix being unable to use window control buttons or menus with touch
174− (LP: #1667604, #1668387)
175−
176− [ Michael Terry ]
177− * Set QT_IM_MODULE in the greeter so that the OSK can come up. (LP:
178− #1670383)
179− * Simplify our startup handling of Mir environment variables and set
180− the right socket path in snappy.
181−
182− [ Michael Zanetti ]
183− * Cancel the home key activation if something else is pressed along
184− with Meta (LP: #1670678)
185− * close the drawer when something is launched from the launcher (LP:
186− #1660367)
187− * use a svg instead of a png for the Launcher's BFB (LP: #1668057)
188− * change the default setting for the launcher autohiding (LP:
189− #1670655)
190−
191− [ Nick Dedekind ]
192− * Split up Shell::test_spreadDisabled to ensure initial state for each
193− test.
194−
195− -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 08 Mar 2017 09:56:46 +0000
196−
197−unity8 (8.15+17.04.20170221-0ubuntu1) zesty; urgency=medium
198−
199− * Handle ubuntu-app-launch API/ABI break
200−
201− -- Ken VanDine <ken.vandine@canonical.com> Tue, 21 Feb 2017 13:23:23 +0000
202−
203−unity8 (8.15+17.04.20170216.1-0ubuntu1) zesty; urgency=medium
204−
205− [ Albert Astals Cid ]
206− * Make menus items close the menu when clicking on them (LP: #1657082,
207− #1657399)
208− * Clicking on an open menu closes it + test
209− * Make the menus and submenus do not go outside the screen when
210− popping out
211− * Auto open submenus on hover (LP: #1657085)
212− * Make the double click on a menu not be maximize the window below
213− (LP: #1657079)
214− * Make the MenuBar InverseMouseArea eat hover events when there's a
215− popup open (LP: #1657763)
216− * Make double click on the window decoration maximize (LP: #1657758)
217− * Eat hover events when the launcher quicklist is open (LP: #1640776)
218− * Remove TODO now that we require Qt > 5.5
219− * Serialize two make targets that want to cp to the same target file
220− (LP: #1660576)
221− * Remove variable that is always false (LP: #1585910)
222−
223− [ Daniel d'Andrada ]
224− * Consolidate launcher API checks
225−
226− [ Lukáš Tinkl ]
227− * Fixes for activating minimized windows and restoring fullscreen ones
228− (LP: #1656808, #1658937, #1658938)
229−
230− [ Michael Zanetti ]
231− * move right edge push area up some levels so it can be used on top of
232− the indicators
233− * fix minimizing/restoring transitions (LP: #1658936)
234− * fix some glitches with spread positioning
235− * fix jumpy animation when closing an item from the spread
236− * Show the wallpaper while the focused app is moving in staged mode
237− (LP: #1648251)
238− * Update the tutorial to mention the app drawer instead of the dash on
239− long left edge swipe (LP: #1658932)
240− * prevent hiding the launcher when the mouse hover event is eaten by
241− the EdgePushArea (LP: #1657045)
242− * properly invalidate the whole model (LP: #1658190)
243− * stabilize OrientedShell test (LP: #1658994)
244−
245− [ Nick Dedekind ]
246− * Added overflow support to application menus.
247− * Updated menu colors
248−
249− -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 16 Feb 2017 13:49:18 +0000
250−
251−unity8 (8.15+17.04.20170206-0ubuntu1) zesty; urgency=medium
252−
253− [ Daniel d'Andrada ]
254− * Initial support for child windows (menus, dialogs, tooltips) (LP:
255− #1543467, #1591384, #1656727)
256−
257− -- Albert Astals Cid <albert.astals@canonical.com> Mon, 06 Feb 2017 09:12:23 +0000
258−
259−unity8 (8.15+17.04.20170131.1-0ubuntu1) zesty; urgency=medium
260−
261− [ Rodney Dawes ]
262− * Remove dependencies on clickscope.
263−
264− -- Albert Astals Cid <albert.astals@canonical.com> Tue, 31 Jan 2017 14:40:33 +0000
265−
266−unity8 (8.15+17.04.20170124-0ubuntu1) zesty; urgency=medium
267−
268− [ Albert Astals Cid ]
269− * Limit tab-focus travelling on dialogs with a fence
270− * Restore focus to where it was when our ShellDialogs get unloaded
271− * Update current session after changing the user
272− * Add keyboard navigation for Indicators
273− * a window -> the current window
274− * There's no spreadDelegate_ anymore
275−
276− [ Daniel d'Andrada ]
277− * Simplify DecoratedWindow
278− * Remove unnecessary warning message
279−
280− [ Josh Arenson ]
281− * Add a test for the session chooser icon in the greeter's sessions
282− list
283−
284− [ Lukáš Tinkl ]
285− * Fix keymap not being applied on the shell itself (LP: #1626435)
286− * Shell dialog improvements (kbd focus, mouse eater)
287− * Start searching directly as you type, w/o having to first
288− focus/click the search field.
289− * Add a test for the real implementation of WindowStateStorage
290− * Use a four finger gesture to open the drawer, much like in u7
291−
292− [ Michael Terry ]
293− * Simplify the lightdm mock to make future greeter improvements easier
294− to test.
295− * Add support for guest sessions in unity8-greeter.
296− * Use a model for PAM prompts, supporting more possible interactions.
297− * Fix grouping of autopkg output and allow optionally passing
298− arguments to installed test scripts.
299− * Add support for LightDM hints for manual logins and hiding normal
300− users.
301−
302− [ Michael Zanetti ]
303− * hint the launcher to indicate a successful size change to the user
304− (LP: #1646457)
305− * Improvements for the appdrawer (LP: #1648173)
306− * Adjust home key to still focus the dash instead of messing with the
307− drawer
308− * allow 4 finger simulation with mousetouchadaptor
309−
310− [ Nick Dedekind ]
311− * Added Alt+F10 shortcut to open app menus. (LP: #1656896)
312− * Fixed menu layout width calculations. (LP: #1657050)
313− * Skip Panel::test_drag_indicator_item_down_shows_menu
314−
315− -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 24 Jan 2017 07:46:58 +0000
316−
317unity8 (8.15+17.04.20170110.4-0ubuntu1) zesty; urgency=medium
1unity8 (8.15+17.04.20170110.4-0ubuntu1) zesty; urgency=medium
318
2
319 [ Albert Astals Cid ]
3 [ Albert Astals Cid ]
@@ -1224,7 +908,7 @@ unity8 (8.12+16.04.20160330-0ubuntu1) xenial; urgency=medium
1224unity8 (8.12+16.04.20160323.2-0ubuntu1) xenial; urgency=medium
908unity8 (8.12+16.04.20160323.2-0ubuntu1) xenial; urgency=medium
1225
909
1226 [ Michael Terry ]
910 [ Michael Terry ]
1227− *
911+ *
1228 * Fix setting OSK layout in OOBE wizard
912 * Fix setting OSK layout in OOBE wizard
1229 * Stop the left edge tutorial from being shown when the bottom edge
913 * Stop the left edge tutorial from being shown when the bottom edge
1230 tutorial wants to be shown after receiving a call.
914 tutorial wants to be shown after receiving a call.
@@ -3936,7 +3620,7 @@ unity8 (8.00+14.10.20140729-0ubuntu1) utopic; urgency=medium
3936 * Re-architecture unity8 to use the QtMirCompositor library so that
3620 * Re-architecture unity8 to use the QtMirCompositor library so that
3937 the Qt scenegraph renderer is used as the Mir compositor, and
3621 the Qt scenegraph renderer is used as the Mir compositor, and
3938 application surfaces are added to the QML scene as items.
3622 application surfaces are added to the QML scene as items.
3939−
3623+
3940 [ Michael Zanetti ]
3624 [ Michael Zanetti ]
3941 * Port phone right-edge spread code to use QtCompositor
3625 * Port phone right-edge spread code to use QtCompositor
3942 * Add right-edge spread animation for tablet
3626 * Add right-edge spread animation for tablet
@@ -4210,8 +3894,8 @@ unity8 (7.90+14.10.20140703.1-0ubuntu1) utopic; urgency=low
4210
3894
4211unity8 (7.90+14.10.20140701.2-0ubuntu2) utopic; urgency=medium
3895unity8 (7.90+14.10.20140701.2-0ubuntu2) utopic; urgency=medium
4212
3896
4213− * debian/control:
3897+ * debian/control:
4214− list qtdeclarative5-ubuntu-ui-toolkit-plugin-gles as an alternative
3898+ list qtdeclarative5-ubuntu-ui-toolkit-plugin-gles as an alternative
4215 choice, since provides are not versionned, should restore installability
3899 choice, since provides are not versionned, should restore installability
4216 on amd64 and i386
3900 on amd64 and i386
4217
3901
@@ -7313,7 +6997,7 @@ unity8 (7.81.2) saucy; urgency=low
7313 [ Michał Sawicz ]
6997 [ Michał Sawicz ]
7314 * Fix icons in ApplicationsFilterGrid.qml.
6998 * Fix icons in ApplicationsFilterGrid.qml.
7315 * Support flipped image in run_on_device.
6999 * Support flipped image in run_on_device.
7316−
7000+
7317 [ Michael Zanetti ]
7001 [ Michael Zanetti ]
7318 * Don't clear lockscreen when it's fading out.
7002 * Don't clear lockscreen when it's fading out.
7319 * Reworked Launcher folding.
7003 * Reworked Launcher folding.
@@ -7398,7 +7082,7 @@ qml-phone-shell (1.79) raring; urgency=low
7398
7082
7399 [ Michael Terry ]
7083 [ Michael Terry ]
7400 * Make greeter look like the desktop one
7084 * Make greeter look like the desktop one
7401−
7085+
7402 [ Gerry Boland ]
7086 [ Gerry Boland ]
7403 * Fix a bug where a minimized app gets focus after closing another app
7087 * Fix a bug where a minimized app gets focus after closing another app
7404 * Applied a workaround to reduce flickering when launching apps
7088 * Applied a workaround to reduce flickering when launching apps
@@ -7414,7 +7098,7 @@ qml-phone-shell (1.79) raring; urgency=low
7414qml-phone-shell (1.78) raring; urgency=low
7098qml-phone-shell (1.78) raring; urgency=low
7415
7099
7416 [ Sergio Schvezov ]
7100 [ Sergio Schvezov ]
7417− * Replacing the music and ski safari mock apps with calendar and weather in
7101+ * Replacing the music and ski safari mock apps with calendar and weather in
7418 the launcher (LP: #1178262).
7102 the launcher (LP: #1178262).
7419
7103
7420 [ Daniel d'Andrada ]
7104 [ Daniel d'Andrada ]
@@ -7456,7 +7140,7 @@ qml-phone-shell (1.77) raring; urgency=low
7456 [ Mathieu Trudel-Lapierre ]
7140 [ Mathieu Trudel-Lapierre ]
7457 * debian/control:
7141 * debian/control:
7458 - Drop indicators-client-plugin* Depends for qml-phone-shell to Recommends.
7142 - Drop indicators-client-plugin* Depends for qml-phone-shell to Recommends.
7459− - Add/update Vcs-Browser, Vcs-Bzr and add a notice to uploaders.
7143+ - Add/update Vcs-Browser, Vcs-Bzr and add a notice to uploaders.
7460 * debian/copyright: fix syntax.
7144 * debian/copyright: fix syntax.
7461
7145
7462 [ Michał Sawicz ]
7146 [ Michał Sawicz ]
@@ -7466,7 +7150,7 @@ qml-phone-shell (1.77) raring; urgency=low
7466 * Renamed Media player files to match with new application name.
7150 * Renamed Media player files to match with new application name.
7467
7151
7468 [ Daniel d'Andrada ]
7152 [ Daniel d'Andrada ]
7469− * New: DirectionalDragArea component. An area that detects axis-aligned
7153+ * New: DirectionalDragArea component. An area that detects axis-aligned
7470 single-finger drag gestures.
7154 single-finger drag gestures.
7471 * Make it possible to send touch events from within QML test code.
7155 * Make it possible to send touch events from within QML test code.
7472
7156
@@ -7903,7 +7587,7 @@ qml-phone-shell (1.39) quantal; urgency=low
7903
7587
7904qml-phone-shell (1.38) quantal; urgency=low
7588qml-phone-shell (1.38) quantal; urgency=low
7905
7589
7906− * fix launching of notepad
7590+ * fix launching of notepad
7907
7591
7908 -- Bill Filler <bill.filler@canonical.com> Fri, 01 Feb 2013 03:21:29 -0500
7592 -- Bill Filler <bill.filler@canonical.com> Fri, 01 Feb 2013 03:21:29 -0500
7909
7593
@@ -7916,14 +7600,14 @@ qml-phone-shell (1.37) quantal; urgency=low
7916
7600
7917qml-phone-shell (1.36) quantal; urgency=low
7601qml-phone-shell (1.36) quantal; urgency=low
7918
7602
7919− * launch real notepad app
7603+ * launch real notepad app
7920 * fix launching of mock apps
7604 * fix launching of mock apps
7921
7605
7922 -- Bill Filler <bill.filler@canonical.com> Thu, 31 Jan 2013 21:36:05 -0500
7606 -- Bill Filler <bill.filler@canonical.com> Thu, 31 Jan 2013 21:36:05 -0500
7923
7607
7924qml-phone-shell (1.35) quantal; urgency=low
7608qml-phone-shell (1.35) quantal; urgency=low
7925
7609
7926− * integrate ubuntu-browser instead of snowshoe
7610+ * integrate ubuntu-browser instead of snowshoe
7927
7611
7928 -- Bill Filler <bill.filler@canonical.com> Thu, 31 Jan 2013 17:33:37 -0500
7612 -- Bill Filler <bill.filler@canonical.com> Thu, 31 Jan 2013 17:33:37 -0500
7929
7613
@@ -8007,7 +7691,7 @@ qml-phone-shell (1.22) quantal; urgency=low
8007
7691
8008qml-phone-shell (1.21) quantal; urgency=low
7692qml-phone-shell (1.21) quantal; urgency=low
8009
7693
8010− * New release with fullscreen launcher fixes
7694+ * New release with fullscreen launcher fixes
8011
7695
8012 -- Bill Filler <bill.filler@canonical.com> Fri, 07 Dec 2012 09:36:37 +0000
7696 -- Bill Filler <bill.filler@canonical.com> Fri, 07 Dec 2012 09:36:37 +0000
8013
7697
@@ -8019,7 +7703,7 @@ qml-phone-shell (1.20) quantal; urgency=low
8019
7703
8020qml-phone-shell (1.19) quantal; urgency=low
7704qml-phone-shell (1.19) quantal; urgency=low
8021
7705
8022− * enable multi-threaded render for apps
7706+ * enable multi-threaded render for apps
8023
7707
8024 -- Bill Filler <bill.filler@canonical.com> Wed, 05 Dec 2012 17:34:09 +0000
7708 -- Bill Filler <bill.filler@canonical.com> Wed, 05 Dec 2012 17:34:09 +0000
8025
7709
@@ -8027,7 +7711,7 @@ qml-phone-shell (1.18) quantal; urgency=low
8027
7711
8028 [ Bill Filler ]
7712 [ Bill Filler ]
8029 * update launcher to use wk2-render (chromeless webkit) for facebook
7713 * update launcher to use wk2-render (chromeless webkit) for facebook
8030− and twitter
7714+ and twitter
8031
7715
8032 -- Florian Boucault <florian.boucault@canonical.com> Wed, 05 Dec 2012 12:20:50 +0000
7716 -- Florian Boucault <florian.boucault@canonical.com> Wed, 05 Dec 2012 12:20:50 +0000
8033
7717
@@ -8039,7 +7723,7 @@ qml-phone-shell (1.17) quantal; urgency=low
8039
7723
8040qml-phone-shell (1.16) quantal; urgency=low
7724qml-phone-shell (1.16) quantal; urgency=low
8041
7725
8042− * fix to launch new gallery with correct args
7726+ * fix to launch new gallery with correct args
8043
7727
8044 -- Bill Filler <bill.filler@canonical.com> Thu, 29 Nov 2012 17:04:36 -0500
7728 -- Bill Filler <bill.filler@canonical.com> Thu, 29 Nov 2012 17:04:36 -0500
8045
7729
@@ -8101,7 +7785,7 @@ qml-phone-shell (1.2) quantal; urgency=low
8101
7785
8102qml-phone-shell (1.1) quantal; urgency=low
7786qml-phone-shell (1.1) quantal; urgency=low
8103
7787
8104− * comment out console.log() to prevent crash
7788+ * comment out console.log() to prevent crash
8105
7789
8106 -- Bill Filler <bill.filler@canonical.com> Sun, 28 Oct 2012 22:18:36 +0100
7790 -- Bill Filler <bill.filler@canonical.com> Sun, 28 Oct 2012 22:18:36 +0100
8107
7791
@@ -8129,19 +7813,19 @@ qml-phone-shell (0.7) quantal; urgency=low
8129 * qml-phone-shell.conf: better setup of env vars and launch
7813 * qml-phone-shell.conf: better setup of env vars and launch
8130 via dbus-luanch to properly setup session bus
7814 via dbus-luanch to properly setup session bus
8131 * shellapplication.cpp: don't setup custom env before launching
7815 * shellapplication.cpp: don't setup custom env before launching
8132− processes
7816+ processes
8133
7817
8134 -- Bill Filler <bill.filler@canonical.com> Sun, 21 Oct 2012 11:32:42 +0200
7818 -- Bill Filler <bill.filler@canonical.com> Sun, 21 Oct 2012 11:32:42 +0200
8135
7819
8136qml-phone-shell (0.6) quantal; urgency=low
7820qml-phone-shell (0.6) quantal; urgency=low
8137
7821
8138− * added additional Android env vars to upstart script
7822+ * added additional Android env vars to upstart script
8139
7823
8140 -- Bill Filler <bill.filler@canonical.com> Fri, 19 Oct 2012 09:35:25 -0400
7824 -- Bill Filler <bill.filler@canonical.com> Fri, 19 Oct 2012 09:35:25 -0400
8141
7825
8142qml-phone-shell (0.5) quantal; urgency=low
7826qml-phone-shell (0.5) quantal; urgency=low
8143
7827
8144− * added support to launch telephony-app
7828+ * added support to launch telephony-app
8145
7829
8146 -- Bill Filler <bill.filler@canonical.com> Thu, 18 Oct 2012 13:45:25 -0400
7830 -- Bill Filler <bill.filler@canonical.com> Thu, 18 Oct 2012 13:45:25 -0400
8147
7831
@@ -8168,8 +7852,3 @@ qml-phone-shell (0.1) quantal; urgency=low
8168 * Initial release
7852 * Initial release
8169
7853
8170 -- Bill Filler <bill.filler@canonical.com> Wed, 10 Oct 2012 10:19:53 -0400
7854 -- Bill Filler <bill.filler@canonical.com> Wed, 10 Oct 2012 10:19:53 -0400
8171−unity8 (8.15+17.04.20170404.7-0ubuntu2) zesty; urgency=medium
8172−
8173− [ Michael Zanetti ]
8174− * Make the default store uri point to gnome software center
8175−
debian/control+194−215
@@ -2,224 +2,221 @@ Source: unity8
2Section: x11
2Section: x11
3Priority: optional
3Priority: optional
4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
4Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
5−Build-Depends:
5+Build-Depends: cmake,
6− android-headers,
7− cmake,
8− cmake-extras,
9− dbus-test-runner,
6+ dbus-test-runner,
10− debhelper (>= 9),
7+ debhelper (>= 9),
11− dh-apparmor,
8+ dh-apparmor,
12− doxyqml,
9+ doxyqml,
10+# To allow cross-compiling to work, we also must append :native
11+# to g++ so we don't try to run arm g++
12+# on an x86 CPU for example, when cross-compiling.
13− g++:native,
13+ g++:native,
14− gdb,
14+ gdb,
15− graphviz,
15+ graphviz,
16− gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
16+ gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
17− libandroid-properties-dev,
17+ libandroid-properties-dev,
18− libconnectivity-qt1-dev (>= 0.7.1),
18+ libconnectivity-qt1-dev (>= 0.7.1),
19− libevdev-dev,
19+ libevdev-dev,
20− libgeonames-dev (>= 0.2),
20+ libgeonames-dev (>= 0.2),
21+ libgnome-desktop-3-dev,
21− libgl1-mesa-dev[!arm64 !armhf] | libgl-dev[!arm64 !armhf],
22+ libgl1-mesa-dev[!arm64 !armhf] | libgl-dev[!arm64 !armhf],
22− libgl1-mesa-dri,
23+ libgl1-mesa-dri,
23− libgles2-mesa-dev[arm64 armhf],
24+ libgles2-mesa-dev[arm64 armhf],
24− libglib2.0-dev,
25+ libglib2.0-dev,
25− libgnome-desktop-3-dev,
26− libgsettings-qt-dev,
26+ libgsettings-qt-dev,
27− libhardware-dev,
27+ libhardware-dev,
28− liblightdm-qt5-3-dev,
28+ liblightdm-qt5-3-dev,
29− libpam0g-dev,
29+ libpam0g-dev,
30− libpulse-dev,
30+ libpulse-dev,
31− libqmenumodel-dev (>= 0.2.12),
31+ libqmenumodel-dev (>= 0.2.11),
32− libqt5sql5-sqlite,
33− libqt5svg5-dev,
32+ libqt5svg5-dev,
34− libqt5xmlpatterns5-dev,
33+ libqt5xmlpatterns5-dev,
35− libqtdbusmock1-dev (>= 0.7),
36− libqtdbustest1-dev,
37− libsystemsettings-dev,
34+ libsystemsettings-dev,
38− libubuntu-app-launch2-dev,
35+ libubuntu-app-launch2-dev,
39− libubuntu-download-manager-common-dev,
36+ libubuntu-download-manager-common-dev,
40− libubuntugestures5-dev (>= 1.3.2030),
37+ libubuntugestures5-dev (>= 1.3.2030),
41− libubuntugestures5-private-dev (>= 1.3.2030),
38+ libubuntugestures5-private-dev (>= 1.3.2030),
42− libudev-dev,
39+ libudev-dev,
43− libudm-common-dev,
40+ libudm-common-dev,
44− libunity-api-dev (>= 8.7),
41+ libunity-api-dev (>= 8.0),
45− libusermetricsoutput1-dev,
42+ libusermetricsoutput1-dev,
43+# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
46− libx11-dev[!arm64 !armhf],
44+ libx11-dev[!arm64 !armhf],
47− libxcb1-dev[!arm64 !armhf],
45+ libxcb1-dev[!arm64 !armhf],
48− libxi-dev[!arm64 !armhf],
46+ libxi-dev[!arm64 !armhf],
47+# End of X11 libs
49− pkg-config,
48+ pkg-config,
50− python3-all:any,
49+ python3-all:any,
51− python3-setuptools,
50+ python3-setuptools,
52− qml-module-qt-labs-folderlistmodel,
51+ qml-module-qt-labs-folderlistmodel,
53− qml-module-qt-labs-settings,
52+ qml-module-qt-labs-settings,
54− qml-module-qtmultimedia (>= 5.6),
55− qml-module-qtqml-statemachine,
53+ qml-module-qtqml-statemachine,
54+ qml-module-qtmultimedia (>= 5.6),
56− qml-module-qtquick-layouts,
55+ qml-module-qtquick-layouts,
57− qml-module-qtquick-xmllistmodel,
56+ qml-module-qtquick-xmllistmodel,
58− qml-module-qtquick2,
57+ qml-module-qtquick2,
59− qml-module-qtsysteminfo,
58+ qml-module-qtsysteminfo,
60− qml-module-qttest,
59+ qml-module-qttest,
61− qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
60+ qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
62− qml-module-ubuntu-layouts,
61+ qml-module-ubuntu-web,
63− qml-module-ubuntu-settings-components,
62+ qt5-default,
64− qml-module-ubuntu-test,
65− qtbase5-dev (>= 5.6),
63+ qtbase5-dev (>= 5.6),
66− qtbase5-dev-tools,
64+ qtbase5-dev-tools,
67− qtbase5-private-dev (>= 5.6),
65+ qtbase5-private-dev (>= 5.6),
68− qtdbustest-runner,
69− qtdeclarative5-dev (>= 5.6),
66+ qtdeclarative5-dev (>= 5.6),
70− qtdeclarative5-dev-tools,
67+ qtdeclarative5-dev-tools,
71− qtdeclarative5-private-dev (>= 5.6),
68+ qtdeclarative5-private-dev (>= 5.6),
72− qtdeclarative5-ubuntu-content1,
69+ qtdeclarative5-ubuntu-content1,
70+ qtdeclarative5-ubuntu-settings-components (>= 0.11),
73− ttf-ubuntu-font-family,
71+ ttf-ubuntu-font-family,
74− ubports-wallpapers,
75− xvfb,
72+ xvfb,
76Standards-Version: 3.9.4
73Standards-Version: 3.9.4
77−Homepage: https://github.com/ubports/unity8
74+Homepage: http://launchpad.net/unity
78−Vcs-Git: https://github.com/ubports/unity8
75+# If you aren't a member of ~unity-team but need to upload
76+# packaging changes, just go ahead. ~unity-team will notice
77+# and sync up the code again.
78+Vcs-Bzr: https://code.launchpad.net/unity8
79+Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
79XS-Testsuite: autopkgtest
80XS-Testsuite: autopkgtest
80X-Ubuntu-Use-Langpack: yes
81X-Ubuntu-Use-Langpack: yes
81
82
82Package: indicators-client
83Package: indicators-client
83Architecture: any
84Architecture: any
84−Depends:
85− qmenumodel-qml (>= 0.2.11),
85+Depends: qmenumodel-qml (>= 0.2.11),
86− qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
86+ qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
87− unity8 (= ${binary:Version}),
87+ unity8 (= ${binary:Version}),
88− ${misc:Depends},
88+ ${misc:Depends},
89− ${shlibs:Depends},
89+ ${shlibs:Depends},
90Description: Indicators client test application
90Description: Indicators client test application
91 This package contains the client application for indicators used by autopilot
91 This package contains the client application for indicators used by autopilot
92
92
93Package: unity8-greeter
93Package: unity8-greeter
94Architecture: any
94Architecture: any
95−Depends:
96− unity-system-compositor,
97− unity8 (= ${binary:Version}),
95+Depends: unity8 (= ${binary:Version}),
96+ unity-system-compositor,
98− ${misc:Depends},
97+ ${misc:Depends},
99− ${shlibs:Depends},
98+ ${shlibs:Depends}
100−Recommends:
99+Recommends: lightdm
101− lightdm,
102−Provides:
103− lightdm-greeter,
100+Provides: lightdm-greeter
104Description: The Unity8 Greeter
101Description: The Unity8 Greeter
105 The Unity 8 greeter is the primary login greeter for Ubuntu devices.
102 The Unity 8 greeter is the primary login greeter for Ubuntu devices.
106
103
104+Package: unity-scope-tool
105+Architecture: any
106+Depends: unity8-common (= ${source:Version}),
107+ unity8-private (= ${binary:Version}),
108+ ${misc:Depends},
109+ ${shlibs:Depends},
110+# We do call pkg-config libunity-scopes from the code
111+ pkg-config,
112+ libunity-scopes-dev,
113+Description: Development tool for Unity scopes
114+ This package contains the development tool for new generation Unity scopes, based
115+ on Unity8.
116+
107Package: unity8
117Package: unity8
108Architecture: any
118Architecture: any
109−Provides:
110− indicator-renderer,
119+Provides: indicator-renderer,
111−Depends:
112− dmz-cursor-theme,
120+Depends: dmz-cursor-theme,
113− gsettings-desktop-schemas,
121+ gsettings-desktop-schemas,
114− libcap2-bin,
122+ libcap2-bin,
115− libglib2.0-bin,
123+ libglib2.0-bin,
116− qmenumodel-qml (>= 0.2.11),
124+ qmenumodel-qml (>= 0.2.11),
117− qml-module-biometryd,
125+ qml-module-biometryd,
118− qml-module-qt-labs-folderlistmodel,
126+ qml-module-qt-labs-folderlistmodel,
119− qml-module-qt-labs-settings,
127+ qml-module-qt-labs-settings,
120− qml-module-qtqml-statemachine,
128+ qml-module-qtqml-statemachine,
121− qml-module-qtquick-xmllistmodel,
129+ qml-module-qtquick-xmllistmodel,
122− qml-module-qtsysteminfo,
130+ qml-module-qtsysteminfo,
131+ qml-module-ubuntu-web,
123− qtdeclarative5-qtmir-plugin (>= 0.4.8),
132+ qtdeclarative5-qtmir-plugin (>= 0.4.8),
124− qtdeclarative5-ubuntu-telephony0.1,
133+ qtdeclarative5-ubuntu-telephony0.1,
125− ubuntu-system-settings (>= 0.4),
134+ ubuntu-system-settings (>= 0.4),
126− unity-launcher-impl-13,
135+ unity-launcher-impl-10,
127− unity8-common (= ${source:Version}),
136+ unity8-common (= ${source:Version}),
128− unity8-private (= ${binary:Version}),
137+ unity8-private (= ${binary:Version}),
129− unity8-private | unity-launcher-impl,
138+ unity8-private | unity-launcher-impl,
130− ${misc:Depends},
139+ ${misc:Depends},
131− ${shlibs:Depends},
140+ ${shlibs:Depends},
132−Recommends:
133− indicator-keyboard,
141+Recommends: indicator-keyboard,
134− indicator-session,
142+ indicator-session,
135− unity-greeter-session-broadcast,
143+ unity-greeter-session-broadcast,
136−Breaks:
144+Suggests: unity-scope-mediascanner2,
137− indicator-network (<< 0.5.1+14.10.20141014),
145+Breaks: indicator-network (<< 0.5.1+14.10.20141014),
146+ ubuntu-touch-session (<< 0.107),
147+ unity8-greeter (<< 7.89),
138− ubuntu-keyboard (<< 0.100),
148+ ubuntu-keyboard (<< 0.100),
139− ubuntu-touch-session (<< 0.107),
140− unity-scope-tool,
141− unity8-greeter (<< 7.89),
142−Replaces:
143− ubuntu-touch-session (<< 0.82~),
149+Replaces: ubuntu-touch-session (<< 0.82~),
144− unity-scope-tool,
145− unity8-greeter (<< 7.89),
150+ unity8-greeter (<< 7.89),
146−Conflicts:
147− ubuntu-system-settings-wizard,
151+Conflicts: ubuntu-system-settings-wizard,
148Description: Unity 8 shell
152Description: Unity 8 shell
149 The Unity 8 shell is the primary user interface for Ubuntu devices.
153 The Unity 8 shell is the primary user interface for Ubuntu devices.
150
154
151Package: unity8-common
155Package: unity8-common
152Architecture: all
156Architecture: all
153−Depends:
154− qml-module-qtquick-layouts,
157+Depends: qml-module-qtquick-layouts,
155− qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
158+ qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030),
156− qml-module-ubuntu-settings-components,
157− qml-module-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
159+ qml-module-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
160+ qtdeclarative5-ubuntu-settings-components (>= 0.11),
158− qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
161+ qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
159− qttranslations5-l10n,
162+ qttranslations5-l10n,
160− ubuntu-thumbnailer-impl-0,
163+ ubuntu-thumbnailer-impl-0,
164+ ubuntu-wallpapers,
161− unity-application-impl-27,
165+ unity-application-impl-23,
162− unity-notifications-impl-3,
166+ unity-notifications-impl-3,
163− unity8-schemas,
167+ unity-plugin-scopes | unity-scopes-impl,
168+ unity-scopes-impl-12,
164− unity8-tests | unity-application-impl,
169+ unity8-tests | unity-application-impl,
165− ${misc:Depends},
170+ ${misc:Depends},
166−Breaks:
167− unity8 (<< 7.86),
171+Breaks: unity8 (<< 7.86),
168−Replaces:
169− unity8 (<< 7.86),
172+Replaces: unity8 (<< 7.86),
170Description: Unity 8 shell (common files)
173Description: Unity 8 shell (common files)
171 The Unity 8 shell is the primary user interface for Ubuntu devices.
174 The Unity 8 shell is the primary user interface for Ubuntu devices.
172 .
175 .
173− This package contains the QML, graphics and locale files for unity8.
176+ This package contains the QML, graphics and locale files shared between
177+ unity8 and unity-scope-tool.
174
178
175Package: unity8-autopilot
179Package: unity8-autopilot
176Architecture: all
180Architecture: all
177−Depends:
178− autopilot-qt5 (>= 1.4),
181+Depends: autopilot-qt5 (>= 1.4),
179− gir1.2-glib-2.0,
182+ gir1.2-glib-2.0,
180− gir1.2-notify-0.7,
183+ gir1.2-notify-0.7,
181− libqt5test5,
184+ libqt5test5,
182− libqt5widgets5,
185+ libqt5widgets5,
183− ofono-phonesim,
186+ ofono-phonesim,
184− python3-autopilot,
187+ python3-autopilot,
185− python3-evdev,
188+ python3-evdev,
186− python3-fixtures,
189+ python3-fixtures,
187− python3-gi,
190+ python3-gi,
188− qttestability-autopilot (>= 1.4),
191+ qttestability-autopilot (>= 1.4),
189− ubuntu-ui-toolkit-autopilot (>= 1.3.2030),
192+ ubuntu-ui-toolkit-autopilot (>= 1.3.2030),
190− unity8 (= ${source:Version}),
193+ unity8 (= ${source:Version}),
191− unity8-tests (= ${source:Version}),
194+ unity8-tests (= ${source:Version}),
192− url-dispatcher-tools,
195+ url-dispatcher-tools,
193− xvfb,
196+ xvfb,
194− ${misc:Depends},
197+ ${misc:Depends},
195− ${python3:Depends},
198+ ${python3:Depends},
196Description: Test package for Unity 8 shell
199Description: Test package for Unity 8 shell
197 Autopilot tests for the unity8 package
200 Autopilot tests for the unity8 package
198
201
199Package: unity8-tests
202Package: unity8-tests
200Architecture: any
203Architecture: any
201Multi-Arch: same
204Multi-Arch: same
202−Pre-Depends:
203− ${misc:Pre-Depends},
205+Pre-Depends: ${misc:Pre-Depends},
204−Depends:
205− dbus-test-runner,
206+Depends: dbus-test-runner,
206− parallel,
207+ parallel,
207− qt5-default,
208+ qt5-default,
208− qtdbustest-runner,
209− qtdeclarative5-dev-tools,
209+ qtdeclarative5-dev-tools,
210− unity8 (= ${source:Version}),
210+ unity8 (= ${source:Version}),
211− xvfb,
211+ xvfb,
212− ${misc:Depends},
212+ ${misc:Depends},
213− ${shlibs:Depends},
213+ ${shlibs:Depends},
214−Provides:
215− unity-application-impl,
214+Provides: unity-application-impl,
216− unity-application-impl-27,
215+ unity-application-impl-23,
217− unity8-fake-env,
216+ unity8-fake-env,
218−Replaces:
219− unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1),
217+Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1),
220− unity8-fake-env,
218+ unity8-fake-env,
221−Conflicts:
222− unity8-fake-env,
219+Conflicts: unity8-fake-env,
223Description: Scripts and mocks for running Unity 8 shell tests
220Description: Scripts and mocks for running Unity 8 shell tests
224 Provides fake implementations of some QML modules used by Unity 8 shell
221 Provides fake implementations of some QML modules used by Unity 8 shell
225 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment
222 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment
@@ -228,45 +225,27 @@ Description: Scripts and mocks for running Unity 8 shell tests
228Package: unity8-private
225Package: unity8-private
229Architecture: any
226Architecture: any
230Multi-Arch: same
227Multi-Arch: same
231−Pre-Depends:
232− ${misc:Pre-Depends},
228+Pre-Depends: ${misc:Pre-Depends},
233−Depends:
234− accountsservice-ubuntu-schemas (>= 0.0.7),
229+Depends: accountsservice-ubuntu-schemas (>= 0.0.7),
235− gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
230+ gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
236− libhardware2,
231+ libhardware2,
232+ unity-schemas (>= 7.3.1+14.10.20140915),
233+ qtdeclarative5-gsettings1.0,
237− qml-module-qtmultimedia,
234+ qml-module-qtmultimedia,
238− qtdeclarative5-gsettings1.0,
239− unity8-schemas,
240− ${misc:Depends},
235+ ${misc:Depends},
241− ${shlibs:Depends},
236+ ${shlibs:Depends},
242−Provides:
243− unity-launcher-impl,
237+Provides: unity-launcher-impl,
244− unity-launcher-impl-13,
238+ unity-launcher-impl-10,
245Description: Unity 8 private libs
239Description: Unity 8 private libs
246 The Unity 8 shell is the primary user interface for Ubuntu devices.
240 The Unity 8 shell is the primary user interface for Ubuntu devices.
247 .
241 .
248 This package contains the private libraries for QML and other components
242 This package contains the private libraries for QML and other components
249 only used by the shell.
243 only used by the shell.
250
244
251−Package: unity8-schemas
252−Architecture: all
253−Multi-Arch: foreign
254−Depends:
255− ${misc:Depends},
256−Replaces:
257− unity-schemas (>= 7.3.1+14.10.20140915),
258−Breaks:
259− unity-schemas (>= 7.3.1+14.10.20140915),
260−Description: Unity 8 schemas
261− The Unity 8 shell is the primary user interface for Ubuntu devices.
262− .
263− This package contains the configuration schemas used by unity.
264−
265Package: unity8-doc
245Package: unity8-doc
266Section: doc
246Section: doc
267Architecture: all
247Architecture: all
268Multi-Arch: foreign
248Multi-Arch: foreign
269−Depends:
270− ${misc:Depends},
249+Depends: ${misc:Depends},
271Description: Documentation for Unity8
250Description: Documentation for Unity8
272 The Unity 8 shell is the primary user interface for Ubuntu devices. (documentation)
251 The Unity 8 shell is the primary user interface for Ubuntu devices. (documentation)
debian/rules+6−20
@@ -7,12 +7,6 @@ include /usr/share/dpkg/default.mk
7#export DH_VERBOSE=1
7#export DH_VERBOSE=1
8export DPKG_GENSYMBOLS_CHECK_LEVEL=4
8export DPKG_GENSYMBOLS_CHECK_LEVEL=4
9export NO_PNG_PKG_MANGLE=1
9export NO_PNG_PKG_MANGLE=1
10−export QT_SELECT=qt5
11−
12−DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
13−
14−# Skip tests on the archs they are known to be flaky with current configuration
15−testskip_architectures := arm64 powerpc ppc64el s390x
16
10
17%:
11%:
18 dh $@ --parallel --fail-missing --with python3
12 dh $@ --parallel --fail-missing --with python3
@@ -24,19 +18,7 @@ override_dh_auto_configure:
24
18
25override_dh_auto_build:
19override_dh_auto_build:
26 # doc is not a default target
20 # doc is not a default target
27− dh_auto_build -- -O all doc
21+ dh_auto_build -- all doc
28−
29−override_dh_auto_test:
30− # Run the entire test battery
31− # Parallel tests have a risk of starting xvfb on the same DISPLAY multiple times,
32− # causing the whole battery to fail.
33−ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
34−ifneq (,$(filter $(DEB_HOST_ARCH),$(testskip_architectures)))
35− -dh_auto_test --no-parallel -- -O -k xvfballtests
36−else
37− dh_auto_test --no-parallel -- -O -k xvfballtests
38−endif
39−endif
40
22
41override_dh_install:
23override_dh_install:
42 # install autopilot tests
24 # install autopilot tests
@@ -47,6 +29,10 @@ override_dh_install:
47 cd $(CURDIR)
29 cd $(CURDIR)
48 dh_install -X'*.pyc' --fail-missing
30 dh_install -X'*.pyc' --fail-missing
49
31
32+override_dh_installdeb:
33+ dh_apparmor --profile-name=usr.bin.unity8-dash -punity8-dash
34+ dh_installdeb
35+
50# use private lib directories
36# use private lib directories
51override_dh_makeshlibs:
37override_dh_makeshlibs:
52 dh_makeshlibs -Nunity8-private -Nunity8-tests
38 dh_makeshlibs -Nunity8-private -Nunity8-tests
@@ -54,4 +40,4 @@ override_dh_makeshlibs:
54override_dh_shlibdeps:
40override_dh_shlibdeps:
55 # Some mock libraries link against liblightdm-qt5-3.so which we want to
41 # Some mock libraries link against liblightdm-qt5-3.so which we want to
56 # avoid, since we only really link against our mock one, not the system one.
42 # avoid, since we only really link against our mock one, not the system one.
57− dh_shlibdeps -XlibMockAccountsService-qml.so -Lunity8-private
43+ dh_shlibdeps -XlibMockLightDM-qml.so -XlibMockAccountsService-qml.so -Lunity8-private
debian/source/formatnew file+1
@@ -0,0 +1 @@
1+1.0
debian/tests/control+3−5
@@ -1,11 +1,9 @@
1Tests: qmluitests.sh
1Tests: qmluitests.sh
2Restrictions: allow-stderr
2Restrictions: allow-stderr
3−Depends:
3+Depends: dpkg-dev,
4− dpkg-dev,
5− unity8-tests,
4+ unity8-tests,
6
5
7Tests: autopilot.sh
6Tests: autopilot.sh
8Restrictions: allow-stderr,
7Restrictions: allow-stderr,
9 isolation-machine,
8 isolation-machine,
10−Depends:
11− unity8-autopilot,
9+Depends: unity8-autopilot,
debian/unity-scope-tool.installnew file+2
@@ -0,0 +1,2 @@
1+usr/bin/unity-scope-tool
2+usr/share/unity8/ScopeTool.qml
debian/unity8-common.install+2
@@ -1,5 +1,7 @@
1+usr/share/glib-2.0/schemas
1usr/share/locale
2usr/share/locale
2usr/share/unity8/Components
3usr/share/unity8/Components
4+usr/share/unity8/Dash
3usr/share/unity8/Notifications
5usr/share/unity8/Notifications
4usr/share/unity8/graphics
6usr/share/unity8/graphics
5var/lib/polkit-1/localauthority/10-vendor.d
7var/lib/polkit-1/localauthority/10-vendor.d
debian/unity8-greeter.install+1−1
@@ -1,5 +1,5 @@
1−data/unity8-greeter-init.conf usr/share/upstart/sessions/
2data/unity8-greeter-wrapper usr/bin/
1data/unity8-greeter-wrapper usr/bin/
2+data/unity8-greeter-init.conf usr/share/upstart/sessions/
3data/unity8-greeter.pkla /var/lib/polkit-1/localauthority/10-vendor.d/
3data/unity8-greeter.pkla /var/lib/polkit-1/localauthority/10-vendor.d/
4usr/share/lightdm/greeters/unity8-greeter.desktop
4usr/share/lightdm/greeters/unity8-greeter.desktop
5usr/share/lightdm/lightdm.conf.d/51-unity8-greeter.conf
5usr/share/lightdm/lightdm.conf.d/51-unity8-greeter.conf
debian/unity8-private.install+3−1
@@ -1,16 +1,18 @@
1usr/lib/*/libunity8-private.*
1usr/lib/*/libunity8-private.*
2usr/lib/*/unity8/qml/AccountsService
2usr/lib/*/unity8/qml/AccountsService
3usr/lib/*/unity8/qml/Cursor
3usr/lib/*/unity8/qml/Cursor
4+usr/lib/*/unity8/qml/Dash
4usr/lib/*/unity8/qml/GlobalShortcut
5usr/lib/*/unity8/qml/GlobalShortcut
5usr/lib/*/unity8/qml/Greeter
6usr/lib/*/unity8/qml/Greeter
7+usr/lib/*/unity8/qml/ImageCache
6usr/lib/*/unity8/qml/LightDM
8usr/lib/*/unity8/qml/LightDM
7usr/lib/*/unity8/qml/Lights
9usr/lib/*/unity8/qml/Lights
8usr/lib/*/unity8/qml/Powerd
10usr/lib/*/unity8/qml/Powerd
9usr/lib/*/unity8/qml/ScreenshotDirectory
11usr/lib/*/unity8/qml/ScreenshotDirectory
10usr/lib/*/unity8/qml/SessionBroadcast
12usr/lib/*/unity8/qml/SessionBroadcast
11−usr/lib/*/unity8/qml/UInput
12usr/lib/*/unity8/qml/Ubuntu
13usr/lib/*/unity8/qml/Ubuntu
13usr/lib/*/unity8/qml/Unity
14usr/lib/*/unity8/qml/Unity
15+usr/lib/*/unity8/qml/UInput
14usr/lib/*/unity8/qml/Utils
16usr/lib/*/unity8/qml/Utils
15usr/lib/*/unity8/qml/WindowManager
17usr/lib/*/unity8/qml/WindowManager
16usr/lib/*/unity8/qml/Wizard
18usr/lib/*/unity8/qml/Wizard
debian/unity8-schemas.installdeleted−1
@@ -1 +0,0 @@
1−usr/share/glib-2.0/schemas
debian/unity8-tests.install+1
@@ -2,6 +2,7 @@ data/unity-mock-indicator-service.conf usr/share/upstart/sessions/
2usr/bin/unity-mock-indicator-service
2usr/bin/unity-mock-indicator-service
3usr/lib/*/unity8/qml/mocks
3usr/lib/*/unity8/qml/mocks
4usr/lib/*/unity8/qml/nonmirplugins
4usr/lib/*/unity8/qml/nonmirplugins
5+usr/lib/*/unity8/qml/scopefakes
5usr/lib/*/unity8/qml/utils
6usr/lib/*/unity8/qml/utils
6usr/lib/*/unity8/tests
7usr/lib/*/unity8/tests
7usr/lib/*/unity8/uqmlscene
8usr/lib/*/unity8/uqmlscene
debian/unity8.install+10−6
@@ -1,19 +1,23 @@
1−data/devices.conf etc/ubuntu/
1+debian/usr.bin.unity8-dash etc/apparmor.d
2−data/test.sensors etc/ubuntusensors/
2+var/lib/unity8/version
3+data/unity8-dash.conf usr/share/upstart/sessions/
3data/unity8-filewatcher.conf usr/share/upstart/sessions/
4data/unity8-filewatcher.conf usr/share/upstart/sessions/
4data/unity8.conf usr/share/upstart/sessions/
5data/unity8.conf usr/share/upstart/sessions/
6+data/devices.conf etc/ubuntu/
5usr/bin/unity8
7usr/bin/unity8
8+usr/bin/unity8-dash
9+usr/share/applications/unity8-dash.desktop
6usr/share/applications/unity8.desktop
10usr/share/applications/unity8.desktop
7usr/share/unity8/ApplicationMenus
11usr/share/unity8/ApplicationMenus
8−usr/share/unity8/DeviceConfiguration.qml
9−usr/share/unity8/DisabledScreenNotice.qml
10usr/share/unity8/Greeter
12usr/share/unity8/Greeter
11usr/share/unity8/Launcher
13usr/share/unity8/Launcher
12−usr/share/unity8/OrientedShell.qml
13usr/share/unity8/Panel
14usr/share/unity8/Panel
14usr/share/unity8/Rotation
15usr/share/unity8/Rotation
16+usr/share/unity8/DeviceConfiguration.qml
17+usr/share/unity8/OrientedShell.qml
18+usr/share/unity8/DisabledScreenNotice.qml
15usr/share/unity8/Shell.qml
19usr/share/unity8/Shell.qml
16usr/share/unity8/Stage
20usr/share/unity8/Stage
17usr/share/unity8/Tutorial
21usr/share/unity8/Tutorial
18usr/share/unity8/Wizard
22usr/share/unity8/Wizard
19−var/lib/unity8/version
23+usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
debian/usr.bin.unity8-dashnew file+21
@@ -0,0 +1,21 @@
1+# vim:syntax=apparmor
2+
3+#include <tunables/global>
4+
5+# v2 compatible wildly permissive profile
6+profile unity8-dash /usr/bin/unity8-dash (attach_disconnected) {
7+ capability,
8+ network,
9+ / rwkl,
10+ /** rwlkm,
11+ /** pix,
12+
13+ mount,
14+ remount,
15+ umount,
16+ pivot_root,
17+ dbus,
18+ signal,
19+ ptrace,
20+ unix,
21+}
plugins/AccountsService/AccountsService.cpp+30−1
@@ -25,6 +25,7 @@
25#include <glib.h>
25#include <glib.h>
26
26
27#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User")
27#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User")
28+#define IFACE_LOCATION_HERE QStringLiteral("com.ubuntu.location.providers.here.AccountsService")
28#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input")
29#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input")
29#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy")
30#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy")
30#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy")
31#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy")
@@ -32,7 +33,7 @@
32#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private")
33#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private")
33
34
34#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
35#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
35−#define PROP_DEMO_EDGES QStringLiteral("DemoEdges2")
36+#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
36#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted")
37#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted")
37#define PROP_EMAIL QStringLiteral("Email")
38#define PROP_EMAIL QStringLiteral("Email")
38#define PROP_ENABLE_FINGERPRINT_IDENTIFICATION QStringLiteral("EnableFingerprintIdentification")
39#define PROP_ENABLE_FINGERPRINT_IDENTIFICATION QStringLiteral("EnableFingerprintIdentification")
@@ -92,6 +93,8 @@ AccountsService::AccountsService(QObject* parent, const QString &user)
92 registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged"));
93 registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged"));
93 registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged"));
94 registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged"));
94 registerProperty(IFACE_ACCOUNTS_USER, PROP_INPUT_SOURCES, QStringLiteral("keymapsChanged"));
95 registerProperty(IFACE_ACCOUNTS_USER, PROP_INPUT_SOURCES, QStringLiteral("keymapsChanged"));
96+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
97+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
95 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_FINGERPRINT_IDENTIFICATION, QStringLiteral("enableFingerprintIdentificationChanged"));
98 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_FINGERPRINT_IDENTIFICATION, QStringLiteral("enableFingerprintIdentificationChanged"));
96 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
99 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
97 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
100 registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
@@ -213,6 +216,32 @@ AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() cons
213 return (PasswordDisplayHint)value.toInt();
216 return (PasswordDisplayHint)value.toInt();
214}
217}
215
218
219+bool AccountsService::hereEnabled() const
220+{
221+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
222+ return value.toBool();
223+}
224+
225+void AccountsService::setHereEnabled(bool enabled)
226+{
227+ setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
228+}
229+
230+QString AccountsService::hereLicensePath() const
231+{
232+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
233+ QString hereLicensePath = value.toString();
234+ if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
235+ hereLicensePath = QStringLiteral("");
236+ return hereLicensePath;
237+}
238+
239+bool AccountsService::hereLicensePathValid() const
240+{
241+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
242+ return !value.toString().isNull();
243+}
244+
216QString AccountsService::realName() const
245QString AccountsService::realName() const
217{
246{
218 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME);
247 auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME);
plugins/AccountsService/AccountsService.h+16
@@ -66,6 +66,16 @@ class AccountsService: public QObject
66 READ failedFingerprintLogins
66 READ failedFingerprintLogins
67 WRITE setFailedFingerprintLogins
67 WRITE setFailedFingerprintLogins
68 NOTIFY failedFingerprintLoginsChanged)
68 NOTIFY failedFingerprintLoginsChanged)
69+ Q_PROPERTY(bool hereEnabled
70+ READ hereEnabled
71+ WRITE setHereEnabled
72+ NOTIFY hereEnabledChanged)
73+ Q_PROPERTY(QString hereLicensePath
74+ READ hereLicensePath
75+ NOTIFY hereLicensePathChanged)
76+ Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
77+ READ hereLicensePathValid
78+ NOTIFY hereLicensePathChanged)
69 Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
79 Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
70 Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
80 Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
71 Q_PROPERTY(QStringList keymaps READ keymaps WRITE setKeymaps NOTIFY keymapsChanged)
81 Q_PROPERTY(QStringList keymaps READ keymaps WRITE setKeymaps NOTIFY keymapsChanged)
@@ -96,6 +106,10 @@ public:
96 void setFailedLogins(uint failedLogins);
106 void setFailedLogins(uint failedLogins);
97 uint failedFingerprintLogins() const;
107 uint failedFingerprintLogins() const;
98 void setFailedFingerprintLogins(uint failedFingerprintLogins);
108 void setFailedFingerprintLogins(uint failedFingerprintLogins);
109+ bool hereEnabled() const;
110+ void setHereEnabled(bool enabled);
111+ QString hereLicensePath() const;
112+ bool hereLicensePathValid() const;
99 QString realName() const;
113 QString realName() const;
100 void setRealName(const QString &realName);
114 void setRealName(const QString &realName);
101 QString email() const;
115 QString email() const;
@@ -115,6 +129,8 @@ Q_SIGNALS:
115 void passwordDisplayHintChanged();
129 void passwordDisplayHintChanged();
116 void failedLoginsChanged();
130 void failedLoginsChanged();
117 void failedFingerprintLoginsChanged();
131 void failedFingerprintLoginsChanged();
132+ void hereEnabledChanged();
133+ void hereLicensePathChanged();
118 void realNameChanged();
134 void realNameChanged();
119 void emailChanged();
135 void emailChanged();
120 void keymapsChanged();
136 void keymapsChanged();
plugins/AccountsService/CMakeLists.txt+2−1
@@ -7,8 +7,9 @@ add_library(AccountsService-qml MODULE
7 plugin.cpp
7 plugin.cpp
8 )
8 )
9
9
10+qt5_use_modules(AccountsService-qml DBus Qml)
11+
10target_link_libraries(AccountsService-qml
12target_link_libraries(AccountsService-qml
11− Qt5::DBus Qt5::Qml
12 ${GLIB_LIBRARIES}
13 ${GLIB_LIBRARIES}
13 )
14 )
14
15
plugins/AccountsService/com.canonical.unity.AccountsService.xml−6
@@ -9,17 +9,11 @@
9 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
9 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
10 value="com.ubuntu.AccountsService.GreeterChangeAny"/>
10 value="com.ubuntu.AccountsService.GreeterChangeAny"/>
11
11
12− <!-- Marks that V1 (pre-8.21) edge demos have been run. Legacy value. -->
13 <!-- Should have been named DemoEdges, sorry folks. -mterry -->
12 <!-- Should have been named DemoEdges, sorry folks. -mterry -->
14 <property name="demo-edges" type="b" access="readwrite">
13 <property name="demo-edges" type="b" access="readwrite">
15 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
14 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
16 </property>
15 </property>
17
16
18− <!-- Marks that V2 (post-8.21) edge demos have been run -->
19− <property name="DemoEdges2" type="b" access="readwrite">
20− <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
21− </property>
22−
23 <!-- List of tutorial pages that have been completed by the user -->
17 <!-- List of tutorial pages that have been completed by the user -->
24 <property name="DemoEdgesCompleted" type="as" access="readwrite">
18 <property name="DemoEdgesCompleted" type="as" access="readwrite">
25 <annotation name="org.freedesktop.Accounts.DefaultValue" value="[]"/>
19 <annotation name="org.freedesktop.Accounts.DefaultValue" value="[]"/>
plugins/CMakeLists.txt+3−1
@@ -1,4 +1,4 @@
1−find_package(QmlPlugins)
1+include(QmlPlugins)
2
2
3# Set up and install a plugin for unity8.
3# Set up and install a plugin for unity8.
4#
4#
@@ -15,8 +15,10 @@ add_subdirectory(AccountsService)
15add_subdirectory(Cursor)
15add_subdirectory(Cursor)
16add_subdirectory(GlobalShortcut)
16add_subdirectory(GlobalShortcut)
17add_subdirectory(Greeter)
17add_subdirectory(Greeter)
18+add_subdirectory(ImageCache)
18add_subdirectory(LightDM)
19add_subdirectory(LightDM)
19add_subdirectory(Lights)
20add_subdirectory(Lights)
21+add_subdirectory(Dash)
20add_subdirectory(Powerd)
22add_subdirectory(Powerd)
21add_subdirectory(ScreenshotDirectory)
23add_subdirectory(ScreenshotDirectory)
22add_subdirectory(SessionBroadcast)
24add_subdirectory(SessionBroadcast)
plugins/Cursor/CMakeLists.txt+2−1
@@ -26,7 +26,8 @@ add_library(Cursor-qml SHARED
26target_link_libraries(Cursor-qml
26target_link_libraries(Cursor-qml
27 xcursorloader-static
27 xcursorloader-static
28 ${QT5PLATFORM_SUPPORT_LDFLAGS}
28 ${QT5PLATFORM_SUPPORT_LDFLAGS}
29− Qt5::Qml Qt5::Quick Qt5::Svg
30)
29)
31
30
31+qt5_use_modules(Cursor-qml Qml Quick Svg)
32+
32add_unity8_plugin(Cursor 1.1 Cursor TARGETS Cursor-qml)
33add_unity8_plugin(Cursor 1.1 Cursor TARGETS Cursor-qml)
plugins/Cursor/CursorImageProvider.cpp−2
@@ -174,8 +174,6 @@ CursorImageProvider::CursorImageProvider()
174 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("not-allowed"));
174 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("not-allowed"));
175 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("circle"));
175 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("circle"));
176
176
177− m_fallbackNames[QStringLiteral("grabbing")].append(QStringLiteral("closedhand")); // Breeze
178−
179 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointing_hand"));
177 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointing_hand"));
180 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointer"));
178 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointer"));
181
179
plugins/Dash/AudioProgressBar.qmlnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Dash 0.1
20+
21+Item {
22+ id: root
23+
24+ implicitHeight: progressBarImage.height
25+
26+ property url source
27+ readonly property double progress: AudioUrlComparer.compare(source, DashAudioPlayer.currentSource) ? DashAudioPlayer.progress : 0
28+
29+ Image {
30+ id: progressBarImage
31+ anchors { left: parent.left; right: parent.right }
32+ height: units.dp(6)
33+ source: "graphics/music_progress_bg.png"
34+ asynchronous: true
35+ sourceSize.width: width
36+ sourceSize.height: height
37+ }
38+
39+ UbuntuShape {
40+ id: progressBarFill
41+ objectName: "progressBarFill"
42+
43+ readonly property int maxWidth: progressBarImage.width
44+
45+ anchors {
46+ left: progressBarImage.left
47+ right: progressBarImage.right
48+ verticalCenter: progressBarImage.verticalCenter
49+ rightMargin: maxWidth - (maxWidth * root.progress)
50+ }
51+ height: units.dp(2)
52+ backgroundColor: theme.palette.normal.activity
53+ }
54+}
plugins/Dash/CMakeLists.txtnew file+47
@@ -0,0 +1,47 @@
1+# There's no cmake var for v8 include path :-/
2+# so create one
3+LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
4+if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
5+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
6+else()
7+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
8+endif()
9+
10+include_directories(
11+ ${CMAKE_CURRENT_SOURCE_DIR}
12+ ${CMAKE_CURRENT_BINARY_DIR}
13+)
14+
15+include_directories(
16+ SYSTEM
17+ ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
18+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
19+ ${Qt5V8_PRIVATE_INCLUDE_DIR}
20+)
21+
22+remove_definitions(-DQT_NO_KEYWORDS)
23+
24+set(QMLPLUGIN_SRC
25+ plugin.cpp
26+ listviewwithpageheader.cpp
27+ abstractdashview.cpp
28+ verticaljournal.cpp
29+ horizontaljournal.cpp
30+ organicgrid.cpp
31+ )
32+
33+add_library(Dash-qml MODULE
34+ ${QMLPLUGIN_SRC}
35+ )
36+
37+target_link_libraries(Dash-qml
38+ ${Qt5Gui_LIBRARIES}
39+ ${Qt5Quick_LIBRARIES}
40+ )
41+
42+qt5_use_modules(Dash-qml Qml Quick Concurrent)
43+
44+add_unity8_plugin(Dash 0.1 Dash TARGETS Dash-qml)
45+
46+install(FILES graphics/music_progress_bg.png DESTINATION ${SHELL_INSTALL_QML}/Dash/graphics/)
47+file(COPY graphics/music_progress_bg.png DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/graphics/)
plugins/Dash/CardAttributes.qmlnew file+71
@@ -0,0 +1,71 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+
21+GridLayout {
22+ id: grid
23+ anchors {
24+ left: parent.left;
25+ right: parent.right;
26+ }
27+ columns: 2 + repeater.count % 2
28+ rowSpacing: units.gu(.5)
29+ property alias model: repeater.model
30+ property color color: theme.palette.normal.baseText
31+ property real fontScale: 1.0
32+
33+ Repeater {
34+ id: repeater
35+ delegate: Row {
36+ spacing: units.gu(0.5)
37+ readonly property int column: index % grid.columns;
38+ Layout.alignment: {
39+ if (column == 0) return Qt.AlignLeft;
40+ if (column == grid.columns - 1 || index == repeater.count - 1) return Qt.AlignRight;
41+ if (column == 1) return Qt.AlignHCenter;
42+ }
43+ Layout.column: index % grid.columns
44+ Layout.row: index / grid.columns
45+ Layout.columnSpan: index == repeater.count - 1 && grid.columns == 3 && column == 1 ? 2 : 1
46+ Layout.maximumWidth: Math.max(icon.width, label.x + label.implicitWidth)
47+ Layout.fillWidth: true
48+ height: units.gu(2)
49+ Icon {
50+ id: icon
51+ height: units.gu(2)
52+ // FIXME Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293
53+ width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth
54+ source: "icon" in modelData && modelData["icon"] || ""
55+ color: grid.color
56+ }
57+ Label {
58+ id: label
59+ width: parent.width - x
60+ anchors.verticalCenter: parent.verticalCenter
61+ text: "value" in modelData && modelData["value"] || "";
62+ elide: Text.ElideRight
63+ maximumLineCount: 1
64+ font.weight: "style" in modelData && modelData["style"] === "highlighted" ? Font.Bold : Font.Light
65+ fontSize: "x-small"
66+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
67+ color: grid.color
68+ }
69+ }
70+ }
71+}
plugins/Dash/CardAudioProgress.qmlnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Dash 0.1
20+
21+Item {
22+ id: root
23+
24+ implicitHeight: positionLabel.y + positionLabel.height
25+ visible: AudioUrlComparer.compare(source, DashAudioPlayer.currentSource)
26+
27+ property int duration: 0
28+ property alias source: progress.source
29+ property color color: theme.palette.normal.baseText
30+ readonly property int position: root.visible ? DashAudioPlayer.position / 1000 : 0
31+
32+ AudioProgressBar {
33+ id: progress
34+ anchors { left: parent.left; right: parent.right }
35+ }
36+
37+ Label {
38+ id: positionLabel
39+ anchors {
40+ left: parent.left
41+ top: progress.bottom
42+ }
43+ verticalAlignment: Text.AlignBottom
44+ fontSize: "x-small"
45+ text: DashAudioPlayer.lengthToString(root.position)
46+ color: root.color
47+ }
48+
49+ Label {
50+ anchors {
51+ right: parent.right
52+ top: progress.bottom
53+ }
54+ verticalAlignment: Text.AlignBottom
55+ fontSize: "x-small"
56+ text: DashAudioPlayer.lengthToString(duration)
57+ color: root.color
58+ }
59+}
plugins/Dash/CardCreator.jsnew file+999
@@ -0,0 +1,999 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+.pragma library
18+
19+// %1 is the template["card-background"]["elements"][0]
20+// %2 is the template["card-background"]["elements"][1]
21+// %3 is whether the loader should be asynchronous or not
22+// %4 is the template["card-background"] string
23+var kBackgroundLoaderCode = 'Loader {\n\
24+ id: backgroundLoader; \n\
25+ objectName: "backgroundLoader"; \n\
26+ anchors.fill: parent; \n\
27+ asynchronous: %3; \n\
28+ visible: status === Loader.Ready; \n\
29+ sourceComponent: UbuntuShape { \n\
30+ objectName: "background"; \n\
31+ radius: "small"; \n\
32+ aspect: { \n\
33+ switch (root.backgroundShapeStyle) { \n\
34+ case "inset": return UbuntuShape.Inset; \n\
35+ case "shadow": return UbuntuShape.DropShadow; \n\
36+ default: \n\
37+ case "flat": return UbuntuShape.Flat; \n\
38+ } \n\
39+ } \n\
40+ backgroundColor: getColor(0) || "white"; \n\
41+ secondaryBackgroundColor: getColor(1) || backgroundColor; \n\
42+ backgroundMode: UbuntuShape.VerticalGradient; \n\
43+ anchors.fill: parent; \n\
44+ source: backgroundImage.source ? backgroundImage : null; \n\
45+ property real luminance: Style.luminance(backgroundColor); \n\
46+ property Image backgroundImage: Image { \n\
47+ objectName: "backgroundImage"; \n\
48+ source: { \n\
49+ if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
50+ else return %4; \n\
51+ } \n\
52+ } \n\
53+ function getColor(index) { \n\
54+ if (cardData && typeof cardData["background"] === "object" \n\
55+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { \n\
56+ return cardData["background"]["elements"][index]; \n\
57+ } else return index === 0 ? %1 : %2; \n\
58+ } \n\
59+ } \n\
60+ }\n';
61+
62+// %1 is the aspect of the UbuntuShape
63+var kArtUbuntuShapeCode = 'UbuntuShape { \n\
64+ anchors.fill: parent; \n\
65+ source: artImage; \n\
66+ sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\
67+ radius: "small"; \n\
68+ aspect: %1; \n\
69+ }';
70+
71+var kArtProportionalShapeCode = 'ProportionalShape { \n\
72+ anchors.left: parent.left; \n\
73+ anchors.right: parent.right; \n\
74+ source: artImage; \n\
75+ aspect: UbuntuShape.DropShadow; \n\
76+ }';
77+
78+// %1 is used as anchors of artShapeLoader
79+// %2 is used as image width
80+// %3 is used as image height
81+// %4 is whether the image should be visible
82+// %5 is whether the loader should be asynchronous or not
83+// %6 is the shape code we want to use
84+// %7 is injected as code to artImage
85+// %8 is used as image fallback
86+var kArtShapeHolderCode = 'Loader { \n\
87+ id: artShapeLoader; \n\
88+ height: root.fixedArtShapeSize.height; \n\
89+ width: root.fixedArtShapeSize.width; \n\
90+ anchors { %1 } \n\
91+ objectName: "artShapeLoader"; \n\
92+ readonly property string cardArt: cardData && cardData["art"] || %8; \n\
93+ onCardArtChanged: { if (item) { item.image.source = cardArt; } } \n\
94+ active: cardArt != ""; \n\
95+ asynchronous: %5; \n\
96+ visible: status === Loader.Ready; \n\
97+ sourceComponent: Item { \n\
98+ id: artShape; \n\
99+ objectName: "artShape"; \n\
100+ visible: image.status === Image.Ready; \n\
101+ readonly property alias image: artImage; \n\
102+ %6 \n\
103+ width: root.fixedArtShapeSize.width; \n\
104+ height: root.fixedArtShapeSize.height; \n\
105+ CroppedImageMinimumSourceSize { \n\
106+ id: artImage; \n\
107+ objectName: "artImage"; \n\
108+ source: artShapeLoader.cardArt; \n\
109+ asynchronous: %5; \n\
110+ visible: %4; \n\
111+ width: %2; \n\
112+ height: %3; \n\
113+ %7 \n\
114+ } \n\
115+ } \n\
116+ }\n';
117+
118+// %1 is used as anchors of artShapeLoader
119+// %2 is used as image width
120+// %3 is used as image height
121+// %4 is whether the image should be visible
122+// %5 is whether the loader should be asynchronous or not
123+// %6 is the shape code we want to use
124+// %7 is injected as code to artImage
125+// %8 is used as image fallback
126+var kArtShapeHolderCodeCardToolCard = 'Loader { \n\
127+ id: artShapeLoader; \n\
128+ anchors { %1 } \n\
129+ objectName: "artShapeLoader"; \n\
130+ readonly property string cardArt: cardData && cardData["art"] || %8; \n\
131+ onCardArtChanged: { if (item) { item.image.source = cardArt; } } \n\
132+ active: cardArt != ""; \n\
133+ asynchronous: %5; \n\
134+ visible: status === Loader.Ready; \n\
135+ sourceComponent: Item { \n\
136+ id: artShape; \n\
137+ objectName: "artShape"; \n\
138+ visible: image.status === Image.Ready; \n\
139+ readonly property alias image: artImage; \n\
140+ %6 \n\
141+ width: image.status !== Image.Ready ? 0 : image.width; \n\
142+ height: image.status !== Image.Ready ? 0 : image.height; \n\
143+ CroppedImageMinimumSourceSize { \n\
144+ id: artImage; \n\
145+ objectName: "artImage"; \n\
146+ source: artShapeLoader.cardArt; \n\
147+ asynchronous: %5; \n\
148+ visible: %4; \n\
149+ width: %2; \n\
150+ height: %3; \n\
151+ %7 \n\
152+ } \n\
153+ } \n\
154+ }\n';
155+
156+// %1 is anchors.fill
157+// %2 is width
158+// %3 is height
159+// %4 is whether the icon should be asynchronous or not
160+var kAudioButtonCode = 'AbstractButton { \n\
161+ id: audioButton; \n\
162+ anchors.fill: %1; \n\
163+ width: %2; \n\
164+ height: %3; \n\
165+ readonly property url source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
166+ UbuntuShape { \n\
167+ anchors.fill: parent; \n\
168+ visible: parent.pressed; \n\
169+ radius: "small"; \n\
170+ } \n\
171+ Rectangle { \n\
172+ color: Qt.rgba(0, 0, 0, 0.5); \n\
173+ anchors.centerIn: parent; \n\
174+ width: parent.width * 0.5; \n\
175+ height: width; \n\
176+ radius: width / 2; \n\
177+ } \n\
178+ Icon { \n\
179+ anchors.centerIn: parent; \n\
180+ width: parent.width * 0.3; \n\
181+ height: width; \n\
182+ opacity: 0.9; \n\
183+ name: DashAudioPlayer.playing && AudioUrlComparer.compare(parent.source, DashAudioPlayer.currentSource) ? "media-playback-pause" : "media-playback-start"; \n\
184+ color: "white"; \n\
185+ asynchronous: %4; \n\
186+ } \n\
187+ onClicked: { \n\
188+ if (AudioUrlComparer.compare(source, DashAudioPlayer.currentSource)) { \n\
189+ if (DashAudioPlayer.playing) { \n\
190+ DashAudioPlayer.pause(); \n\
191+ } else { \n\
192+ DashAudioPlayer.play(); \n\
193+ } \n\
194+ } else { \n\
195+ var playlist = (cardData["quickPreviewData"] && cardData["quickPreviewData"]["playlist"]) || null; \n\
196+ DashAudioPlayer.playSource(source, playlist); \n\
197+ } \n\
198+ } \n\
199+ onPressAndHold: { \n\
200+ root.pressAndHold(); \n\
201+ } \n\
202+ }';
203+
204+// %1 is whether the loader should be asynchronous or not
205+// %2 is the header height code
206+var kOverlayLoaderCode = 'Loader { \n\
207+ id: overlayLoader; \n\
208+ readonly property real overlayHeight: %2 + units.gu(2); \n\
209+ anchors.fill: artShapeLoader; \n\
210+ active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
211+ asynchronous: %1; \n\
212+ visible: showHeader && status === Loader.Ready; \n\
213+ sourceComponent: UbuntuShapeOverlay { \n\
214+ id: overlay; \n\
215+ property real luminance: Style.luminance(overlayColor); \n\
216+ aspect: UbuntuShape.Flat; \n\
217+ radius: "small"; \n\
218+ overlayColor: cardData && cardData["overlayColor"] || "#99000000"; \n\
219+ overlayRect: Qt.rect(0, 1 - overlayLoader.overlayHeight / height, 1, 1); \n\
220+ } \n\
221+ }\n';
222+
223+// multiple row version of HeaderRowCode
224+function kHeaderRowCodeGenerator() {
225+ var kHeaderRowCodeTemplate = 'Row { \n\
226+ id: row; \n\
227+ objectName: "outerRow"; \n\
228+ property real margins: units.gu(1); \n\
229+ spacing: margins; \n\
230+ %2\
231+ anchors { %1 } \n\
232+ anchors.right: parent.right; \n\
233+ anchors.margins: margins; \n\
234+ anchors.rightMargin: 0; \n\
235+ data: [ \n\
236+ %3 \n\
237+ ] \n\
238+ }\n';
239+ var args = Array.prototype.slice.call(arguments);
240+ var isCardTool = args.shift();
241+ var heightCode = isCardTool ? "" : "height: root.fixedHeaderHeight; \n";
242+ var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(heightCode).arg(args.join(',\n'));
243+ return code;
244+}
245+
246+// multiple item version of kHeaderContainerCode
247+function kHeaderContainerCodeGenerator() {
248+ var headerContainerCodeTemplate = 'Item { \n\
249+ id: headerTitleContainer; \n\
250+ anchors { %1 } \n\
251+ width: parent.width - x; \n\
252+ implicitHeight: %2; \n\
253+ data: [ \n\
254+ %3 \n\
255+ ]\n\
256+ }\n';
257+ var args = Array.prototype.slice.call(arguments);
258+ var code = headerContainerCodeTemplate.arg(args.shift()).arg(args.shift()).arg(args.join(',\n'));
259+ return code;
260+}
261+
262+// %1 is used as anchors of mascotShapeLoader
263+// %2 is whether the loader should be asynchronous or not
264+var kMascotShapeLoaderCode = 'Loader { \n\
265+ id: mascotShapeLoader; \n\
266+ objectName: "mascotShapeLoader"; \n\
267+ asynchronous: %2; \n\
268+ active: mascotImage.status === Image.Ready; \n\
269+ visible: showHeader && active && status === Loader.Ready; \n\
270+ width: units.gu(6); \n\
271+ height: units.gu(5.625); \n\
272+ sourceComponent: UbuntuShape { aspect: UbuntuShape.Flat; image: mascotImage } \n\
273+ anchors { %1 } \n\
274+ }\n';
275+
276+// %1 is used as anchors of mascotImage
277+// %2 is used as visible of mascotImage
278+// %3 is injected as code to mascotImage
279+// %4 is used as fallback image
280+var kMascotImageCode = 'CroppedImageMinimumSourceSize { \n\
281+ id: mascotImage; \n\
282+ objectName: "mascotImage"; \n\
283+ anchors { %1 } \n\
284+ source: cardData && cardData["mascot"] || %4; \n\
285+ width: units.gu(6); \n\
286+ height: units.gu(5.625); \n\
287+ horizontalAlignment: Image.AlignHCenter; \n\
288+ verticalAlignment: Image.AlignVCenter; \n\
289+ visible: %2; \n\
290+ %3 \n\
291+ }\n';
292+
293+// %1 is used as anchors of titleLabel
294+// %2 is used as color of titleLabel
295+// %3 is used as extra condition for visible of titleLabel
296+// %4 is used as title width
297+// %5 is used as horizontal alignment
298+var kTitleLabelCode = 'Label { \n\
299+ id: titleLabel; \n\
300+ objectName: "titleLabel"; \n\
301+ anchors { %1 } \n\
302+ elide: Text.ElideRight; \n\
303+ fontSize: "small"; \n\
304+ wrapMode: Text.Wrap; \n\
305+ maximumLineCount: 2; \n\
306+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
307+ color: %2; \n\
308+ visible: showHeader %3; \n\
309+ width: %4; \n\
310+ text: root.title; \n\
311+ font.weight: Font.Normal; \n\
312+ horizontalAlignment: %5; \n\
313+ }\n';
314+
315+// %1 is used as extra anchors of emblemIcon
316+// %2 is used as color of emblemIcon
317+// FIXME The width code is a
318+// Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293
319+var kEmblemIconCode = 'Icon { \n\
320+ id: emblemIcon; \n\
321+ objectName: "emblemIcon"; \n\
322+ anchors { \n\
323+ bottom: titleLabel.baseline; \n\
324+ right: parent.right; \n\
325+ %1 \n\
326+ } \n\
327+ source: cardData && cardData["emblem"] || ""; \n\
328+ color: %2; \n\
329+ height: source != "" ? titleLabel.font.pixelSize : 0; \n\
330+ width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth; \n\
331+ }\n';
332+
333+// %1 is used as anchors of touchdown effect
334+var kTouchdownCode = 'Loader { \n\
335+ active: root.pressed; \n\
336+ anchors { %1 } \n\
337+ sourceComponent: UbuntuShape { \n\
338+ objectName: "touchdown"; \n\
339+ anchors.fill: parent; \n\
340+ radius: "small"; \n\
341+ borderSource: "radius_pressed.sci" \n\
342+ } \n\
343+ }\n';
344+
345+// %1 is used as anchors of subtitleLabel
346+// %2 is used as color of subtitleLabel
347+var kSubtitleLabelCode = 'Label { \n\
348+ id: subtitleLabel; \n\
349+ objectName: "subtitleLabel"; \n\
350+ anchors { %1 } \n\
351+ anchors.topMargin: units.dp(2); \n\
352+ elide: Text.ElideRight; \n\
353+ maximumLineCount: 1; \n\
354+ fontSize: "x-small"; \n\
355+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
356+ color: %2; \n\
357+ visible: titleLabel.visible && titleLabel.text; \n\
358+ text: cardData && cardData["subtitle"] || ""; \n\
359+ font.weight: Font.Light; \n\
360+ }\n';
361+
362+// %1 is used as anchors of attributesRow
363+// %2 is used as color of attributesRow
364+var kAttributesRowCode = 'CardAttributes { \n\
365+ id: attributesRow; \n\
366+ objectName: "attributesRow"; \n\
367+ anchors { %1 } \n\
368+ color: %2; \n\
369+ fontScale: root.fontScale; \n\
370+ model: cardData && cardData["attributes"]; \n\
371+ }\n';
372+
373+// %1 is used as anchors of socialActionsRow
374+// %2 is used as color of socialActionsRow
375+var kSocialActionsRowCode = 'CardSocialActions { \n\
376+ id: socialActionsRow; \n\
377+ objectName: "socialActionsRow"; \n\
378+ anchors { %1 } \n\
379+ color: %2; \n\
380+ model: cardData && cardData["socialActions"]; \n\
381+ onClicked: root.action(actionId); \n\
382+ }\n';
383+
384+// %1 is used as top anchor of summary
385+// %2 is used as topMargin anchor of summary
386+// %3 is used as color of summary
387+var kSummaryLabelCode = 'Label { \n\
388+ id: summary; \n\
389+ objectName: "summaryLabel"; \n\
390+ anchors { \n\
391+ top: %1; \n\
392+ left: parent.left; \n\
393+ right: parent.right; \n\
394+ margins: units.gu(1); \n\
395+ topMargin: %2; \n\
396+ } \n\
397+ wrapMode: Text.Wrap; \n\
398+ maximumLineCount: 5; \n\
399+ elide: Text.ElideRight; \n\
400+ text: cardData && cardData["summary"] || ""; \n\
401+ height: text ? implicitHeight : 0; \n\
402+ fontSize: "x-small"; \n\
403+ font.weight: Font.Light; \n\
404+ color: %3; \n\
405+ }\n';
406+
407+// %1 is used as bottom anchor of audio progress bar
408+// %2 is used as left anchor of audio progress bar
409+// %3 is used as text color
410+var kAudioProgressBarCode = 'CardAudioProgress { \n\
411+ id: audioProgressBar; \n\
412+ duration: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["duration"]) || 0; \n\
413+ source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
414+ anchors { \n\
415+ bottom: %1; \n\
416+ left: %2; \n\
417+ right: parent.right; \n\
418+ margins: units.gu(1); \n\
419+ } \n\
420+ color: %3; \n\
421+ }';
422+
423+function sanitizeColor(colorString) {
424+ if (colorString !== undefined) {
425+ if (colorString.match(/^[#a-z0-9]*$/i) === null) {
426+ // This is not the perfect regexp for color
427+ // but what we're trying to do here is just protect
428+ // against injection so it's ok
429+ return "";
430+ }
431+ }
432+ return colorString;
433+}
434+
435+function cardString(template, components, isCardTool, artShapeStyle, categoryLayout) {
436+ var code;
437+
438+ var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
439+
440+ code = 'AbstractButton { \n\
441+ id: root; \n\
442+ property var cardData; \n\
443+ property string backgroundShapeStyle: "flat"; \n\
444+ property real fontScale: 1.0; \n\
445+ property var scopeStyle: null; \n\
446+ readonly property string title: cardData && cardData["title"] || ""; \n\
447+ property bool showHeader: true; \n\
448+ implicitWidth: childrenRect.width; \n\
449+ enabled: %1; \n\
450+ \n'.arg(templateInteractive);
451+
452+ if (!isCardTool) {
453+ code += "property int fixedHeaderHeight: -1; \n\
454+ property size fixedArtShapeSize: Qt.size(-1, -1); \n";
455+ }
456+
457+ var hasArt = components["art"] && components["art"]["field"] || false;
458+ var hasSummary = components["summary"] || false;
459+ var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false;
460+ var artAndSummary = hasArt && hasSummary && !isConciergeMode;
461+ var isHorizontal = template["card-layout"] === "horizontal";
462+ var hasBackground = (!isHorizontal && (template["card-background"] || components["background"] || artAndSummary)) ||
463+ (hasSummary && (template["card-background"] || components["background"]));
464+ var hasTitle = components["title"] || false;
465+ var hasMascot = components["mascot"] || false;
466+ var hasEmblem = components["emblem"] && !(hasMascot && template["card-size"] === "small") || false;
467+ var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
468+ var hasSubtitle = hasTitle && components["subtitle"] || false;
469+ var hasHeaderRow = hasMascot && hasTitle;
470+ var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
471+ var hasSocialActions = hasTitle && components["social-actions"] || false;
472+ var isAudio = template["quick-preview-type"] === "audio";
473+ var asynchronous = isCardTool ? "false" : "true";
474+
475+ code += 'signal action(var actionId);\n';
476+ if (isAudio) {
477+ // For now we only support audio cards with [optional] art, title, subtitle
478+ // in horizontal mode
479+ // Anything else makes it behave not like an audio card
480+ if (hasSummary) isAudio = false;
481+ if (!isHorizontal) isAudio = false;
482+ if (hasMascot) isAudio = false;
483+ if (hasEmblem) isAudio = false;
484+ if (headerAsOverlay) isAudio = false;
485+ if (hasAttributes) isAudio = false;
486+ }
487+
488+ if (hasBackground) {
489+ var templateCardBackground;
490+ if (template && typeof template["card-background"] === "string") {
491+ templateCardBackground = 'decodeURI("' + encodeURI(template["card-background"]) + '")';
492+ } else {
493+ templateCardBackground = '""';
494+ }
495+
496+ var backgroundElements0;
497+ var backgroundElements1;
498+ if (template && typeof template["card-background"] === "object" && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
499+ var element0 = sanitizeColor(template["card-background"]["elements"][0]);
500+ var element1 = sanitizeColor(template["card-background"]["elements"][1]);
501+ if (element0 !== undefined) {
502+ backgroundElements0 = '"%1"'.arg(element0);
503+ }
504+ if (element1 !== undefined) {
505+ backgroundElements1 = '"%1"'.arg(element1);
506+ }
507+ }
508+ code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(asynchronous).arg(templateCardBackground);
509+ }
510+
511+ if (hasArt) {
512+ var artShapeAspect;
513+ if (isCardTool) {
514+ code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
515+
516+ var artShapeAspect = components["art"] && components["art"]["aspect-ratio"] || 1;
517+ if (isNaN(artShapeAspect)) {
518+ artShapeAspect = 1;
519+ }
520+ } else {
521+ artShapeAspect = "(root.fixedArtShapeSize.width / root.fixedArtShapeSize.height)";
522+ }
523+
524+ var widthCode, heightCode;
525+ var artAnchors;
526+ if (isHorizontal) {
527+ artAnchors = 'left: parent.left';
528+ if (hasMascot || hasTitle) {
529+ widthCode = 'height * ' + artShapeAspect;
530+ heightCode = 'headerHeight + 2 * units.gu(1)';
531+ } else {
532+ // This side of the else is a bit silly, who wants an horizontal layout without mascot and title?
533+ // So we define a "random" height of the image height + 2 gu for the margins
534+ widthCode = 'height * ' + artShapeAspect
535+ heightCode = 'units.gu(7.625)';
536+ }
537+ } else {
538+ artAnchors = 'horizontalCenter: parent.horizontalCenter;';
539+ widthCode = 'root.width'
540+ heightCode = 'width / ' + artShapeAspect;
541+ }
542+
543+ var fallback = !isCardTool && components["art"] && components["art"]["fallback"] || "";
544+ fallback = encodeURI(fallback);
545+ var fallbackStatusCode = "";
546+ var fallbackURICode = '""';
547+ if (fallback !== "") {
548+ // fallbackStatusCode has %8 in it because we want to substitute it for fallbackURICode
549+ // which in kArtShapeHolderCode is %8
550+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';
551+ fallbackURICode = 'decodeURI("%1")'.arg(fallback);
552+ }
553+ var artShapeHolderShapeCode;
554+ if (!isConciergeMode) {
555+ if (artShapeStyle === "icon") {
556+ artShapeHolderShapeCode = kArtProportionalShapeCode;
557+ } else {
558+ var artShapeHolderShapeAspect;
559+ switch (artShapeStyle) {
560+ case "inset": artShapeHolderShapeAspect = "UbuntuShape.Inset"; break;
561+ case "shadow": artShapeHolderShapeAspect = "UbuntuShape.DropShadow"; break;
562+ default:
563+ case "flat": artShapeHolderShapeAspect = "UbuntuShape.Flat"; break;
564+ }
565+ artShapeHolderShapeCode = kArtUbuntuShapeCode.arg(artShapeHolderShapeAspect);
566+ }
567+ } else {
568+ artShapeHolderShapeCode = "";
569+ }
570+ var artShapeHolderCode = isCardTool ? kArtShapeHolderCodeCardToolCard : kArtShapeHolderCode;
571+ code += artShapeHolderCode.arg(artAnchors)
572+ .arg(widthCode)
573+ .arg(heightCode)
574+ .arg(isConciergeMode ? "true" : "false")
575+ .arg(asynchronous)
576+ .arg(artShapeHolderShapeCode)
577+ .arg(fallbackStatusCode)
578+ .arg(fallbackURICode);
579+ } else if (isCardTool) {
580+ code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
581+ }
582+
583+ if (headerAsOverlay) {
584+ var headerHeightCode = isCardTool ? "headerHeight" : "root.fixedHeaderHeight";
585+ code += kOverlayLoaderCode.arg(asynchronous).arg(headerHeightCode);
586+ }
587+
588+ var headerVerticalAnchors;
589+ if (headerAsOverlay) {
590+ headerVerticalAnchors = 'bottom: artShapeLoader.bottom; \n\
591+ bottomMargin: units.gu(1);\n';
592+ } else {
593+ if (hasArt) {
594+ if (isHorizontal) {
595+ headerVerticalAnchors = 'top: artShapeLoader.top; \n\
596+ topMargin: units.gu(1);\n';
597+ } else {
598+ headerVerticalAnchors = 'top: artShapeLoader.bottom; \n\
599+ topMargin: units.gu(1);\n';
600+ }
601+ } else {
602+ headerVerticalAnchors = 'top: parent.top; \n\
603+ topMargin: units.gu(1);\n';
604+ }
605+ }
606+
607+ var headerLeftAnchor;
608+ var headerLeftAnchorHasMargin = false;
609+ if (isHorizontal && hasArt) {
610+ headerLeftAnchor = 'left: artShapeLoader.right; \n\
611+ leftMargin: units.gu(1);\n';
612+ headerLeftAnchorHasMargin = true;
613+ } else if (isHorizontal && isAudio) {
614+ headerLeftAnchor = 'left: audioButton.right; \n\
615+ leftMargin: units.gu(1);\n';
616+ headerLeftAnchorHasMargin = true;
617+ } else {
618+ headerLeftAnchor = 'left: parent.left;\n';
619+ }
620+
621+ var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary && !isAudio;
622+
623+ if (hasHeaderRow) {
624+ code += 'readonly property int headerHeight: row.height;\n'
625+ } else if (hasMascot) {
626+ code += 'readonly property int headerHeight: mascotImage.height;\n'
627+ } else if (hasAttributes) {
628+ if (hasTitle && hasSubtitle) {
629+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + attributesRow.height + attributesRow.anchors.topMargin;\n'
630+ } else if (hasTitle) {
631+ code += 'readonly property int headerHeight: titleLabel.height + attributesRow.height + attributesRow.anchors.topMargin;\n'
632+ } else {
633+ code += 'readonly property int headerHeight: attributesRow.height;\n'
634+ }
635+ } else if (isAudio) {
636+ if (hasSubtitle) {
637+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
638+ } else if (hasTitle) {
639+ code += 'readonly property int headerHeight: titleLabel.height + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
640+ } else {
641+ code += 'readonly property int headerHeight: audioProgressBar.height;\n'
642+ }
643+ } else if (hasSubtitle) {
644+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
645+ } else if (hasTitle) {
646+ code += 'readonly property int headerHeight: titleLabel.height;\n'
647+ } else {
648+ code += 'readonly property int headerHeight: 0;\n'
649+ }
650+
651+ var mascotShapeCode = '';
652+ var mascotCode = '';
653+ if (hasMascot) {
654+ var useMascotShape = !hasBackground && !headerAsOverlay;
655+ var mascotAnchors = '';
656+ if (!hasHeaderRow) {
657+ mascotAnchors += headerLeftAnchor;
658+ mascotAnchors += headerVerticalAnchors;
659+ if (!headerLeftAnchorHasMargin) {
660+ mascotAnchors += 'leftMargin: units.gu(1);\n'
661+ }
662+ } else {
663+ mascotAnchors = 'verticalCenter: parent.verticalCenter;'
664+ }
665+
666+ if (useMascotShape) {
667+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors).arg(asynchronous);
668+ }
669+
670+ var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
671+ var fallback = !isCardTool && components["mascot"] && components["mascot"]["fallback"] || "";
672+ fallback = encodeURI(fallback);
673+ var fallbackStatusCode = "";
674+ var fallbackURICode = '""';
675+ if (fallback !== "") {
676+ // fallbackStatusCode has %4 in it because we want to substitute it for fallbackURICode
677+ // which in kMascotImageCode is %4
678+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %4;';
679+ fallbackURICode = 'decodeURI("%1")'.arg(fallback);
680+ }
681+ mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible).arg(fallbackStatusCode).arg(fallbackURICode);
682+ }
683+
684+ var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white")';
685+
686+ var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
687+ var titleSubtitleCode = '';
688+ if (hasTitle) {
689+ var titleColor;
690+ if (headerAsOverlay) {
691+ titleColor = 'root.scopeStyle && overlayLoader.item ? root.scopeStyle.getTextColor(overlayLoader.item.luminance) : (overlayLoader.item && overlayLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white")';
692+ } else if (hasSummary) {
693+ titleColor = 'summary.color';
694+ } else if (hasBackground) {
695+ titleColor = summaryColorWithBackground;
696+ } else {
697+ titleColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
698+ }
699+
700+ var titleAnchors;
701+ var subtitleAnchors;
702+ var attributesAnchors;
703+ var titleContainerAnchors;
704+ var titleRightAnchor;
705+ var titleWidth = "undefined";
706+
707+ var extraRightAnchor = '';
708+ var extraLeftAnchor = '';
709+ if (!touchdownOnArtShape) {
710+ extraRightAnchor = 'rightMargin: units.gu(1); \n';
711+ extraLeftAnchor = 'leftMargin: units.gu(1); \n';
712+ } else if (headerAsOverlay && !hasEmblem) {
713+ extraRightAnchor = 'rightMargin: units.gu(1); \n';
714+ }
715+
716+ if (hasMascot) {
717+ titleContainerAnchors = 'verticalCenter: parent.verticalCenter; ';
718+ } else {
719+ titleContainerAnchors = 'right: parent.right; ';
720+ titleContainerAnchors += headerLeftAnchor;
721+ titleContainerAnchors += headerVerticalAnchors;
722+ if (!headerLeftAnchorHasMargin) {
723+ titleContainerAnchors += extraLeftAnchor;
724+ }
725+ }
726+ if (hasEmblem) {
727+ titleRightAnchor = 'right: emblemIcon.left; \n\
728+ rightMargin: emblemIcon.width > 0 ? units.gu(0.5) : 0; \n';
729+ } else {
730+ titleRightAnchor = 'right: parent.right; \n'
731+ titleRightAnchor += extraRightAnchor;
732+ }
733+
734+ if (hasTitleContainer) {
735+ // Using headerTitleContainer
736+ titleAnchors = titleRightAnchor;
737+ titleAnchors += 'left: parent.left; \n\
738+ top: parent.top;';
739+ subtitleAnchors = 'right: parent.right; \n\
740+ left: parent.left; \n';
741+ subtitleAnchors += extraRightAnchor;
742+ if (hasSubtitle) {
743+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
744+ subtitleAnchors += 'top: titleLabel.bottom;\n';
745+ } else {
746+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
747+ }
748+ } else if (hasMascot) {
749+ // Using row without titleContainer
750+ titleAnchors = 'verticalCenter: parent.verticalCenter;\n';
751+ titleWidth = "parent.width - x";
752+ } else {
753+ if (headerAsOverlay) {
754+ // Using anchors to the overlay
755+ titleAnchors = titleRightAnchor;
756+ titleAnchors += 'left: parent.left; \n\
757+ leftMargin: units.gu(1); \n\
758+ top: overlayLoader.top; \n\
759+ topMargin: units.gu(1) + overlayLoader.height - overlayLoader.overlayHeight; \n';
760+ } else {
761+ // Using anchors to the mascot/parent
762+ titleAnchors = titleRightAnchor;
763+ titleAnchors += headerLeftAnchor;
764+ titleAnchors += headerVerticalAnchors;
765+ if (!headerLeftAnchorHasMargin) {
766+ titleAnchors += extraLeftAnchor;
767+ }
768+ }
769+ subtitleAnchors = 'left: titleLabel.left; \n\
770+ leftMargin: titleLabel.leftMargin; \n';
771+ subtitleAnchors += extraRightAnchor;
772+ if (hasEmblem) {
773+ // using container
774+ subtitleAnchors += 'right: parent.right; \n';
775+ } else {
776+ subtitleAnchors += 'right: titleLabel.right; \n';
777+ }
778+
779+ if (hasSubtitle) {
780+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
781+ subtitleAnchors += 'top: titleLabel.bottom;\n';
782+ } else {
783+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
784+ }
785+ }
786+
787+ var titleAlignment = "Text.AlignHCenter";
788+ if (template["card-layout"] === "horizontal"
789+ || typeof components["title"] !== "object"
790+ || components["title"]["align"] === "left") titleAlignment = "Text.AlignLeft";
791+ var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
792+ for (var key in keys) {
793+ key = keys[key];
794+ try {
795+ if (typeof components[key] === "string"
796+ || typeof components[key]["field"] === "string") titleAlignment = "Text.AlignLeft";
797+ } catch (e) {
798+ continue;
799+ }
800+ }
801+
802+ // code for different elements
803+ var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
804+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth).arg(titleAlignment);
805+ var subtitleCode;
806+ var attributesCode;
807+
808+ // code for the title container
809+ var containerCode = [];
810+ var containerHeight = 'titleLabel.height';
811+ containerCode.push(titleCode);
812+ if (hasSubtitle) {
813+ subtitleCode = kSubtitleLabelCode.arg(subtitleAnchors).arg(titleColor);
814+ containerCode.push(subtitleCode);
815+ containerHeight += ' + subtitleLabel.height';
816+ }
817+ if (hasEmblem) {
818+ containerCode.push(kEmblemIconCode.arg(extraRightAnchor).arg(titleColor));
819+ }
820+ if (hasAttributes) {
821+ attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(titleColor);
822+ containerCode.push(attributesCode);
823+ containerHeight += ' + attributesRow.height';
824+ }
825+
826+ if (hasTitleContainer) {
827+ // use container
828+ titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, containerHeight, containerCode);
829+ } else {
830+ // no container
831+ titleSubtitleCode = titleCode;
832+ if (hasSubtitle) {
833+ titleSubtitleCode += subtitleCode;
834+ }
835+ if (hasAttributes) {
836+ titleSubtitleCode += attributesCode;
837+ }
838+ }
839+ }
840+
841+ if (hasHeaderRow) {
842+ var rowCode = [mascotCode, titleSubtitleCode];
843+ if (mascotShapeCode != '') {
844+ rowCode.unshift(mascotShapeCode);
845+ }
846+ code += kHeaderRowCodeGenerator(isCardTool, headerVerticalAnchors + headerLeftAnchor, rowCode)
847+ } else {
848+ code += mascotShapeCode + mascotCode + titleSubtitleCode;
849+ }
850+
851+ if (isAudio) {
852+ var audioProgressBarLeftAnchor = 'audioButton.right';
853+ var audioProgressBarBottomAnchor = 'audioButton.bottom';
854+ var audioProgressBarTextColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
855+
856+ code += kAudioProgressBarCode.arg(audioProgressBarBottomAnchor)
857+ .arg(audioProgressBarLeftAnchor)
858+ .arg(audioProgressBarTextColor);
859+
860+ var audioButtonAnchorsFill;
861+ var audioButtonWidth;
862+ var audioButtonHeight;
863+ if (hasArt) {
864+ audioButtonAnchorsFill = 'artShapeLoader';
865+ audioButtonWidth = 'undefined';
866+ audioButtonHeight = 'undefined';
867+ } else {
868+ audioButtonAnchorsFill = 'undefined';
869+ audioButtonWidth = 'height';
870+ audioButtonHeight = isCardTool ? 'headerHeight + 2 * units.gu(1)'
871+ : 'root.fixedHeaderHeight + 2 * units.gu(1)';
872+ }
873+ code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight).arg(asynchronous);
874+ }
875+
876+ if (hasSummary) {
877+ var summaryTopAnchor;
878+ if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeLoader.bottom';
879+ else if (headerAsOverlay && hasArt) summaryTopAnchor = 'artShapeLoader.bottom';
880+ else if (hasHeaderRow) summaryTopAnchor = 'row.bottom';
881+ else if (hasTitleContainer) summaryTopAnchor = 'headerTitleContainer.bottom';
882+ else if (hasMascot) summaryTopAnchor = 'mascotImage.bottom';
883+ else if (hasAttributes) summaryTopAnchor = 'attributesRow.bottom';
884+ else if (hasSubtitle) summaryTopAnchor = 'subtitleLabel.bottom';
885+ else if (hasTitle) summaryTopAnchor = 'titleLabel.bottom';
886+ else if (hasArt) summaryTopAnchor = 'artShapeLoader.bottom';
887+ else summaryTopAnchor = 'parent.top';
888+
889+ var summaryColor;
890+ if (hasBackground) {
891+ summaryColor = summaryColorWithBackground;
892+ } else {
893+ summaryColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
894+ }
895+
896+ var summaryTopMargin = (hasMascot || hasSubtitle || hasAttributes ? 'anchors.margins' : '0');
897+
898+ code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
899+ }
900+
901+ if (hasSocialActions) {
902+ var socialAnchors;
903+ var socialTopAnchor;
904+
905+ if (hasSummary) socialTopAnchor = 'summary.bottom;';
906+ else if (isHorizontal && hasArt) socialTopAnchor = 'artShapeLoader.bottom;';
907+ else if (headerAsOverlay && hasArt) socialTopAnchor = 'artShapeLoader.bottom;';
908+ else if (hasHeaderRow) socialTopAnchor = 'row.bottom;';
909+ else if (hasTitleContainer) socialTopAnchor = 'headerTitleContainer.bottom;';
910+ else if (hasMascot) socialTopAnchor = 'mascotImage.bottom;';
911+ else if (hasAttributes) socialTopAnchor = 'attributesRow.bottom;';
912+ else if (hasSubtitle) socialTopAnchor = 'subtitleLabel.bottom;';
913+ else if (hasTitle) socialTopAnchor = 'titleLabel.bottom;';
914+ else if (hasArt) socialTopAnchor = 'artShapeLoader.bottom;';
915+ else socialTopAnchor = 'parent.top';
916+
917+ socialAnchors = 'top: ' + socialTopAnchor + ' left: parent.left; right: parent.right; topMargin: units.gu(1);'
918+
919+ var socialColor;
920+ if (hasBackground) {
921+ socialColor = summaryColorWithBackground;
922+ } else {
923+ socialColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
924+ }
925+
926+ code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor);
927+ }
928+
929+ if (artShapeStyle != "shadow" && artShapeStyle != "icon" && !isCardTool) {
930+ var touchdownAnchors;
931+ if (hasBackground) {
932+ touchdownAnchors = 'fill: backgroundLoader';
933+ } else if (touchdownOnArtShape) {
934+ touchdownAnchors = 'fill: artShapeLoader';
935+ } else {
936+ touchdownAnchors = 'fill: root'
937+ }
938+ code += kTouchdownCode.arg(touchdownAnchors);
939+ }
940+
941+ if (isCardTool || categoryLayout !== "grid") {
942+ var implicitHeight = 'implicitHeight: ';
943+ if (hasSocialActions) {
944+ implicitHeight += 'socialActionsRow.y + socialActionsRow.height + units.gu(1);\n';
945+ } else if (hasSummary) {
946+ implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
947+ } else if (isAudio) {
948+ implicitHeight += 'audioButton.height;\n';
949+ } else if (headerAsOverlay) {
950+ implicitHeight += 'artShapeLoader.height;\n';
951+ } else if (hasHeaderRow) {
952+ implicitHeight += 'row.y + row.height + units.gu(1);\n';
953+ } else if (hasMascot) {
954+ implicitHeight += 'mascotImage.y + mascotImage.height;\n';
955+ } else if (hasTitleContainer) {
956+ implicitHeight += 'headerTitleContainer.y + headerTitleContainer.height + units.gu(1);\n';
957+ } else if (hasAttributes) {
958+ implicitHeight += 'attributesRow.y + attributesRow.height + units.gu(1);\n';
959+ } else if (hasSubtitle) {
960+ implicitHeight += 'subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
961+ } else if (hasTitle) {
962+ implicitHeight += 'titleLabel.y + titleLabel.height + units.gu(1);\n';
963+ } else if (hasArt) {
964+ implicitHeight += 'artShapeLoader.height;\n';
965+ } else {
966+ implicitHeight = '';
967+ }
968+ } else {
969+ implicitHeight = '';
970+ }
971+
972+ // Close the AbstractButton
973+ code += implicitHeight + '}\n';
974+
975+ return code;
976+}
977+
978+function createCardComponent(parent, template, components, isCardTool, artShapeStyle, categoryLayout, identifier) {
979+ var imports = 'import QtQuick 2.4; \n\
980+ import Ubuntu.Components 1.3; \n\
981+ import Ubuntu.Settings.Components 0.1; \n\
982+ import Dash 0.1;\n\
983+ import Utils 0.1;\n';
984+ var card = cardString(template, components, isCardTool, artShapeStyle, categoryLayout);
985+ var code = imports + 'Component {\n' + card + '}\n';
986+
987+ try {
988+ return Qt.createQmlObject(code, parent, identifier);
989+ } catch (e) {
990+ console.error("ERROR: Invalid component created.");
991+ console.error("Template:");
992+ console.error(JSON.stringify(template));
993+ console.error("Components:");
994+ console.error(JSON.stringify(components));
995+ console.error("Code:");
996+ console.error(code);
997+ throw e;
998+ }
999+}
plugins/Dash/CardCreatorCache.qmlnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+pragma Singleton
18+import QtQuick 2.4
19+import "CardCreator.js" as CardCreator
20+
21+QtObject {
22+ id: root
23+
24+ property var cache: new Object();
25+
26+ function getCardComponent(template, components, isCardTool, artShapeStyle, categoryLayout) {
27+ if (template === undefined || components === undefined)
28+ return undefined;
29+
30+ var tString = JSON.stringify(template);
31+ var cString = JSON.stringify(components);
32+ var allString = tString + cString + isCardTool + artShapeStyle + categoryLayout;
33+ var component = cache[allString];
34+ if (component === undefined) {
35+ component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, categoryLayout, allString);
36+ cache[allString] = component;
37+ }
38+ return component;
39+ }
40+}
plugins/Dash/CardSocialActions.qmlnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright 2016 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+
21+Column {
22+ id: socialActions
23+ spacing: units.gu(0.5)
24+
25+ property alias model: repeater.model
26+ property color color: theme.palette.normal.baseText
27+
28+ signal clicked(var actionId)
29+
30+ Rectangle {
31+ id: divider
32+ visible: repeater.count > 0
33+ anchors {
34+ left: parent.left;
35+ right: parent.right;
36+ leftMargin:units.dp(1);
37+ rightMargin: units.dp(1);
38+ }
39+ color: Qt.darker(theme.palette.normal.background, 1.12)
40+ height: visible ? units.dp(1) : 0
41+ }
42+
43+ Row {
44+ id: row
45+ anchors {
46+ left: parent.left
47+ right: parent.right
48+ leftMargin: units.gu(1)
49+ rightMargin: units.gu(1)
50+ }
51+ spacing: units.gu(2)
52+ readonly property int visibleItems: {
53+ if (width <= units.gu(12)) // small card
54+ return 2;
55+ else if (width <= units.gu(21)) // medium card
56+ return 3;
57+ else // large or horizontal card
58+ return 4;
59+ }
60+
61+ Repeater {
62+ id: repeater
63+ delegate: Loader {
64+ height: units.gu(2)
65+ active: index < row.visibleItems
66+ sourceComponent: AbstractButton {
67+ objectName: "delegate" + index
68+ height: units.gu(2)
69+ width: icon.width
70+ Icon {
71+ id: icon
72+ objectName: "icon"
73+
74+ readonly property url urlIcon: modelData && modelData["icon"] || ""
75+ readonly property url urlTemporaryIcon: "temporaryIcon" in modelData && modelData["temporaryIcon"] || ""
76+
77+ height: units.gu(2)
78+ // FIXME Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293
79+ width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth
80+ source: urlIcon
81+ color: socialActions.color
82+
83+ onUrlIconChanged: {
84+ if (urlIcon) source = urlIcon
85+ }
86+ }
87+
88+ onClicked: socialActions.clicked(modelData["id"]);
89+ onPressedChanged: if (pressed && icon.urlTemporaryIcon != "") icon.source = icon.urlTemporaryIcon
90+ }
91+ }
92+ }
93+ }
94+}
plugins/Dash/CroppedImageMinimumSourceSize.qmlnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 2014, 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+
19+Image {
20+ id: root
21+
22+ fillMode: Image.PreserveAspectCrop
23+
24+ property bool useHeight: false
25+ function updateUseHeight()
26+ {
27+ // Do not turn into a binding since otherwise the qml
28+ // engine complains about binding loops
29+ useHeight = (implicitWidth / implicitHeight) > (width / height);
30+ }
31+
32+ onHeightChanged: updateUseHeight();
33+ onWidthChanged: updateUseHeight();
34+ onImplicitHeightChanged: updateUseHeight();
35+ onImplicitWidthChanged: updateUseHeight();
36+
37+ sourceSize: useHeight ? Qt.size(0, height) : Qt.size(width, 0)
38+}
plugins/Dash/DashAudioPlayer.qmlnew file+120
@@ -0,0 +1,120 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+pragma Singleton
18+import QtQuick 2.4
19+import QtMultimedia 5.6
20+import Dash 0.1
21+
22+QtObject {
23+ id: root
24+ readonly property real progress: priv.audio ? priv.audio.position / priv.audio.duration : 0.0
25+ readonly property bool playing: priv.audio ? priv.audio.playbackState === Audio.PlayingState : false
26+ readonly property bool paused: priv.audio ? priv.audio.playbackState === Audio.PausedState : false
27+ readonly property bool stopped: priv.audio ? priv.audio.playbackState === Audio.StoppedState : true
28+ readonly property int position: priv.audio ? priv.audio.position : 0
29+ readonly property url currentSource: priv.audio ? priv.audio.playlist.currentItemSource : ""
30+ readonly property Playlist playlist: priv.audio ? priv.audio.playlist : null
31+
32+ function playSource(newSource, newPlaylist) {
33+ if (!priv.audio) {
34+ console.info("DashAudioPlayer: creating player");
35+ priv.audio = priv.audioComponent.createObject(root);
36+ }
37+ stop();
38+ priv.audio.playlist.clear();
39+ if (newPlaylist) {
40+ // Look for newSource in newPlaylist
41+ var sourceIndex = -1;
42+ for (var i in newPlaylist) {
43+ if (AudioUrlComparer.compare(newSource, newPlaylist[i])) {
44+ sourceIndex = i;
45+ break;
46+ }
47+ }
48+ var urls = [];
49+ if (sourceIndex === -1 && newSource != "") {
50+ // If the playing song is not in the playlist, add it
51+ urls.push(newSource);
52+ sourceIndex = 0;
53+ }
54+ for (var i in newPlaylist) {
55+ urls.push(newPlaylist[i]);
56+ }
57+ priv.audio.playlist.addItems(urls);
58+ priv.audio.playlist.currentIndex = sourceIndex;
59+ } else {
60+ priv.audio.playlist.addItem(newSource);
61+ priv.audio.playlist.currentIndex = 0;
62+ }
63+ play();
64+ }
65+
66+ function stop() {
67+ if (priv.audio) {
68+ priv.audio.stop();
69+ }
70+ }
71+
72+ function play() {
73+ if (priv.audio) {
74+ priv.audio.play();
75+ }
76+ }
77+
78+ function pause() {
79+ if (priv.audio) {
80+ priv.audio.pause();
81+ }
82+ }
83+
84+ property QtObject priv: QtObject {
85+ id: priv
86+ property Audio audio: null
87+ property Component audioComponent: Component {
88+ Audio {
89+ playlist: Playlist {
90+ objectName: "playlist"
91+ }
92+ /* Remove player in case of error so it gets recreated next time
93+ * we need it. Happens if backend media player restarted, for
94+ * instance. qtmultimedia should probably handle this
95+ * transparently (LP: #1616425).
96+ */
97+ onError: {
98+ console.warn("DashAudioPlayer: error event (" +
99+ priv.audio.errorString + "), destroying");
100+ priv.audio.destroy();
101+ }
102+ }
103+ }
104+ }
105+
106+ function lengthToString(s) {
107+ if (typeof(s) !== "number" || s < 0) return "";
108+
109+ var sec = "" + s % 60;
110+ if (sec.length == 1) sec = "0" + sec;
111+ var hour = Math.floor(s / 3600);
112+ if (hour < 1) {
113+ return Math.floor(s / 60) + ":" + sec;
114+ } else {
115+ var min = "" + Math.floor(s / 60) % 60;
116+ if (min.length == 1) min = "0" + min;
117+ return hour + ":" + min + ":" + sec;
118+ }
119+ }
120+}
plugins/Dash/ScopeStyle.qmlnew file+95
@@ -0,0 +1,95 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Utils 0.1
19+import Ubuntu.Components 1.3
20+
21+/*! \brief Helper for processing scope customization options.
22+
23+ It will take the customizations object passed by the scope and
24+ process it to provide the scope UI with data such as colors or
25+ image paths.
26+ */
27+
28+QtObject {
29+ /// Style object passed from the scope
30+ property var style: Object()
31+
32+ /// Color used for text and symbolic icons
33+ readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
34+
35+ /// Luminance of the foreground color
36+ readonly property real foregroundLuminance: foreground ? Style.luminance(foreground) : Style.luminance(d.defaultDark)
37+
38+ /// Color used for the overall background
39+ readonly property color background: "background-color" in style ? style["background-color"] : "#00f5f5f5"
40+
41+ /// Luminance of the background color
42+ readonly property real backgroundLuminance: background ? Style.luminance(background) : Style.luminance(d.defaultLight)
43+
44+ /*! \brief Get the most contrasting available color based on luminance
45+ *
46+ * If background color is transparent, theme provided colors are taken into account
47+ */
48+ function getTextColor(luminance) {
49+ if (Math.abs(foregroundLuminance - luminance) >
50+ Math.abs(d.opaqueBackgroundLuminance - luminance)) {
51+ return foreground;
52+ } else {
53+ return d.opaqueBackground;
54+ }
55+ }
56+
57+ /// Source of the logo image for the header
58+ readonly property url headerLogo: "logo" in d.headerStyle ? d.headerStyle["logo"] : ""
59+
60+ /// Background style for the header
61+ readonly property url headerBackground: "background" in d.headerStyle ? d.headerStyle["background"] : "color:///#ffffff"
62+
63+ /// Foreground color for the header
64+ readonly property color headerForeground: "foreground-color" in d.headerStyle ? d.headerStyle["foreground-color"] : foreground
65+
66+ /// Color of the header divider
67+ readonly property color headerDividerColor: "divider-color" in d.headerStyle ? d.headerStyle["divider-color"] : "#e0e0e0"
68+
69+ /// Background style for the navigation
70+ readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5"
71+
72+ /// Color of the primary preview button
73+ readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : theme.palette.normal.positive
74+
75+ //! @cond
76+ property var d: QtObject {
77+ // FIXME: should be taken from the theme
78+ readonly property color defaultLight: "white"
79+ readonly property color defaultDark: UbuntuColors.darkGrey
80+ readonly property real defaultLightLuminance: Style.luminance(defaultLight)
81+ readonly property real defaultDarkLuminance: Style.luminance(defaultDark)
82+
83+ readonly property color opaqueBackground: {
84+ background.a > 0 ?
85+ background :
86+ (Math.abs(foregroundLuminance - defaultLightLuminance) >
87+ Math.abs(foregroundLuminance - defaultDarkLuminance)) ?
88+ defaultLight : defaultDark
89+ }
90+ readonly property real opaqueBackgroundLuminance: Style.luminance(opaqueBackground)
91+
92+ readonly property var headerStyle: "page-header" in style ? style["page-header"] : { }
93+ }
94+ //! @endcond
95+}
plugins/Dash/abstractdashview.cppnew file+359
@@ -0,0 +1,359 @@
1+/*
2+ * Copyright (C) 2013, 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "abstractdashview.h"
18+
19+#include <private/qquickitem_p.h>
20+
21+AbstractDashView::AbstractDashView()
22+ : m_delegateModel(nullptr)
23+ , m_asyncRequestedIndex(-1)
24+ , m_columnSpacing(0)
25+ , m_rowSpacing(0)
26+ , m_buffer(320) // Same value as QML_VIEW_DEFAULTCACHEBUFFER in qquickitemview.cpp (Qt 5.6)
27+ , m_displayMarginBeginning(0)
28+ , m_displayMarginEnd(0)
29+ , m_needsRelayout(false)
30+ , m_delegateValidated(false)
31+ , m_implicitHeightDirty(false)
32+{
33+ connect(this, &AbstractDashView::widthChanged, this, &AbstractDashView::relayout);
34+ connect(this, &AbstractDashView::heightChanged, this, &AbstractDashView::onHeightChanged);
35+}
36+
37+QAbstractItemModel *AbstractDashView::model() const
38+{
39+ return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
40+}
41+
42+void AbstractDashView::setModel(QAbstractItemModel *model)
43+{
44+ if (model != this->model()) {
45+ if (!m_delegateModel) {
46+ createDelegateModel();
47+ } else {
48+ disconnect(m_delegateModel, &QQmlDelegateModel::modelUpdated, this, &AbstractDashView::onModelUpdated);
49+ }
50+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
51+ connect(m_delegateModel, &QQmlDelegateModel::modelUpdated, this, &AbstractDashView::onModelUpdated);
52+
53+ cleanupExistingItems();
54+
55+ Q_EMIT modelChanged();
56+ polish();
57+ }
58+}
59+
60+QQmlComponent *AbstractDashView::delegate() const
61+{
62+ return m_delegateModel ? m_delegateModel->delegate() : nullptr;
63+}
64+
65+void AbstractDashView::setDelegate(QQmlComponent *delegate)
66+{
67+ if (delegate != this->delegate()) {
68+ if (!m_delegateModel) {
69+ createDelegateModel();
70+ }
71+
72+ cleanupExistingItems();
73+
74+ m_delegateModel->setDelegate(delegate);
75+
76+ Q_EMIT delegateChanged();
77+ m_delegateValidated = false;
78+ polish();
79+ }
80+}
81+
82+qreal AbstractDashView::columnSpacing() const
83+{
84+ return m_columnSpacing;
85+}
86+
87+void AbstractDashView::setColumnSpacing(qreal columnSpacing)
88+{
89+ if (columnSpacing != m_columnSpacing) {
90+ m_columnSpacing = columnSpacing;
91+ Q_EMIT columnSpacingChanged();
92+
93+ if (isComponentComplete()) {
94+ relayout();
95+ }
96+ }
97+}
98+
99+qreal AbstractDashView::rowSpacing() const
100+{
101+ return m_rowSpacing;
102+}
103+
104+void AbstractDashView::setRowSpacing(qreal rowSpacing)
105+{
106+ if (rowSpacing != m_rowSpacing) {
107+ m_rowSpacing = rowSpacing;
108+ Q_EMIT rowSpacingChanged();
109+
110+ if (isComponentComplete()) {
111+ relayout();
112+ }
113+ }
114+}
115+
116+int AbstractDashView::cacheBuffer() const
117+{
118+ return m_buffer;
119+}
120+
121+void AbstractDashView::setCacheBuffer(int buffer)
122+{
123+ if (buffer < 0) {
124+ qmlInfo(this) << "Cannot set a negative cache buffer";
125+ return;
126+ }
127+
128+ if (m_buffer != buffer) {
129+ m_buffer = buffer;
130+ if (isComponentComplete()) {
131+ polish();
132+ }
133+ emit cacheBufferChanged();
134+ }
135+}
136+
137+qreal AbstractDashView::displayMarginBeginning() const
138+{
139+ return m_displayMarginBeginning;
140+}
141+
142+void AbstractDashView::setDisplayMarginBeginning(qreal begin)
143+{
144+ if (m_displayMarginBeginning == begin)
145+ return;
146+ m_displayMarginBeginning = begin;
147+ if (isComponentComplete()) {
148+ polish();
149+ }
150+ emit displayMarginBeginningChanged();
151+}
152+
153+qreal AbstractDashView::displayMarginEnd() const
154+{
155+ return m_displayMarginEnd;
156+}
157+
158+void AbstractDashView::setDisplayMarginEnd(qreal end)
159+{
160+ if (m_displayMarginEnd == end)
161+ return;
162+ m_displayMarginEnd = end;
163+ if (isComponentComplete()) {
164+ polish();
165+ }
166+ emit displayMarginEndChanged();
167+}
168+
169+void AbstractDashView::createDelegateModel()
170+{
171+ m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
172+ connect(m_delegateModel, &QQmlDelegateModel::createdItem, this, &AbstractDashView::itemCreated);
173+ if (isComponentComplete())
174+ m_delegateModel->componentComplete();
175+}
176+
177+void AbstractDashView::refill()
178+{
179+ if (!isComponentComplete() || height() < 0) {
180+ return;
181+ }
182+
183+ const qreal from = -m_displayMarginBeginning;
184+ const qreal to = height() + m_displayMarginEnd;
185+ const qreal bufferFrom = from - m_buffer;
186+ const qreal bufferTo = to + m_buffer;
187+
188+ bool added = addVisibleItems(from, to, false);
189+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
190+ added |= addVisibleItems(bufferFrom, bufferTo, true);
191+
192+ if (added || removed) {
193+ m_implicitHeightDirty = true;
194+ polish();
195+ }
196+}
197+
198+bool AbstractDashView::addVisibleItems(qreal fillFromY, qreal fillToY, bool asynchronous)
199+{
200+ if (fillToY <= fillFromY)
201+ return false;
202+
203+ if (!delegate())
204+ return false;
205+
206+ if (m_delegateModel->count() == 0)
207+ return false;
208+
209+ int modelIndex;
210+ qreal yPos;
211+ findBottomModelIndexToAdd(&modelIndex, &yPos);
212+ bool changed = false;
213+ while (modelIndex < m_delegateModel->count() && yPos <= fillToY) {
214+ if (!createItem(modelIndex, asynchronous))
215+ break;
216+
217+ changed = true;
218+ findBottomModelIndexToAdd(&modelIndex, &yPos);
219+ }
220+
221+ findTopModelIndexToAdd(&modelIndex, &yPos);
222+ while (modelIndex >= 0 && yPos > fillFromY) {
223+ if (!createItem(modelIndex, asynchronous))
224+ break;
225+
226+ changed = true;
227+ findTopModelIndexToAdd(&modelIndex, &yPos);
228+ }
229+
230+ return changed;
231+}
232+
233+QQuickItem *AbstractDashView::createItem(int modelIndex, bool asynchronous)
234+{
235+ if (asynchronous && m_asyncRequestedIndex != -1)
236+ return nullptr;
237+
238+ m_asyncRequestedIndex = -1;
239+ QObject* object = m_delegateModel->object(modelIndex, asynchronous);
240+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
241+ if (!item) {
242+ if (object) {
243+ m_delegateModel->release(object);
244+ if (!m_delegateValidated) {
245+ m_delegateValidated = true;
246+ QObject* delegateObj = delegate();
247+ qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
248+ }
249+ } else {
250+ m_asyncRequestedIndex = modelIndex;
251+ }
252+ return nullptr;
253+ } else {
254+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
255+ addItemToView(modelIndex, item);
256+ return item;
257+ }
258+}
259+
260+void AbstractDashView::releaseItem(QQuickItem *item)
261+{
262+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
263+ QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
264+ if (flags & QQmlDelegateModel::Destroyed) {
265+ item->setParentItem(nullptr);
266+ }
267+}
268+
269+void AbstractDashView::setImplicitHeightDirty()
270+{
271+ m_implicitHeightDirty = true;
272+}
273+
274+void AbstractDashView::itemCreated(int modelIndex, QObject *object)
275+{
276+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
277+ if (!item) {
278+ qWarning() << "AbstractDashView::itemCreated got a non item for index" << modelIndex;
279+ return;
280+ }
281+ item->setParentItem(this);
282+
283+ // We only need to call createItem if we are here because of an asynchronous generation
284+ // otherwise we are in this slot because createItem is creating the item sync
285+ // and thus we don't need to call createItem again, nor need to set m_implicitHeightDirty
286+ // and call polish because the sync createItem was called from addVisibleItems that
287+ // is called from refill that will already do those if an item was added
288+ if (modelIndex == m_asyncRequestedIndex) {
289+ createItem(modelIndex, false);
290+ m_implicitHeightDirty = true;
291+ polish();
292+ }
293+}
294+
295+void AbstractDashView::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
296+{
297+ if (reset) {
298+ cleanupExistingItems();
299+ } else {
300+ processModelRemoves(changeSet.removes());
301+
302+ // The current AbstractDashViews do not support insertions that are not at the end
303+ // so reset if that happens
304+ Q_FOREACH(const QQmlChangeSet::Change insert, changeSet.inserts()) {
305+ if (insert.index < m_delegateModel->count() - 1) {
306+ cleanupExistingItems();
307+ break;
308+ }
309+ }
310+ }
311+ polish();
312+}
313+
314+
315+void AbstractDashView::relayout()
316+{
317+ m_needsRelayout = true;
318+ polish();
319+}
320+
321+void AbstractDashView::onHeightChanged()
322+{
323+ polish();
324+}
325+
326+void AbstractDashView::updatePolish()
327+{
328+ if (!model())
329+ return;
330+
331+ if (m_needsRelayout) {
332+ doRelayout();
333+ m_needsRelayout = false;
334+ m_implicitHeightDirty = true;
335+ }
336+
337+ refill();
338+
339+ const qreal from = -m_displayMarginBeginning;
340+ const qreal to = height() + m_displayMarginEnd;
341+ updateItemCulling(from, to);
342+
343+ if (m_implicitHeightDirty) {
344+ calculateImplicitHeight();
345+ m_implicitHeightDirty = false;
346+ }
347+}
348+
349+void AbstractDashView::componentComplete()
350+{
351+ if (m_delegateModel)
352+ m_delegateModel->componentComplete();
353+
354+ QQuickItem::componentComplete();
355+
356+ m_needsRelayout = true;
357+
358+ polish();
359+}
plugins/Dash/abstractdashview.hnew file+128
@@ -0,0 +1,128 @@
1+/*
2+ * Copyright (C) 2013, 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef ABSTRACTDASHVIEW_H
18+#define ABSTRACTDASHVIEW_H
19+
20+#include <QQuickItem>
21+
22+class QAbstractItemModel;
23+class QQmlComponent;
24+
25+#include <private/qqmldelegatemodel_p.h>
26+#include <private/qquickitemchangelistener_p.h>
27+#include <qqmlinfo.h>
28+
29+class AbstractDashView : public QQuickItem, public QQuickItemChangeListener
30+{
31+ Q_OBJECT
32+
33+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
34+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
35+ Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
36+ Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
37+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
38+ Q_PROPERTY(qreal displayMarginBeginning READ displayMarginBeginning
39+ WRITE setDisplayMarginBeginning
40+ NOTIFY displayMarginBeginningChanged)
41+ Q_PROPERTY(qreal displayMarginEnd READ displayMarginEnd
42+ WRITE setDisplayMarginEnd
43+ NOTIFY displayMarginEndChanged)
44+
45+friend class VerticalJournalTest;
46+friend class HorizontalJournalTest;
47+friend class OrganicGridTest;
48+
49+public:
50+ AbstractDashView();
51+
52+ QAbstractItemModel *model() const;
53+ void setModel(QAbstractItemModel *model);
54+
55+ QQmlComponent *delegate() const;
56+ void setDelegate(QQmlComponent *delegate);
57+
58+ qreal columnSpacing() const;
59+ void setColumnSpacing(qreal columnSpacing);
60+
61+ qreal rowSpacing() const;
62+ void setRowSpacing(qreal rowSpacing);
63+
64+ int cacheBuffer() const;
65+ void setCacheBuffer(int);
66+
67+ qreal displayMarginBeginning() const;
68+ void setDisplayMarginBeginning(qreal);
69+
70+ qreal displayMarginEnd() const;
71+ void setDisplayMarginEnd(qreal);
72+
73+Q_SIGNALS:
74+ void modelChanged();
75+ void delegateChanged();
76+ void columnSpacingChanged();
77+ void rowSpacingChanged();
78+ void cacheBufferChanged();
79+ void displayMarginBeginningChanged();
80+ void displayMarginEndChanged();
81+
82+protected Q_SLOTS:
83+ void relayout();
84+
85+protected:
86+ void updatePolish() override;
87+ void componentComplete() override;
88+
89+ void releaseItem(QQuickItem *item);
90+ void setImplicitHeightDirty();
91+
92+private Q_SLOTS:
93+ void itemCreated(int modelIndex, QObject *object);
94+ void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
95+ void onHeightChanged();
96+
97+private:
98+ void createDelegateModel();
99+ void refill();
100+ bool addVisibleItems(qreal fillFromY, qreal fillToY, bool asynchronous);
101+ QQuickItem *createItem(int modelIndex, bool asynchronous);
102+
103+ virtual void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) = 0;
104+ virtual void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) = 0;
105+ virtual void addItemToView(int modelIndex, QQuickItem *item) = 0;
106+ virtual bool removeNonVisibleItems(qreal bufferFromY, qreal bufferToY) = 0;
107+ virtual void cleanupExistingItems() = 0;
108+ virtual void doRelayout() = 0;
109+ virtual void updateItemCulling(qreal visibleFromY, qreal visibleToY) = 0;
110+ virtual void calculateImplicitHeight() = 0;
111+ virtual void processModelRemoves(const QVector<QQmlChangeSet::Change> &removes) = 0;
112+
113+ QQmlDelegateModel *m_delegateModel;
114+
115+ // Index we are waiting because we requested it asynchronously
116+ int m_asyncRequestedIndex;
117+
118+ int m_columnSpacing;
119+ int m_rowSpacing;
120+ int m_buffer;
121+ qreal m_displayMarginBeginning;
122+ qreal m_displayMarginEnd;
123+ bool m_needsRelayout;
124+ bool m_delegateValidated;
125+ bool m_implicitHeightDirty;
126+};
127+
128+#endif
plugins/Dash/graphics/music_progress_bg.pngnew file

Binary file not shown.

plugins/Dash/horizontaljournal.cppnew file+239
@@ -0,0 +1,239 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+/*
18+ * The implementation is centered around m_visibleItems
19+ * that a list for each of the items in the view.
20+ * m_firstVisibleIndex is the index of the first item in m_visibleItems
21+ * m_lastInRowIndexPosition is a map that contains the x position
22+ * of items that are the last ones of a row so we can reconstruct the rows
23+ * when building back
24+ */
25+
26+#include "horizontaljournal.h"
27+
28+#include <qqmlengine.h>
29+#include <qqmlinfo.h>
30+#include <private/qqmldelegatemodel_p.h>
31+#include <private/qquickitem_p.h>
32+
33+HorizontalJournal::HorizontalJournal()
34+ : m_firstVisibleIndex(-1)
35+ , m_rowHeight(0)
36+{
37+}
38+
39+qreal HorizontalJournal::rowHeight() const
40+{
41+ return m_rowHeight;
42+}
43+
44+void HorizontalJournal::setRowHeight(qreal rowHeight)
45+{
46+ if (rowHeight != m_rowHeight) {
47+ m_rowHeight = rowHeight;
48+ Q_EMIT rowHeightChanged();
49+
50+ if (isComponentComplete()) {
51+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
52+ item->setHeight(rowHeight);
53+ }
54+ relayout();
55+ }
56+ }
57+}
58+
59+void HorizontalJournal::findBottomModelIndexToAdd(int *modelIndex, qreal *yPos)
60+{
61+ if (m_visibleItems.isEmpty()) {
62+ *modelIndex = 0;
63+ *yPos = 0;
64+ } else {
65+ *modelIndex = m_firstVisibleIndex + m_visibleItems.count();
66+ if (m_lastInRowIndexPosition.contains(*modelIndex - 1)) {
67+ *yPos = m_visibleItems.last()->y() + m_rowHeight + rowSpacing();
68+ } else {
69+ *yPos = m_visibleItems.last()->y();
70+ }
71+ }
72+}
73+
74+void HorizontalJournal::findTopModelIndexToAdd(int *modelIndex, qreal *yPos)
75+{
76+ if (m_visibleItems.isEmpty()) {
77+ *modelIndex = -1;
78+ *yPos = INT_MIN;
79+ } else {
80+ *modelIndex = m_firstVisibleIndex - 1;
81+ if (m_lastInRowIndexPosition.contains(*modelIndex)) {
82+ *yPos = m_visibleItems.first()->y() - rowSpacing() - m_rowHeight;
83+ } else {
84+ *yPos = m_visibleItems.first()->y();
85+ }
86+ }
87+}
88+
89+bool HorizontalJournal::removeNonVisibleItems(qreal bufferFromY, qreal bufferToY)
90+{
91+ bool changed = false;
92+
93+ while (!m_visibleItems.isEmpty() && m_visibleItems.first()->y() + m_rowHeight < bufferFromY) {
94+ releaseItem(m_visibleItems.takeFirst());
95+ changed = true;
96+ m_firstVisibleIndex++;
97+ }
98+
99+ while (!m_visibleItems.isEmpty() && m_visibleItems.last()->y() > bufferToY) {
100+ releaseItem(m_visibleItems.takeLast());
101+ changed = true;
102+ m_lastInRowIndexPosition.remove(m_firstVisibleIndex + m_visibleItems.count());
103+ }
104+
105+ if (m_visibleItems.isEmpty()) {
106+ m_firstVisibleIndex = -1;
107+ }
108+
109+ return changed;
110+}
111+
112+void HorizontalJournal::addItemToView(int modelIndex, QQuickItem *item)
113+{
114+ if (item->height() != m_rowHeight) {
115+ qWarning() << "Item" << modelIndex << "height is not the one that the rowHeight mandates, resetting it";
116+ item->setHeight(m_rowHeight);
117+ }
118+
119+ if (m_visibleItems.isEmpty()) {
120+ Q_ASSERT(modelIndex == 0);
121+ item->setY(0);
122+ item->setX(0);
123+ m_visibleItems << item;
124+ m_firstVisibleIndex = 0;
125+ } else {
126+ // modelIndex has to be either m_firstVisibleIndex - 1 or m_firstVisibleIndex + m_visibleItems.count()
127+ if (modelIndex == m_firstVisibleIndex + m_visibleItems.count()) {
128+ QQuickItem *lastItem = m_visibleItems.last();
129+ if (lastItem->x() + lastItem->width() + columnSpacing() + item->width() <= width()) {
130+ // Fits in the row
131+ item->setY(lastItem->y());
132+ item->setX(lastItem->x() + lastItem->width() + columnSpacing());
133+ } else {
134+ // Starts a new row
135+ item->setY(lastItem->y() + m_rowHeight + rowSpacing());
136+ item->setX(0);
137+ m_lastInRowIndexPosition[modelIndex - 1] = lastItem->x();
138+ }
139+ m_visibleItems << item;
140+ } else if (modelIndex == m_firstVisibleIndex - 1) {
141+ QQuickItem *firstItem = m_visibleItems.first();
142+ if (m_lastInRowIndexPosition.contains(modelIndex)) {
143+ // It is the last item of its row, so start a new one since we're going back
144+ item->setY(firstItem->y() - rowSpacing() - m_rowHeight);
145+ item->setX(m_lastInRowIndexPosition[modelIndex]);
146+ } else {
147+ item->setY(firstItem->y());
148+ item->setX(firstItem->x() - columnSpacing() - item->width());
149+ }
150+ m_firstVisibleIndex = modelIndex;
151+ m_visibleItems.prepend(item);
152+ } else {
153+ qWarning() << "HorizontalJournal::addItemToView - Got unexpected modelIndex"
154+ << modelIndex << m_firstVisibleIndex << m_visibleItems.count();
155+ }
156+ }
157+}
158+
159+void HorizontalJournal::cleanupExistingItems()
160+{
161+ // Cleanup the existing items
162+ Q_FOREACH(QQuickItem *item, m_visibleItems)
163+ releaseItem(item);
164+ m_visibleItems.clear();
165+ m_lastInRowIndexPosition.clear();
166+ m_firstVisibleIndex = -1;
167+ setImplicitHeightDirty();
168+}
169+
170+void HorizontalJournal::calculateImplicitHeight()
171+{
172+ if (m_firstVisibleIndex >= 0) {
173+ const int nIndexes = m_firstVisibleIndex + m_visibleItems.count();
174+ const double bottomMostY = m_visibleItems.last()->y() + m_rowHeight;
175+ const double averageHeight = bottomMostY / nIndexes;
176+ setImplicitHeight(bottomMostY + averageHeight * (model()->rowCount() - nIndexes));
177+ } else {
178+ setImplicitHeight(0);
179+ }
180+}
181+
182+void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Change> &removes)
183+{
184+ Q_FOREACH(const QQmlChangeSet::Change remove, removes) {
185+ for (int i = remove.count - 1; i >= 0; --i) {
186+ const int indexToRemove = remove.index + i;
187+ // We only support removing from the end so
188+ // any of the last items of a column has to be indexToRemove
189+ const int lastIndex = m_firstVisibleIndex + m_visibleItems.count() - 1;
190+ if (indexToRemove == lastIndex) {
191+ releaseItem(m_visibleItems.takeLast());
192+ m_lastInRowIndexPosition.remove(indexToRemove);
193+ } else {
194+ if (indexToRemove < lastIndex) {
195+ qDebug() << "HorizontalJournal only supports removal from the end of the model, resetting instead";
196+ cleanupExistingItems();
197+ break;
198+ } else {
199+ setImplicitHeightDirty();
200+ }
201+ }
202+ }
203+ }
204+ if (m_visibleItems.isEmpty()) {
205+ m_firstVisibleIndex = -1;
206+ }
207+}
208+
209+
210+void HorizontalJournal::doRelayout()
211+{
212+ // If m_firstVisibleIndex is not 0 we need to drop all the delegates
213+ // since we can't consistently relayout without the first item being there
214+
215+ if (m_firstVisibleIndex == 0) {
216+ int i = 0;
217+ const QList<QQuickItem*> allItems = m_visibleItems;
218+ m_visibleItems.clear();
219+ m_lastInRowIndexPosition.clear();
220+ Q_FOREACH(QQuickItem *item, allItems) {
221+ addItemToView(i, item);
222+ ++i;
223+ }
224+ } else {
225+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
226+ releaseItem(item);
227+ }
228+ m_visibleItems.clear();
229+ m_lastInRowIndexPosition.clear();
230+ m_firstVisibleIndex = -1;
231+ }
232+}
233+
234+void HorizontalJournal::updateItemCulling(qreal visibleFromY, qreal visibleToY)
235+{
236+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
237+ QQuickItemPrivate::get(item)->setCulled(item->y() + m_rowHeight <= visibleFromY || item->y() >= visibleToY);
238+ }
239+}
plugins/Dash/horizontaljournal.hnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef HORIZONTALJOURNAL_H
18+#define HORIZONTALJOURNAL_H
19+
20+#include "abstractdashview.h"
21+
22+ /** A horizontal journal is a view that creates delegates
23+ * based on a model and layouts them one after the other
24+ * in the same row until there is no more free space for the next item
25+ * and so that item is layouted in the next row
26+ *
27+ * All delegates are forced to rowHeight if they don't have it.
28+ */
29+ class HorizontalJournal : public AbstractDashView
30+{
31+ Q_OBJECT
32+
33+ Q_PROPERTY(qreal rowHeight READ rowHeight WRITE setRowHeight NOTIFY rowHeightChanged)
34+
35+friend class HorizontalJournalTest;
36+
37+public:
38+ HorizontalJournal();
39+
40+ qreal rowHeight() const;
41+ void setRowHeight(qreal rowHeight);
42+
43+Q_SIGNALS:
44+ void rowHeightChanged();
45+
46+private:
47+ void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) override;
48+ void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) override;
49+ bool removeNonVisibleItems(qreal bufferFromY, qreal bufferToY) override;
50+ void addItemToView(int modelIndex, QQuickItem *item) override;
51+ void cleanupExistingItems() override;
52+ void calculateImplicitHeight() override;
53+ void doRelayout() override;
54+ void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
55+ void processModelRemoves(const QVector<QQmlChangeSet::Change> &removes) override;
56+
57+ int m_firstVisibleIndex;
58+ QList<QQuickItem*> m_visibleItems;
59+ QMap<int, double> m_lastInRowIndexPosition;
60+ int m_rowHeight;
61+};
62+
63+#endif
plugins/Dash/listviewwithpageheader.cppnew file+1394
@@ -0,0 +1,1394 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+/*
18+ * Some documentation on how this thing works:
19+ *
20+ * A flickable has two very important concepts that define the top and
21+ * height of the flickable area.
22+ * The top is returned in minYExtent()
23+ * The height is set using setContentHeight()
24+ * By changing those two values we can make the list grow up or down
25+ * as needed. e.g. if we are in the middle of the list
26+ * and something that is above the viewport grows, since we do not
27+ * want to change the viewport because of that we just adjust the
28+ * minYExtent so that the list grows up.
29+ *
30+ * The implementation on the list relies on the delegateModel doing
31+ * most of the instantiation work. You call createItem() when you
32+ * need to create an item asking for it async or not. If returns null
33+ * it means the item will be created async and the model will call the
34+ * itemCreated slot with the item.
35+ *
36+ * updatePolish is the central point of dispatch for the work of the
37+ * class. It is called by the scene graph just before drawing the class.
38+ * In it we:
39+ * * Make sure all items are positioned correctly
40+ * * Add/Remove items if needed
41+ * * Update the content height if it was dirty
42+ *
43+ * m_visibleItems contains all the items we have created at the moment.
44+ * Actually not all of them are visible since it includes the ones
45+ * in the cache area we create asynchronously to help performance.
46+ * The first item in m_visibleItems has the m_firstVisibleIndex in
47+ * the model. If you actually want to know what is the first
48+ * item in the viewport you have to find the first non culled element
49+ * in m_visibleItems
50+ *
51+ * All the items (except the header) are childs of m_clipItem which
52+ * is a child of the contentItem() of the flickable (The contentItem()
53+ * is what actually 'moves' in a a flickable). This way
54+ * we can implement the clipping needed so we can have the header
55+ * shown in the middle of the list over the items without the items
56+ * leaking under the header in case it is transparent.
57+ *
58+ * The first item of m_visibleItems is the one that defines the
59+ * positions of all the rest of items (see updatePolish()) and
60+ * this is why sometimes we move it even if it's not the item
61+ * that has triggered the function (i.e. in itemGeometryChanged())
62+ *
63+ * m_visibleItems is a list of ListItem. Each ListItem
64+ * will contain a item and potentially a sectionItem. The sectionItem
65+ * is only there when the list is using sectionDelegate+sectionProperty
66+ * and this is the first item of the section. Each ListItem is vertically
67+ * layouted with the sectionItem first and then the item.
68+ *
69+ * For sectioning we also have a section item alone (m_topSectionItem)
70+ * that is used for the cases we need to show the sticky section item at
71+ * the top of the view.
72+ *
73+ * Each delegate item has a context property called heightToClip that is
74+ * used to communicate to the delegate implementation in case it has to
75+ * clip itself because of overlapping with the top sticky section item.
76+ * This is an implementation decision since it has been agreed it
77+ * is easier to implement the clipping in QML with this info than to
78+ * do it at the C++ level.
79+ *
80+ * Note that minYExtent and height are not always totally accurate, since
81+ * we don't have the items created we can't guess their heights
82+ * so we can only guarantee the values are correct when the first/last
83+ * items of the list are visible, otherwise we just live with good enough
84+ * values that make the list scrollable
85+ *
86+ * There are a few things that are not really implemented or tested properly
87+ * which we don't use at the moment like changing the model, changing
88+ * the section delegate, having a section delegate that changes its size, etc.
89+ * The known missing features are marked with TODOs along the code.
90+ */
91+
92+#include "listviewwithpageheader.h"
93+
94+#include <QCoreApplication>
95+#include <QDebug>
96+#include <qqmlinfo.h>
97+#include <qqmlengine.h>
98+#include <private/qqmlcontext_p.h>
99+#include <private/qqmldelegatemodel_p.h>
100+#include <private/qqmlglobal_p.h>
101+#include <private/qquickitem_p.h>
102+#include <private/qquickanimation_p.h>
103+// #include <private/qquickrectangle_p.h>
104+
105+qreal ListViewWithPageHeader::ListItem::height() const
106+{
107+ return m_item->height() + (m_sectionItem ? m_sectionItem->height() : 0);
108+}
109+
110+qreal ListViewWithPageHeader::ListItem::y() const
111+{
112+ return m_item->y() - (m_sectionItem ? m_sectionItem->height() : 0);
113+}
114+
115+void ListViewWithPageHeader::ListItem::setY(qreal newY)
116+{
117+ if (m_sectionItem) {
118+ m_sectionItem->setY(newY);
119+ m_item->setY(newY + m_sectionItem->height());
120+ } else {
121+ m_item->setY(newY);
122+ }
123+}
124+
125+bool ListViewWithPageHeader::ListItem::culled() const
126+{
127+ return QQuickItemPrivate::get(m_item)->culled;
128+}
129+
130+void ListViewWithPageHeader::ListItem::setCulled(bool culled)
131+{
132+ QQuickItemPrivate::get(m_item)->setCulled(culled);
133+ if (m_sectionItem)
134+ QQuickItemPrivate::get(m_sectionItem)->setCulled(culled);
135+}
136+
137+void ListViewWithPageHeader::ListItem::setSectionItem(QQuickItem *sectionItem)
138+{
139+ m_sectionItem = sectionItem;
140+}
141+
142+ListViewWithPageHeader::ListViewWithPageHeader()
143+ : m_delegateModel(nullptr)
144+ , m_asyncRequestedIndex(-1)
145+ , m_delegateValidated(false)
146+ , m_firstVisibleIndex(-1)
147+ , m_minYExtent(0)
148+ , m_contentHeightDirty(false)
149+ , m_headerItem(nullptr)
150+ , m_previousContentY(0)
151+ , m_headerItemShownHeight(0)
152+ , m_sectionDelegate(nullptr)
153+ , m_topSectionItem(nullptr)
154+ , m_forceNoClip(false)
155+ , m_inLayout(false)
156+ , m_inContentHeightKeepHeaderShown(false)
157+ , m_cacheBuffer(0)
158+{
159+ m_clipItem = new QQuickItem(contentItem());
160+// m_clipItem = new QQuickRectangle(contentItem());
161+// ((QQuickRectangle*)m_clipItem)->setColor(Qt::gray);
162+
163+ m_contentYAnimation = new QQuickNumberAnimation(this);
164+ m_contentYAnimation->setEasing(QEasingCurve::OutQuad);
165+ m_contentYAnimation->setProperty(QStringLiteral("contentY"));
166+ m_contentYAnimation->setDuration(200);
167+ m_contentYAnimation->setTargetObject(this);
168+
169+ connect(contentItem(), &QQuickItem::widthChanged, this, &ListViewWithPageHeader::onContentWidthChanged);
170+ connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged);
171+ connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged);
172+ connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged);
173+
174+ setFlickableDirection(VerticalFlick);
175+}
176+
177+ListViewWithPageHeader::~ListViewWithPageHeader()
178+{
179+}
180+
181+QAbstractItemModel *ListViewWithPageHeader::model() const
182+{
183+ return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
184+}
185+
186+void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
187+{
188+ if (model != this->model()) {
189+ if (!m_delegateModel) {
190+ createDelegateModel();
191+ } else {
192+ disconnect(m_delegateModel, &QQmlDelegateModel::modelUpdated, this, &ListViewWithPageHeader::onModelUpdated);
193+ }
194+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
195+ connect(m_delegateModel, &QQmlDelegateModel::modelUpdated, this, &ListViewWithPageHeader::onModelUpdated);
196+ Q_EMIT modelChanged();
197+ polish();
198+ // TODO?
199+// Q_EMIT contentHeightChanged();
200+// Q_EMIT contentYChanged();
201+ }
202+}
203+
204+QQmlComponent *ListViewWithPageHeader::delegate() const
205+{
206+ return m_delegateModel ? m_delegateModel->delegate() : nullptr;
207+}
208+
209+void ListViewWithPageHeader::setDelegate(QQmlComponent *delegate)
210+{
211+ if (delegate != this->delegate()) {
212+ if (!m_delegateModel) {
213+ createDelegateModel();
214+ }
215+
216+ // Cleanup the existing items
217+ Q_FOREACH(ListItem *item, m_visibleItems)
218+ releaseItem(item);
219+ m_visibleItems.clear();
220+ initializeValuesForEmptyList();
221+
222+ m_delegateModel->setDelegate(delegate);
223+
224+ Q_EMIT delegateChanged();
225+ m_delegateValidated = false;
226+ m_contentHeightDirty = true;
227+ polish();
228+ }
229+}
230+
231+void ListViewWithPageHeader::initializeValuesForEmptyList()
232+{
233+ m_firstVisibleIndex = -1;
234+ adjustMinYExtent();
235+ setContentY(0);
236+ m_clipItem->setY(0);
237+ if (m_topSectionItem) {
238+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
239+ }
240+}
241+
242+QQuickItem *ListViewWithPageHeader::header() const
243+{
244+ return m_headerItem;
245+}
246+
247+void ListViewWithPageHeader::setHeader(QQuickItem *headerItem)
248+{
249+ if (m_headerItem != headerItem) {
250+ qreal oldHeaderHeight = 0;
251+ qreal oldHeaderY = 0;
252+ if (m_headerItem) {
253+ oldHeaderHeight = m_headerItem->height();
254+ oldHeaderY = m_headerItem->y();
255+ m_headerItem->setParentItem(nullptr);
256+ QQuickItemPrivate::get(m_headerItem)->removeItemChangeListener(this, QQuickItemPrivate::ImplicitHeight);
257+ }
258+ m_headerItem = headerItem;
259+ if (m_headerItem) {
260+ m_headerItem->setParentItem(contentItem());
261+ m_headerItem->setZ(1);
262+ m_previousHeaderImplicitHeight = m_headerItem->implicitHeight();
263+ QQuickItemPrivate::get(m_headerItem)->addItemChangeListener(this, QQuickItemPrivate::ImplicitHeight);
264+ }
265+ qreal newHeaderHeight = m_headerItem ? m_headerItem->height() : 0;
266+ if (!m_visibleItems.isEmpty() && newHeaderHeight != oldHeaderHeight) {
267+ headerHeightChanged(newHeaderHeight, oldHeaderHeight, oldHeaderY);
268+ polish();
269+ m_contentHeightDirty = true;
270+ }
271+ Q_EMIT headerChanged();
272+ }
273+}
274+
275+QQmlComponent *ListViewWithPageHeader::sectionDelegate() const
276+{
277+ return m_sectionDelegate;
278+}
279+
280+void ListViewWithPageHeader::setSectionDelegate(QQmlComponent *delegate)
281+{
282+ if (delegate != m_sectionDelegate) {
283+ // TODO clean existing sections
284+
285+ m_sectionDelegate = delegate;
286+
287+ m_topSectionItem = getSectionItem(QString(), false /*watchGeometry*/);
288+ if (m_topSectionItem) {
289+ m_topSectionItem->setZ(3);
290+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
291+ connect(m_topSectionItem, &QQuickItem::heightChanged, this, &ListViewWithPageHeader::stickyHeaderHeightChanged);
292+ }
293+
294+ // TODO create sections for existing items
295+
296+ Q_EMIT sectionDelegateChanged();
297+ Q_EMIT stickyHeaderHeightChanged();
298+ }
299+}
300+
301+QString ListViewWithPageHeader::sectionProperty() const
302+{
303+ return m_sectionProperty;
304+}
305+
306+void ListViewWithPageHeader::setSectionProperty(const QString &property)
307+{
308+ if (property != m_sectionProperty) {
309+ m_sectionProperty = property;
310+
311+ updateWatchedRoles();
312+
313+ // TODO recreate sections
314+
315+ Q_EMIT sectionPropertyChanged();
316+ }
317+}
318+
319+bool ListViewWithPageHeader::forceNoClip() const
320+{
321+ return m_forceNoClip;
322+}
323+
324+void ListViewWithPageHeader::setForceNoClip(bool noClip)
325+{
326+ if (noClip != m_forceNoClip) {
327+ m_forceNoClip = noClip;
328+ updateClipItem();
329+ Q_EMIT forceNoClipChanged();
330+ }
331+}
332+
333+int ListViewWithPageHeader::stickyHeaderHeight() const
334+{
335+ return m_topSectionItem ? m_topSectionItem->height() : 0;
336+}
337+
338+qreal ListViewWithPageHeader::headerItemShownHeight() const
339+{
340+ return m_headerItemShownHeight;
341+}
342+
343+int ListViewWithPageHeader::cacheBuffer() const
344+{
345+ return m_cacheBuffer;
346+}
347+
348+void ListViewWithPageHeader::setCacheBuffer(int cacheBuffer)
349+{
350+ if (cacheBuffer < 0) {
351+ qmlInfo(this) << "Cannot set a negative cache buffer";
352+ return;
353+ }
354+
355+ if (cacheBuffer != m_cacheBuffer) {
356+ m_cacheBuffer = cacheBuffer;
357+ Q_EMIT cacheBufferChanged();
358+ polish();
359+ }
360+}
361+
362+void ListViewWithPageHeader::positionAtBeginning()
363+{
364+ if (m_delegateModel->count() <= 0)
365+ return;
366+
367+ qreal headerHeight = (m_headerItem ? m_headerItem->height() : 0);
368+ if (m_firstVisibleIndex != 0) {
369+ // TODO This could be optimized by trying to reuse the interesection
370+ // of items that may end up intersecting between the existing
371+ // m_visibleItems and the items we are creating in the next loop
372+ Q_FOREACH(ListItem *item, m_visibleItems)
373+ releaseItem(item);
374+ m_visibleItems.clear();
375+ m_firstVisibleIndex = -1;
376+
377+ // Create the item 0, it will be already correctly positioned at createItem()
378+ m_clipItem->setY(0);
379+ ListItem *item = createItem(0, false);
380+ // Create the subsequent items
381+ int modelIndex = 1;
382+ qreal pos = item->y() + item->height();
383+ const qreal bufferTo = height() + m_cacheBuffer;
384+ while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
385+ if (!(item = createItem(modelIndex, false)))
386+ break;
387+ pos += item->height();
388+ ++modelIndex;
389+ }
390+
391+ m_previousContentY = m_visibleItems.first()->y() - headerHeight;
392+ }
393+ setContentY(m_visibleItems.first()->y() + m_clipItem->y() - headerHeight);
394+ if (m_headerItem) {
395+ // TODO This should not be needed and the code that adjust the m_headerItem position
396+ // in viewportMoved() should be enough but in some cases we have not found a way to reproduce
397+ // yet the code of viewportMoved() fails so here we make sure that at least if we are calling
398+ // positionAtBeginning the header item will be correctly positioned
399+ m_headerItem->setY(-m_minYExtent);
400+ }
401+}
402+
403+static inline bool uFuzzyCompare(qreal r1, qreal r2)
404+{
405+ return qFuzzyCompare(r1, r2) || (qFuzzyIsNull(r1) && qFuzzyIsNull(r2));
406+}
407+
408+void ListViewWithPageHeader::showHeader()
409+{
410+ if (!m_headerItem)
411+ return;
412+
413+ const auto to = qMax(-minYExtent(), contentY() - m_headerItem->height() + m_headerItemShownHeight);
414+ if (!uFuzzyCompare(to, contentY())) {
415+ const bool headerShownByItsOwn = contentY() < m_headerItem->y() + m_headerItem->height();
416+ if (headerShownByItsOwn && m_headerItemShownHeight == 0) {
417+ // We are not clipping since we are just at the top of the viewport
418+ // but because of the showHeader animation we will need to, so
419+ // enable the clipping without logically moving the items
420+ m_headerItemShownHeight = m_headerItem->y() + m_headerItem->height() - contentY();
421+ if (!m_visibleItems.isEmpty()) {
422+ updateClipItem();
423+ ListItem *firstItem = m_visibleItems.first();
424+ firstItem->setY(firstItem->y() - m_headerItemShownHeight);
425+ layout();
426+ }
427+ Q_EMIT headerItemShownHeightChanged();
428+ }
429+ m_contentYAnimation->setTo(to);
430+ contentYAnimationType = ContentYAnimationShowHeader;
431+ m_contentYAnimation->start();
432+ }
433+}
434+
435+int ListViewWithPageHeader::firstCreatedIndex() const
436+{
437+ return m_firstVisibleIndex;
438+}
439+
440+int ListViewWithPageHeader::createdItemCount() const
441+{
442+ return m_visibleItems.count();
443+}
444+
445+QQuickItem *ListViewWithPageHeader::item(int modelIndex) const
446+{
447+ ListItem *item = itemAtIndex(modelIndex);
448+ if (item)
449+ return item->m_item;
450+ else
451+ return nullptr;
452+}
453+
454+bool ListViewWithPageHeader::maximizeVisibleArea(int modelIndex)
455+{
456+ ListItem *listItem = itemAtIndex(modelIndex);
457+ if (listItem) {
458+ return maximizeVisibleArea(listItem, listItem->height());
459+ }
460+
461+ return false;
462+}
463+
464+bool ListViewWithPageHeader::maximizeVisibleArea(int modelIndex, int itemHeight)
465+{
466+ if (itemHeight < 0)
467+ return false;
468+
469+ ListItem *listItem = itemAtIndex(modelIndex);
470+ if (listItem) {
471+ return maximizeVisibleArea(listItem, itemHeight + (listItem->sectionItem() ? listItem->sectionItem()->height() : 0));
472+ }
473+
474+ return false;
475+}
476+
477+bool ListViewWithPageHeader::maximizeVisibleArea(ListItem *listItem, int listItemHeight)
478+{
479+ if (listItem) {
480+ layout();
481+ const auto listItemY = m_clipItem->y() + listItem->y();
482+ if (listItemY > contentY() && listItemY + listItemHeight > contentY() + height()) {
483+ // we can scroll the list up to show more stuff
484+ const auto to = qMin(listItemY, listItemY + listItemHeight - height());
485+ m_contentYAnimation->setTo(to);
486+ contentYAnimationType = ContentYAnimationMaximizeVisibleArea;
487+ m_contentYAnimation->start();
488+ } else if ((listItemY < contentY() && listItemY + listItemHeight < contentY() + height()) ||
489+ (m_topSectionItem && !listItem->sectionItem() && listItemY - m_topSectionItem->height() < contentY() && listItemY + listItemHeight < contentY() + height()))
490+ {
491+ // we can scroll the list down to show more stuff
492+ auto realVisibleListItemY = listItemY;
493+ if (m_topSectionItem) {
494+ // If we are showing the top section sticky item and this item doesn't have a section
495+ // item we have to make sure to scroll it a bit more so that it is not underlapping
496+ // the top section sticky item
497+ bool topSectionShown = !QQuickItemPrivate::get(m_topSectionItem)->culled;
498+ if (topSectionShown && !listItem->sectionItem()) {
499+ realVisibleListItemY -= m_topSectionItem->height();
500+ }
501+ }
502+ const auto to = qMax(realVisibleListItemY, listItemY + listItemHeight - height());
503+ m_contentYAnimation->setTo(to);
504+ contentYAnimationType = ContentYAnimationMaximizeVisibleArea;
505+ m_contentYAnimation->start();
506+ }
507+ return true;
508+ }
509+ return false;
510+}
511+
512+qreal ListViewWithPageHeader::minYExtent() const
513+{
514+// qDebug() << "ListViewWithPageHeader::minYExtent" << m_minYExtent;
515+ return m_minYExtent;
516+}
517+
518+qreal ListViewWithPageHeader::maxYExtent() const
519+{
520+ return height() - contentHeight();
521+}
522+
523+void ListViewWithPageHeader::componentComplete()
524+{
525+ if (m_delegateModel)
526+ m_delegateModel->componentComplete();
527+
528+ QQuickFlickable::componentComplete();
529+
530+ polish();
531+}
532+
533+void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
534+{
535+ // Check we are not being taken down and don't paint anything
536+ // TODO Check if we still need this in 5.2
537+ // For reproduction just inifnite loop testDash or testDashContent
538+ if (!QQmlEngine::contextForObject(this)->parentContext())
539+ return;
540+
541+ QQuickFlickable::viewportMoved(orient);
542+// qDebug() << "ListViewWithPageHeader::viewportMoved" << contentY();
543+ const qreal diff = m_previousContentY - contentY();
544+ adjustHeader(diff);
545+ m_previousContentY = contentY();
546+ layout();
547+ polish();
548+}
549+
550+void ListViewWithPageHeader::adjustHeader(qreal diff)
551+{
552+ const bool showHeaderAnimationRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationShowHeader;
553+ if (m_headerItem) {
554+ const auto oldHeaderItemShownHeight = m_headerItemShownHeight;
555+ if (uFuzzyCompare(contentY(), -m_minYExtent) || contentY() > -m_minYExtent) {
556+ m_headerItem->setHeight(m_headerItem->implicitHeight());
557+ // We are going down (but it's not because of the rebound at the end)
558+ // (but the header was not shown by it's own position)
559+ // or the header is partially shown and we are not doing a maximizeVisibleArea either
560+ const bool scrolledUp = m_previousContentY > contentY();
561+ const bool notRebounding = qRound(contentY() + height()) < qRound(contentHeight());
562+ const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();
563+ const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
564+
565+ if (!scrolledUp && (contentY() == -m_minYExtent || (m_headerItemShownHeight == 0 && m_previousContentY == m_headerItem->y()))) {
566+ m_headerItemShownHeight = 0;
567+ m_headerItem->setY(-m_minYExtent);
568+ } else if ((scrolledUp && notRebounding && notShownByItsOwn && !maximizeVisibleAreaRunning) || (m_headerItemShownHeight > 0) || m_inContentHeightKeepHeaderShown) {
569+ if (maximizeVisibleAreaRunning && diff > 0) {
570+ // If we are maximizing and the header was shown, make sure we hide it
571+ m_headerItemShownHeight -= diff;
572+ } else {
573+ m_headerItemShownHeight += diff;
574+ }
575+ if (uFuzzyCompare(contentY(), -m_minYExtent)) {
576+ m_headerItemShownHeight = 0;
577+ } else {
578+ m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, m_headerItem->height());
579+ }
580+ if (m_headerItemShownHeight > 0) {
581+ if (uFuzzyCompare(m_headerItem->height(), m_headerItemShownHeight)) {
582+ m_headerItem->setY(contentY());
583+ m_headerItemShownHeight = m_headerItem->height();
584+ } else {
585+ m_headerItem->setY(contentY() - m_headerItem->height() + m_headerItemShownHeight);
586+ }
587+ } else {
588+ m_headerItem->setY(-m_minYExtent);
589+ }
590+ } else if (m_headerItemShownHeight == 0 && m_previousContentY > m_headerItem->y() && contentY() < m_headerItem->y()) {
591+ // The header was hidden but now that we've moved up (e.g. because of item removed) it's visible
592+ // make sure it isn't
593+ m_headerItem->setY(-m_minYExtent);
594+ }
595+ Q_EMIT headerItemShownHeightChanged();
596+ } else {
597+ // Stick the header item to the top when dragging down
598+ m_headerItem->setY(contentY());
599+ m_headerItem->setHeight(m_headerItem->implicitHeight() + (-m_minYExtent - contentY()));
600+ }
601+ // We will be changing the clip item, need to accomadate for it
602+ // otherwise we move the firstItem down/up twice (unless the
603+ // show header animation is running, where we want to keep the viewport stable)
604+ if (!showHeaderAnimationRunning) {
605+ diff += oldHeaderItemShownHeight - m_headerItemShownHeight;
606+ } else {
607+ diff = -diff;
608+ }
609+ }
610+ if (!m_visibleItems.isEmpty()) {
611+ updateClipItem();
612+ ListItem *firstItem = m_visibleItems.first();
613+ firstItem->setY(firstItem->y() + diff);
614+ if (showHeaderAnimationRunning) {
615+ adjustMinYExtent();
616+ }
617+ }
618+}
619+
620+void ListViewWithPageHeader::createDelegateModel()
621+{
622+ m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
623+ connect(m_delegateModel, &QQmlDelegateModel::createdItem, this, &ListViewWithPageHeader::itemCreated);
624+ if (isComponentComplete())
625+ m_delegateModel->componentComplete();
626+ updateWatchedRoles();
627+}
628+
629+void ListViewWithPageHeader::refill()
630+{
631+ if (m_inLayout) {
632+ return;
633+ }
634+ if (!isComponentComplete()) {
635+ return;
636+ }
637+
638+ const qreal from = contentY();
639+ const qreal to = from + height();
640+ const qreal bufferFrom = from - m_cacheBuffer;
641+ const qreal bufferTo = to + m_cacheBuffer;
642+
643+ bool added = addVisibleItems(from, to, false);
644+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
645+ added |= addVisibleItems(bufferFrom, bufferTo, true);
646+
647+ if (added || removed) {
648+ m_contentHeightDirty = true;
649+ }
650+}
651+
652+bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
653+{
654+ if (!delegate())
655+ return false;
656+
657+ if (m_delegateModel->count() == 0)
658+ return false;
659+
660+ ListItem *item;
661+// qDebug() << "ListViewWithPageHeader::addVisibleItems" << fillFrom << fillTo << asynchronous;
662+
663+ int modelIndex = 0;
664+ qreal pos = 0;
665+ if (!m_visibleItems.isEmpty()) {
666+ modelIndex = m_firstVisibleIndex + m_visibleItems.count();
667+ item = m_visibleItems.last();
668+ pos = item->y() + item->height() + m_clipItem->y();
669+ }
670+ bool changed = false;
671+// qDebug() << (modelIndex < m_delegateModel->count()) << pos << fillTo;
672+ while (modelIndex < m_delegateModel->count() && pos <= fillTo) {
673+// qDebug() << "refill: append item" << modelIndex << "pos" << pos << "asynchronous" << asynchronous;
674+ if (!(item = createItem(modelIndex, asynchronous)))
675+ break;
676+ pos += item->height();
677+ ++modelIndex;
678+ changed = true;
679+ }
680+
681+ modelIndex = 0;
682+ pos = 0;
683+ if (!m_visibleItems.isEmpty()) {
684+ modelIndex = m_firstVisibleIndex - 1;
685+ item = m_visibleItems.first();
686+ pos = item->y() + m_clipItem->y();
687+ }
688+ while (modelIndex >= 0 && pos > fillFrom) {
689+// qDebug() << "refill: prepend item" << modelIndex << "pos" << pos << "fillFrom" << fillFrom << "asynchronous" << asynchronous;
690+ if (!(item = createItem(modelIndex, asynchronous)))
691+ break;
692+ pos -= item->height();
693+ --modelIndex;
694+ changed = true;
695+ }
696+
697+ return changed;
698+}
699+
700+void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
701+{
702+ QQuickItem *item = listItem->m_item;
703+ QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
704+ if (flags & QQmlDelegateModel::Destroyed) {
705+ item->setParentItem(nullptr);
706+ }
707+ if (listItem->sectionItem()) {
708+ listItem->sectionItem()->deleteLater();
709+ }
710+ delete listItem;
711+}
712+
713+void ListViewWithPageHeader::releaseItem(ListItem *listItem)
714+{
715+ QQuickItemPrivate::get(listItem->m_item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
716+ if (listItem->sectionItem()) {
717+ QQuickItemPrivate::get(listItem->sectionItem())->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
718+ }
719+ m_itemsToRelease << listItem;
720+}
721+
722+void ListViewWithPageHeader::updateWatchedRoles()
723+{
724+ if (m_delegateModel) {
725+ QList<QByteArray> roles;
726+ if (!m_sectionProperty.isEmpty())
727+ roles << m_sectionProperty.toUtf8();
728+ m_delegateModel->setWatchedRoles(roles);
729+ }
730+}
731+
732+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyInserted)
733+{
734+ if (!m_sectionDelegate)
735+ return nullptr;
736+
737+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
738+
739+ if (modelIndex > 0) {
740+ const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
741+ if (section == prevSection)
742+ return nullptr;
743+ }
744+ if (modelIndex + 1 < model()->rowCount() && !alreadyInserted) {
745+ // Already inserted items can't steal next section header
746+ const QString nextSection = m_delegateModel->stringValue(modelIndex + 1, m_sectionProperty);
747+ if (section == nextSection) {
748+ // Steal the section header
749+ ListItem *nextItem = itemAtIndex(modelIndex); // Not +1 since not yet inserted into m_visibleItems
750+ if (nextItem) {
751+ QQuickItem *sectionItem = nextItem->sectionItem();
752+ nextItem->setSectionItem(nullptr);
753+ return sectionItem;
754+ }
755+ }
756+ }
757+
758+ return getSectionItem(section);
759+}
760+
761+QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText, bool watchGeometry)
762+{
763+ QQuickItem *sectionItem = nullptr;
764+
765+ QQmlContext *creationContext = m_sectionDelegate->creationContext();
766+ QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
767+ QObject *nobj = m_sectionDelegate->beginCreate(context);
768+ if (nobj) {
769+ QQml_setParent_noEvent(context, nobj);
770+ sectionItem = qobject_cast<QQuickItem *>(nobj);
771+ if (!sectionItem) {
772+ delete nobj;
773+ } else {
774+ sectionItem->setProperty("text", sectionText);
775+ sectionItem->setProperty("delegate", QVariant());
776+ sectionItem->setZ(2);
777+ QQml_setParent_noEvent(sectionItem, m_clipItem);
778+ sectionItem->setParentItem(m_clipItem);
779+ }
780+ } else {
781+ delete context;
782+ }
783+ m_sectionDelegate->completeCreate();
784+
785+ if (watchGeometry && sectionItem) {
786+ QQuickItemPrivate::get(sectionItem)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
787+ }
788+
789+ return sectionItem;
790+}
791+
792+void ListViewWithPageHeader::updateSectionItem(int modelIndex)
793+{
794+ ListItem *item = itemAtIndex(modelIndex);
795+ if (item) {
796+ const QString sectionText = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
797+
798+ bool needSectionHeader = true;
799+ // if it is the same section as the previous item need to drop the section
800+ if (modelIndex > 0) {
801+ const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
802+ if (sectionText == prevSection) {
803+ needSectionHeader = false;
804+ }
805+ }
806+
807+ if (needSectionHeader) {
808+ if (!item->sectionItem()) {
809+ item->setSectionItem(getSectionItem(sectionText));
810+ } else {
811+ item->sectionItem()->setProperty("text", sectionText);
812+ }
813+ } else {
814+ if (item->sectionItem()) {
815+ item->sectionItem()->deleteLater();
816+ item->setSectionItem(nullptr);
817+ }
818+ }
819+ }
820+}
821+
822+bool ListViewWithPageHeader::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
823+{
824+// qDebug() << "ListViewWithPageHeader::removeNonVisibleItems" << bufferFrom << bufferTo;
825+ // Do not remove items if we are overshooting up or down, since we'll come back
826+ // to the "stable" position and delete/create items without any reason
827+ if (contentY() < -m_minYExtent) {
828+ return false;
829+ } else if (contentY() + height() > contentHeight()) {
830+ return false;
831+ }
832+ bool changed = false;
833+
834+ bool foundVisible = false;
835+ int i = 0;
836+ int removedItems = 0;
837+ const auto oldFirstVisibleIndex = m_firstVisibleIndex;
838+ while (i < m_visibleItems.count()) {
839+ ListItem *item = m_visibleItems[i];
840+ const qreal pos = item->y() + m_clipItem->y();
841+// qDebug() << i << pos << (pos + item->height()) << bufferFrom << bufferTo;
842+ if (pos + item->height() < bufferFrom || pos > bufferTo) {
843+// qDebug() << "Releasing" << i << (pos + item->height() < bufferFrom) << pos + item->height() << bufferFrom << (pos > bufferTo) << pos << bufferTo;
844+ releaseItem(item);
845+ m_visibleItems.removeAt(i);
846+ changed = true;
847+ ++removedItems;
848+ } else {
849+ if (!foundVisible) {
850+ foundVisible = true;
851+ const int itemIndex = m_firstVisibleIndex + removedItems + i;
852+ m_firstVisibleIndex = itemIndex;
853+ }
854+ ++i;
855+ }
856+ }
857+ if (!foundVisible) {
858+ initializeValuesForEmptyList();
859+ }
860+ if (m_firstVisibleIndex != oldFirstVisibleIndex) {
861+ adjustMinYExtent();
862+ }
863+
864+ return changed;
865+}
866+
867+ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIndex, bool asynchronous)
868+{
869+// qDebug() << "CREATE ITEM" << modelIndex;
870+ if (asynchronous && m_asyncRequestedIndex != -1)
871+ return nullptr;
872+
873+ m_asyncRequestedIndex = -1;
874+ QObject* object = m_delegateModel->object(modelIndex, asynchronous);
875+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
876+ if (!item) {
877+ if (object) {
878+ m_delegateModel->release(object);
879+ if (!m_delegateValidated) {
880+ m_delegateValidated = true;
881+ QObject* delegateObj = delegate();
882+ qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
883+ }
884+ } else {
885+ m_asyncRequestedIndex = modelIndex;
886+ }
887+ return 0;
888+ } else {
889+// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
890+ ListItem *listItem = new ListItem;
891+ listItem->m_item = item;
892+ listItem->setSectionItem(getSectionItem(modelIndex, false /*Not yet inserted into m_visibleItems*/));
893+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
894+ ListItem *prevItem = itemAtIndex(modelIndex - 1);
895+ bool lostItem = false; // Is an item that we requested async but because of model changes
896+ // it is no longer attached to any of the existing items (has no prev nor next item)
897+ // nor is the first item
898+ if (prevItem) {
899+ listItem->setY(prevItem->y() + prevItem->height());
900+ } else {
901+ ListItem *currItem = itemAtIndex(modelIndex);
902+ if (currItem) {
903+ // There's something already in m_visibleItems at out index, meaning this is an insert, so attach to its top
904+ listItem->setY(currItem->y() - listItem->height());
905+ } else {
906+ ListItem *nextItem = itemAtIndex(modelIndex + 1);
907+ if (nextItem) {
908+ listItem->setY(nextItem->y() - listItem->height());
909+ } else if (modelIndex == 0) {
910+ listItem->setY(-m_clipItem->y() + (m_headerItem ? m_headerItem->height() : 0));
911+ } else if (!m_visibleItems.isEmpty()) {
912+ lostItem = true;
913+ }
914+ }
915+ }
916+ if (lostItem) {
917+ listItem->setCulled(true);
918+ releaseItem(listItem);
919+ listItem = nullptr;
920+ } else {
921+ listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() <= contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
922+ if (m_visibleItems.isEmpty()) {
923+ m_visibleItems << listItem;
924+ } else {
925+ m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
926+ }
927+ if (m_firstVisibleIndex < 0 || modelIndex < m_firstVisibleIndex) {
928+ m_firstVisibleIndex = modelIndex;
929+ polish();
930+ }
931+ if (listItem->sectionItem()) {
932+ listItem->sectionItem()->setProperty("delegate", QVariant::fromValue(listItem->m_item));
933+ }
934+ adjustMinYExtent();
935+ m_contentHeightDirty = true;
936+ }
937+ return listItem;
938+ }
939+}
940+
941+void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
942+{
943+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
944+ if (!item) {
945+ qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
946+ return;
947+ }
948+// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
949+ // Check we are not being taken down and don't paint anything
950+ // TODO Check if we still need this in 5.2
951+ // For reproduction just inifnite loop testDash or testDashContent
952+ if (!QQmlEngine::contextForObject(this)->parentContext())
953+ return;
954+
955+ item->setParentItem(m_clipItem);
956+ // FIXME Why do we need the refreshExpressions call?
957+ QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
958+ QQmlContextPrivate::get(context)->data->refreshExpressions();
959+ item->setProperty("heightToClip", QVariant::fromValue<int>(0));
960+ if (modelIndex == m_asyncRequestedIndex) {
961+ createItem(modelIndex, false);
962+ refill();
963+ }
964+}
965+
966+void ListViewWithPageHeader::updateClipItem()
967+{
968+ m_clipItem->setHeight(height() - m_headerItemShownHeight);
969+ m_clipItem->setY(contentY() + m_headerItemShownHeight);
970+ m_clipItem->setClip(!m_forceNoClip && m_headerItemShownHeight > 0);
971+}
972+
973+void ListViewWithPageHeader::onContentHeightChanged()
974+{
975+ updateClipItem();
976+}
977+
978+void ListViewWithPageHeader::onContentWidthChanged()
979+{
980+ m_clipItem->setWidth(contentItem()->width());
981+}
982+
983+void ListViewWithPageHeader::onHeightChanged()
984+{
985+ m_clipItem->setHeight(height() - m_headerItemShownHeight);
986+ polish();
987+}
988+
989+
990+void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
991+{
992+ // TODO Do something with reset
993+// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
994+ const auto oldFirstVisibleIndex = m_firstVisibleIndex;
995+
996+ Q_FOREACH(const QQmlChangeSet::Change remove, changeSet.removes()) {
997+// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
998+ if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
999+ const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
1000+ // If all the items we are removing are either not created or culled
1001+ // we have to grow down to avoid viewport changing
1002+ bool growDown = true;
1003+ for (int i = 0; growDown && i < remove.count; ++i) {
1004+ const int modelIndex = remove.index + i;
1005+ ListItem *item = itemAtIndex(modelIndex);
1006+ if (item && !item->culled()) {
1007+ growDown = false;
1008+ }
1009+ }
1010+ for (int i = remove.count - 1; i >= 0; --i) {
1011+ const int visibleIndex = remove.index + i - m_firstVisibleIndex;
1012+ if (visibleIndex >= 0 && visibleIndex < m_visibleItems.count()) {
1013+ ListItem *item = m_visibleItems[visibleIndex];
1014+ // Pass the section item down if needed
1015+ if (item->sectionItem() && visibleIndex + 1 < m_visibleItems.count()) {
1016+ ListItem *nextItem = m_visibleItems[visibleIndex + 1];
1017+ if (!nextItem->sectionItem()) {
1018+ nextItem->setSectionItem(item->sectionItem());
1019+ item->setSectionItem(nullptr);
1020+ }
1021+ }
1022+ releaseItem(item);
1023+ m_visibleItems.removeAt(visibleIndex);
1024+ }
1025+ }
1026+ if (growDown) {
1027+ adjustMinYExtent();
1028+ } else if (remove.index <= m_firstVisibleIndex && !m_visibleItems.isEmpty()) {
1029+ m_visibleItems.first()->setY(oldFirstValidIndexPos);
1030+ }
1031+ if (m_visibleItems.isEmpty()) {
1032+ m_firstVisibleIndex = -1;
1033+ } else {
1034+ m_firstVisibleIndex -= qMax(0, m_firstVisibleIndex - remove.index);
1035+ }
1036+ } else if (remove.index + remove.count <= m_firstVisibleIndex) {
1037+ m_firstVisibleIndex -= remove.count;
1038+ }
1039+ for (int i = remove.count - 1; i >= 0; --i) {
1040+ const int modelIndex = remove.index + i;
1041+ if (modelIndex == m_asyncRequestedIndex) {
1042+ m_asyncRequestedIndex = -1;
1043+ } else if (modelIndex < m_asyncRequestedIndex) {
1044+ m_asyncRequestedIndex--;
1045+ }
1046+ }
1047+ }
1048+
1049+ Q_FOREACH(const QQmlChangeSet::Change insert, changeSet.inserts()) {
1050+// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
1051+ const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
1052+ const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
1053+ if (insertingInValidIndexes || firstItemWithViewOnTop)
1054+ {
1055+ // If the items we are adding won't be really visible
1056+ // we grow up instead of down to not change the viewport
1057+ bool growUp = false;
1058+ if (!firstItemWithViewOnTop) {
1059+ for (int i = 0; i < m_visibleItems.count(); ++i) {
1060+ if (!m_visibleItems[i]->culled()) {
1061+ if (insert.index <= m_firstVisibleIndex + i) {
1062+ growUp = true;
1063+ }
1064+ break;
1065+ }
1066+ }
1067+ }
1068+
1069+ const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
1070+ for (int i = insert.count - 1; i >= 0; --i) {
1071+ const int modelIndex = insert.index + i;
1072+ ListItem *item = createItem(modelIndex, false);
1073+ if (growUp) {
1074+ ListItem *firstItem = m_visibleItems.first();
1075+ firstItem->setY(firstItem->y() - item->height());
1076+ }
1077+ // Adding an item may break a "same section" chain, so check
1078+ // if we need adding a new section item
1079+ if (m_sectionDelegate) {
1080+ ListItem *nextItem = itemAtIndex(modelIndex + 1);
1081+ if (nextItem && !nextItem->sectionItem()) {
1082+ nextItem->setSectionItem(getSectionItem(modelIndex + 1, true /* alredy inserted into m_visibleItems*/));
1083+ if (growUp && nextItem->sectionItem()) {
1084+ ListItem *firstItem = m_visibleItems.first();
1085+ firstItem->setY(firstItem->y() - nextItem->sectionItem()->height());
1086+ }
1087+ }
1088+ }
1089+ }
1090+ if (firstItemWithViewOnTop) {
1091+ ListItem *firstItem = m_visibleItems.first();
1092+ firstItem->setY(oldFirstValidIndexPos);
1093+ }
1094+ adjustMinYExtent();
1095+ } else if (insert.index <= m_firstVisibleIndex) {
1096+ m_firstVisibleIndex += insert.count;
1097+ }
1098+
1099+ for (int i = insert.count - 1; i >= 0; --i) {
1100+ const int modelIndex = insert.index + i;
1101+ if (modelIndex <= m_asyncRequestedIndex) {
1102+ m_asyncRequestedIndex++;
1103+ }
1104+ }
1105+ }
1106+
1107+ Q_FOREACH(const QQmlChangeSet::Change change, changeSet.changes()) {
1108+ for (int i = change.start(); i < change.end(); ++i) {
1109+ updateSectionItem(i);
1110+ }
1111+ // Also update the section header for the next item after the change since it may be influenced
1112+ updateSectionItem(change.end());
1113+ }
1114+
1115+ if (m_firstVisibleIndex != oldFirstVisibleIndex) {
1116+ if (m_visibleItems.isEmpty()) {
1117+ initializeValuesForEmptyList();
1118+ } else {
1119+ adjustMinYExtent();
1120+ }
1121+ }
1122+
1123+ for (int i = 0; i < m_visibleItems.count(); ++i) {
1124+ ListItem *item = m_visibleItems[i];
1125+ if (item->sectionItem()) {
1126+ item->sectionItem()->setProperty("delegate", QVariant::fromValue(item->m_item));
1127+ }
1128+ }
1129+
1130+ layout();
1131+ polish();
1132+ m_contentHeightDirty = true;
1133+}
1134+
1135+void ListViewWithPageHeader::contentYAnimationRunningChanged(bool running)
1136+{
1137+ setInteractive(!running);
1138+ if (!running) {
1139+ m_contentHeightDirty = true;
1140+ polish();
1141+ }
1142+}
1143+
1144+void ListViewWithPageHeader::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1145+{
1146+ const qreal heightDiff = newGeometry.height() - oldGeometry.height();
1147+ if (heightDiff != 0) {
1148+ if (!m_visibleItems.isEmpty()) {
1149+ ListItem *firstItem = m_visibleItems.first();
1150+ const auto prevFirstItemY = firstItem->y();
1151+ if (!m_inContentHeightKeepHeaderShown && oldGeometry.y() + oldGeometry.height() + m_clipItem->y() <= contentY()) {
1152+ firstItem->setY(firstItem->y() - heightDiff);
1153+ } else if (item == firstItem->sectionItem()) {
1154+ firstItem->setY(firstItem->y() + heightDiff);
1155+ }
1156+
1157+ if (firstItem->y() != prevFirstItemY) {
1158+ adjustMinYExtent();
1159+ layout();
1160+ }
1161+ }
1162+ refill();
1163+ adjustMinYExtent();
1164+ polish();
1165+ m_contentHeightDirty = true;
1166+ }
1167+}
1168+
1169+void ListViewWithPageHeader::itemImplicitHeightChanged(QQuickItem *item)
1170+{
1171+ if (item == m_headerItem) {
1172+ const qreal diff = m_headerItem->implicitHeight() - m_previousHeaderImplicitHeight;
1173+ if (diff != 0) {
1174+ adjustHeader(diff);
1175+ m_previousHeaderImplicitHeight = m_headerItem->implicitHeight();
1176+ layout();
1177+ polish();
1178+ m_contentHeightDirty = true;
1179+ }
1180+ }
1181+}
1182+
1183+void ListViewWithPageHeader::headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY)
1184+{
1185+ const qreal heightDiff = newHeaderHeight - oldHeaderHeight;
1186+ if (m_headerItemShownHeight > 0) {
1187+ // If the header is shown because of the clip
1188+ // Change its size
1189+ m_headerItemShownHeight += heightDiff;
1190+ m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, newHeaderHeight);
1191+ updateClipItem();
1192+ adjustMinYExtent();
1193+ Q_EMIT headerItemShownHeightChanged();
1194+ } else {
1195+ if (oldHeaderY + oldHeaderHeight > contentY()) {
1196+ // If the header is shown because its position
1197+ // Change its size
1198+ ListItem *firstItem = m_visibleItems.first();
1199+ firstItem->setY(firstItem->y() + heightDiff);
1200+ layout();
1201+ } else {
1202+ // If the header is not on screen, just change the start of the list
1203+ // so the viewport is not changed
1204+ adjustMinYExtent();
1205+ }
1206+ }
1207+}
1208+
1209+
1210+void ListViewWithPageHeader::adjustMinYExtent()
1211+{
1212+ if (m_visibleItems.isEmpty() || (contentHeight() + m_minYExtent < height())) {
1213+ m_minYExtent = 0;
1214+ } else {
1215+ qreal nonCreatedHeight = 0;
1216+ if (m_firstVisibleIndex != 0) {
1217+ // Calculate the average height of items to estimate the position of the list start
1218+ const int visibleItems = m_visibleItems.count();
1219+ qreal visibleItemsHeight = 0;
1220+ Q_FOREACH(ListItem *item, m_visibleItems) {
1221+ visibleItemsHeight += item->height();
1222+ }
1223+ nonCreatedHeight = m_firstVisibleIndex * visibleItemsHeight / visibleItems;
1224+// qDebug() << m_firstVisibleIndex << visibleItemsHeight << visibleItems << nonCreatedHeight;
1225+ }
1226+ const qreal headerHeight = (m_headerItem ? m_headerItem->implicitHeight() : 0);
1227+ m_minYExtent = nonCreatedHeight - m_visibleItems.first()->y() - m_clipItem->y() + headerHeight;
1228+ if (m_minYExtent != 0 && qFuzzyIsNull(m_minYExtent)) {
1229+ m_minYExtent = 0;
1230+ m_visibleItems.first()->setY(nonCreatedHeight - m_clipItem->y() + headerHeight);
1231+ }
1232+ }
1233+}
1234+
1235+ListViewWithPageHeader::ListItem *ListViewWithPageHeader::itemAtIndex(int modelIndex) const
1236+{
1237+ const int visibleIndexedModelIndex = modelIndex - m_firstVisibleIndex;
1238+ if (visibleIndexedModelIndex >= 0 && visibleIndexedModelIndex < m_visibleItems.count())
1239+ return m_visibleItems[visibleIndexedModelIndex];
1240+
1241+ return nullptr;
1242+}
1243+
1244+void ListViewWithPageHeader::layout()
1245+{
1246+ if (m_inLayout)
1247+ return;
1248+
1249+ m_inLayout = true;
1250+ if (!m_visibleItems.isEmpty()) {
1251+ const qreal visibleFrom = contentY() - m_clipItem->y() + m_headerItemShownHeight;
1252+ const qreal visibleTo = contentY() + height() - m_clipItem->y();
1253+
1254+ qreal pos = m_visibleItems.first()->y();
1255+
1256+// qDebug() << "ListViewWithPageHeader::layout Updating positions and heights. contentY" << contentY() << "minYExtent" << minYExtent();
1257+ int firstReallyVisibleItem = -1;
1258+ int modelIndex = m_firstVisibleIndex;
1259+ Q_FOREACH(ListItem *item, m_visibleItems) {
1260+ const bool cull = pos + item->height() <= visibleFrom || pos >= visibleTo;
1261+ item->setCulled(cull);
1262+ item->setY(pos);
1263+ if (!cull && firstReallyVisibleItem == -1) {
1264+ firstReallyVisibleItem = modelIndex;
1265+ if (m_topSectionItem) {
1266+ // Positing the top section sticky item is a two step process
1267+ // First we set it either we cull it (because it doesn't need to be sticked to the top)
1268+ // or stick it to the top
1269+ // Then after the loop we'll make sure that if there's another section just below it
1270+ // pushed the sticky section up to make it disappear
1271+ const qreal topSectionStickPos = m_headerItemShownHeight + contentY() - m_clipItem->y();
1272+ bool showStickySectionItem;
1273+ // We need to show the "top section sticky item" when the position at the "top" of the
1274+ // viewport is bigger than the start of the position of the first visible item
1275+ // i.e. the first visible item starts before the viewport, or when the first
1276+ // visible item starts just at the viewport start and it does not have its own section item
1277+ if (topSectionStickPos > pos) {
1278+ showStickySectionItem = true;
1279+ } else if (topSectionStickPos == pos) {
1280+ showStickySectionItem = !item->sectionItem();
1281+ } else {
1282+ showStickySectionItem = false;
1283+ }
1284+ if (!showStickySectionItem) {
1285+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
1286+ if (item->sectionItem()) {
1287+ // This seems it should happen since why would we cull the top section
1288+ // if the first visible item has no section header? This only happens briefly
1289+ // when increasing the height of a list that is at the bottom, the m_topSectionItem
1290+ // gets shown shortly in the next polish call
1291+ QQuickItemPrivate::get(item->sectionItem())->setCulled(false);
1292+ }
1293+ } else {
1294+ // Update the top sticky section header
1295+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
1296+ m_topSectionItem->setProperty("text", section);
1297+
1298+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
1299+ m_topSectionItem->setY(topSectionStickPos);
1300+ m_topSectionItem->setProperty("delegate", QVariant::fromValue(item->m_item));
1301+ if (item->sectionItem()) {
1302+ QQuickItemPrivate::get(item->sectionItem())->setCulled(true);
1303+ }
1304+ }
1305+ }
1306+ }
1307+ const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);
1308+ if (!cull && pos < clipFrom) {
1309+ item->m_item->setProperty("heightToClip", clipFrom - pos);
1310+ } else {
1311+ item->m_item->setProperty("heightToClip", QVariant::fromValue<int>(0));
1312+ }
1313+// qDebug() << "ListViewWithPageHeader::layout" << item->m_item;
1314+ pos += item->height();
1315+ ++modelIndex;
1316+ }
1317+
1318+ // Second step of section sticky item positioning
1319+ // Look at the next section header, check if it's pushing up the sticky one
1320+ if (m_topSectionItem) {
1321+ if (firstReallyVisibleItem >= 0) {
1322+ for (int i = firstReallyVisibleItem - m_firstVisibleIndex + 1; i < m_visibleItems.count(); ++i) {
1323+ ListItem *item = m_visibleItems[i];
1324+ if (item->sectionItem()) {
1325+ if (m_topSectionItem->y() + m_topSectionItem->height() > item->y()) {
1326+ m_topSectionItem->setY(item->y() - m_topSectionItem->height());
1327+ }
1328+ break;
1329+ }
1330+ }
1331+ }
1332+ }
1333+ }
1334+ if (m_headerItem) {
1335+ const bool cullHeader = m_headerItem->y() + m_headerItem->height() < contentY();
1336+ QQuickItemPrivate::get(m_headerItem)->setCulled(cullHeader);
1337+ }
1338+ m_inLayout = false;
1339+}
1340+
1341+void ListViewWithPageHeader::updatePolish()
1342+{
1343+ // Check we are not being taken down and don't paint anything
1344+ // TODO Check if we still need this in 5.2
1345+ // For reproduction just inifnite loop testDash or testDashContent
1346+ if (!QQmlEngine::contextForObject(this)->parentContext())
1347+ return;
1348+
1349+ Q_FOREACH(ListItem *item, m_itemsToRelease)
1350+ reallyReleaseItem(item);
1351+ m_itemsToRelease.clear();
1352+
1353+ if (!model())
1354+ return;
1355+
1356+ layout();
1357+
1358+ refill();
1359+
1360+ if (m_contentHeightDirty) {
1361+ qreal contentHeight;
1362+ if (m_visibleItems.isEmpty()) {
1363+ contentHeight = m_headerItem ? m_headerItem->height() : 0;
1364+ } else {
1365+ const int modelCount = model()->rowCount();
1366+ const int visibleItems = m_visibleItems.count();
1367+ const int lastValidIndex = m_firstVisibleIndex + visibleItems - 1;
1368+ qreal nonCreatedHeight = 0;
1369+ if (lastValidIndex != modelCount - 1) {
1370+ const int visibleItems = m_visibleItems.count();
1371+ qreal visibleItemsHeight = 0;
1372+ Q_FOREACH(ListItem *item, m_visibleItems) {
1373+ visibleItemsHeight += item->height();
1374+ }
1375+ const int unknownSizes = modelCount - (m_firstVisibleIndex + visibleItems);
1376+ nonCreatedHeight = unknownSizes * visibleItemsHeight / visibleItems;
1377+ }
1378+ ListItem *item = m_visibleItems.last();
1379+ contentHeight = nonCreatedHeight + item->y() + item->height() + m_clipItem->y();
1380+ if (m_firstVisibleIndex != 0) {
1381+ // Make sure that if we are shrinking we tell the view we still fit
1382+ m_minYExtent = qMax(m_minYExtent, -(contentHeight - height()));
1383+ }
1384+ }
1385+
1386+ m_contentHeightDirty = false;
1387+ adjustMinYExtent();
1388+ m_inContentHeightKeepHeaderShown = m_headerItem && m_headerItem->y() == contentY();
1389+ setContentHeight(contentHeight);
1390+ m_inContentHeightKeepHeaderShown = false;
1391+ }
1392+}
1393+
1394+#include "moc_listviewwithpageheader.cpp"
plugins/Dash/listviewwithpageheader.hnew file+218
@@ -0,0 +1,218 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef LISTVIEWWITHPAGEHEADER_H
18+#define LISTVIEWWITHPAGEHEADER_H
19+
20+#include <private/qquickitemchangelistener_p.h>
21+#include <private/qquickflickable_p.h>
22+
23+class QAbstractItemModel;
24+class QQuickNumberAnimation;
25+class QQmlChangeSet;
26+class QQmlDelegateModel;
27+
28+
29+/**
30+ Note for users of this class
31+
32+ ListViewWithPageHeader already loads delegates async when appropiate so if
33+ your delegate uses a Loader you should not enable the asynchronous feature since
34+ that will need to introduce sizing problems
35+
36+ With the double async it may happen what while we are scrolling down
37+ we reach to a point where given the size of the just created delegate with loader not yet loaded (which will be very close to 0)
38+ we are already "at the end" of the list, but then a few milliseconds later the loader finishes loading and we could
39+ have kept scrolling. This is specially visible at the end of the list where you realize
40+ that scrolling ended a bit before the end of the list but the speed of the flicking was good
41+ to reach the end
42+
43+ By not having the second async we get a better sizing when the delegate is created and things work better
44+*/
45+
46+class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeListener
47+{
48+ Q_OBJECT
49+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
50+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
51+ Q_PROPERTY(QQuickItem *pageHeader READ header WRITE setHeader NOTIFY headerChanged)
52+ Q_PROPERTY(QQmlComponent *sectionDelegate READ sectionDelegate WRITE setSectionDelegate NOTIFY sectionDelegateChanged)
53+ Q_PROPERTY(QString sectionProperty READ sectionProperty WRITE setSectionProperty NOTIFY sectionPropertyChanged)
54+ Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
55+ Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
56+ Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
57+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
58+
59+ friend class ListViewWithPageHeaderTest;
60+ friend class ListViewWithPageHeaderTestSection;
61+ friend class ListViewWithPageHeaderTestExternalModel;
62+
63+public:
64+ ListViewWithPageHeader();
65+ ~ListViewWithPageHeader();
66+
67+ QAbstractItemModel *model() const;
68+ void setModel(QAbstractItemModel *model);
69+
70+ QQmlComponent *delegate() const;
71+ void setDelegate(QQmlComponent *delegate);
72+
73+ QQuickItem *header() const;
74+ void setHeader(QQuickItem *header);
75+
76+ QQmlComponent *sectionDelegate() const;
77+ void setSectionDelegate(QQmlComponent *delegate);
78+
79+ QString sectionProperty() const;
80+ void setSectionProperty(const QString &property);
81+
82+ bool forceNoClip() const;
83+ void setForceNoClip(bool noClip);
84+
85+ int stickyHeaderHeight() const;
86+ qreal headerItemShownHeight() const;
87+
88+ int cacheBuffer() const;
89+ void setCacheBuffer(int cacheBuffer);
90+
91+ Q_INVOKABLE void positionAtBeginning();
92+ Q_INVOKABLE void showHeader();
93+ Q_INVOKABLE int firstCreatedIndex() const;
94+ Q_INVOKABLE int createdItemCount() const;
95+ Q_INVOKABLE QQuickItem *item(int modelIndex) const;
96+
97+ // The index has to be created for this to try to do something
98+ // Created items are those visible and the precached ones
99+ // Returns if the item existed or not
100+ Q_INVOKABLE bool maximizeVisibleArea(int modelIndex);
101+ Q_INVOKABLE bool maximizeVisibleArea(int modelIndex, int itemHeight);
102+
103+Q_SIGNALS:
104+ void modelChanged();
105+ void delegateChanged();
106+ void headerChanged();
107+ void sectionDelegateChanged();
108+ void sectionPropertyChanged();
109+ void forceNoClipChanged();
110+ void stickyHeaderHeightChanged();
111+ void headerItemShownHeightChanged();
112+ void cacheBufferChanged();
113+
114+protected:
115+ void componentComplete() override;
116+ void viewportMoved(Qt::Orientations orient) override;
117+ qreal minYExtent() const override;
118+ qreal maxYExtent() const override;
119+ void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
120+ void itemImplicitHeightChanged(QQuickItem *item) override;
121+ void updatePolish() override;
122+
123+private Q_SLOTS:
124+ void itemCreated(int modelIndex, QObject *object);
125+ void onContentHeightChanged();
126+ void onContentWidthChanged();
127+ void onHeightChanged();
128+ void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
129+ void contentYAnimationRunningChanged(bool running);
130+
131+private:
132+ class ListItem
133+ {
134+ public:
135+ qreal height() const;
136+
137+ qreal y() const;
138+ void setY(qreal newY);
139+
140+ bool culled() const;
141+ void setCulled(bool culled);
142+
143+ QQuickItem *sectionItem() const { return m_sectionItem; }
144+ void setSectionItem(QQuickItem *sectionItem);
145+
146+ QQuickItem *m_item;
147+ private:
148+ QQuickItem *m_sectionItem;
149+ };
150+
151+ bool maximizeVisibleArea(ListItem *listItem, int listItemHeight);
152+
153+ void createDelegateModel();
154+
155+ void layout();
156+ void refill();
157+ bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
158+ bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
159+ ListItem *createItem(int modelIndex, bool asynchronous);
160+
161+ void adjustHeader(qreal diff);
162+ void adjustMinYExtent();
163+ void updateClipItem();
164+ void headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY);
165+ ListItem *itemAtIndex(int modelIndex) const; // Returns the item at modelIndex if has been created
166+ void releaseItem(ListItem *item);
167+ void reallyReleaseItem(ListItem *item);
168+ void updateWatchedRoles();
169+ QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
170+ QQuickItem *getSectionItem(const QString &sectionText, bool watchGeometry = true);
171+ void updateSectionItem(int modelIndex);
172+ void initializeValuesForEmptyList();
173+
174+ QQmlDelegateModel *m_delegateModel;
175+
176+ // Index we are waiting because we requested it asynchronously
177+ int m_asyncRequestedIndex;
178+
179+ // Used to only give a warning once if the delegate does not return objects
180+ bool m_delegateValidated;
181+
182+ // Visible indexes, [0] is m_firstValidIndex, [0+1] is m_firstValidIndex +1, ...
183+ QList<ListItem *> m_visibleItems;
184+ int m_firstVisibleIndex;
185+
186+ qreal m_minYExtent;
187+
188+ QQuickItem *m_clipItem;
189+
190+ // If any of the heights has changed
191+ // or new items have been added/removed
192+ bool m_contentHeightDirty;
193+
194+ QQuickItem *m_headerItem;
195+ qreal m_previousContentY;
196+ qreal m_previousHeaderImplicitHeight;
197+ qreal m_headerItemShownHeight; // The height of header shown when the header is shown outside its topmost position
198+ // i.e. it's being shown after dragging down in the middle of the list
199+ enum ContentYAnimationType { ContentYAnimationShowHeader, ContentYAnimationMaximizeVisibleArea };
200+ ContentYAnimationType contentYAnimationType;
201+ QQuickNumberAnimation *m_contentYAnimation;
202+
203+ QQmlComponent *m_sectionDelegate;
204+ QString m_sectionProperty;
205+ QQuickItem *m_topSectionItem;
206+
207+ bool m_forceNoClip;
208+ bool m_inLayout;
209+ bool m_inContentHeightKeepHeaderShown;
210+ int m_cacheBuffer;
211+
212+ // Qt 5.0 doesn't like releasing the items just after itemCreated
213+ // so we delay the releasing until the next updatePolish
214+ QList<ListItem *> m_itemsToRelease;
215+};
216+
217+
218+#endif
plugins/Dash/organicgrid.cppnew file+259
@@ -0,0 +1,259 @@
1+/*
2+ * Copyright (C) 2014, 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "organicgrid.h"
18+
19+#include <math.h>
20+
21+#include <private/qquickitem_p.h>
22+
23+OrganicGrid::OrganicGrid()
24+ : m_firstVisibleIndex(-1)
25+ , m_numberOfModulesPerRow(-1)
26+{
27+}
28+
29+QSizeF OrganicGrid::smallDelegateSize() const
30+{
31+ return m_smallDelegateSize;
32+}
33+
34+void OrganicGrid::setSmallDelegateSize(const QSizeF size)
35+{
36+ if (m_smallDelegateSize != size) {
37+ m_smallDelegateSize = size;
38+ Q_EMIT smallDelegateSizeChanged();
39+
40+ if (isComponentComplete()) {
41+ relayout();
42+ }
43+ }
44+}
45+
46+QSizeF OrganicGrid::bigDelegateSize() const
47+{
48+ return m_bigDelegateSize;
49+}
50+
51+void OrganicGrid::setBigDelegateSize(const QSizeF size)
52+{
53+ if (m_bigDelegateSize != size) {
54+ m_bigDelegateSize = size;
55+ Q_EMIT bigDelegateSizeChanged();
56+
57+ if (isComponentComplete()) {
58+ relayout();
59+ }
60+ }
61+}
62+
63+QPointF OrganicGrid::positionForIndex(int modelIndex) const
64+{
65+ const qreal moduleHeight = m_smallDelegateSize.height() + rowSpacing() + m_bigDelegateSize.height();
66+ const qreal moduleWidth = m_smallDelegateSize.width() * 2 + columnSpacing() * 2 + m_bigDelegateSize.width();
67+ const int itemsPerRow = m_numberOfModulesPerRow * 6;
68+ const int rowIndex = floor(modelIndex / itemsPerRow);
69+ const int columnIndex = floor((modelIndex - rowIndex * itemsPerRow) / 6);
70+
71+ qreal yPos = (moduleHeight + rowSpacing()) * rowIndex;
72+ const int moduleIndex = modelIndex % 6;
73+ if (moduleIndex == 2) {
74+ yPos += m_smallDelegateSize.height() + rowSpacing();
75+ } else if (moduleIndex == 3 || moduleIndex == 5) {
76+ yPos += m_bigDelegateSize.height() + rowSpacing();
77+ }
78+
79+ qreal xPos = (moduleWidth + columnSpacing()) * columnIndex;
80+ if (moduleIndex == 1) {
81+ xPos += m_smallDelegateSize.width() + columnSpacing();
82+ } else if (moduleIndex == 3) {
83+ xPos += m_bigDelegateSize.width() + columnSpacing();
84+ } else if (moduleIndex == 4) {
85+ xPos += (m_smallDelegateSize.width() + columnSpacing()) * 2;
86+ } else if (moduleIndex == 5) {
87+ xPos += m_bigDelegateSize.width() + m_smallDelegateSize.width() + columnSpacing() * 2;
88+ }
89+
90+ return QPointF(xPos, yPos);
91+}
92+
93+QSizeF OrganicGrid::sizeForIndex(int modelIndex) const
94+{
95+ const int moduleIndex = modelIndex % 6;
96+ if (moduleIndex == 0 || moduleIndex == 1 || moduleIndex == 3 || moduleIndex == 5) {
97+ return m_smallDelegateSize;
98+ } else {
99+ return m_bigDelegateSize;
100+ }
101+}
102+
103+void OrganicGrid::findBottomModelIndexToAdd(int *modelIndex, qreal *yPos)
104+{
105+ if (m_visibleItems.isEmpty()) {
106+ *modelIndex = 0;
107+ *yPos = 0;
108+ } else {
109+ *modelIndex = m_firstVisibleIndex + m_visibleItems.count();
110+ // We create stuff in a 6-module basis, so always return back
111+ // the y position of the first item
112+ const int firstModuleIndex = ((*modelIndex) / 6) * 6;
113+ *yPos = positionForIndex(firstModuleIndex).y();
114+ }
115+}
116+
117+void OrganicGrid::findTopModelIndexToAdd(int *modelIndex, qreal *yPos)
118+{
119+ if (m_visibleItems.isEmpty()) {
120+ *modelIndex = 0;
121+ *yPos = 0;
122+ } else {
123+ *modelIndex = m_firstVisibleIndex - 1;
124+ // We create stuff in a 6-module basis, so always return back
125+ // the y position of the last item bottom
126+ const int lastModuleIndex = ((*modelIndex) / 6) * 6 + 5;
127+ *yPos = positionForIndex(lastModuleIndex).y();
128+ *yPos += sizeForIndex(lastModuleIndex).height();
129+ }
130+}
131+
132+void OrganicGrid::addItemToView(int modelIndex, QQuickItem *item)
133+{
134+ // modelIndex has to be either m_firstVisibleIndex - 1 or m_firstVisibleIndex + m_visibleItems.count() or the first
135+ if (modelIndex == m_firstVisibleIndex + m_visibleItems.count()) {
136+ m_visibleItems << item;
137+ } else if (modelIndex == m_firstVisibleIndex - 1) {
138+ m_firstVisibleIndex = modelIndex;
139+ m_visibleItems.prepend(item);
140+ } else if (modelIndex == 0) {
141+ m_firstVisibleIndex = 0;
142+ m_visibleItems << item;
143+ } else {
144+ qWarning() << "OrganicGrid::addItemToView - Got unexpected modelIndex"
145+ << modelIndex << m_firstVisibleIndex << m_visibleItems.count();
146+ return;
147+ }
148+
149+ const QPointF pos = positionForIndex(modelIndex);
150+ item->setPosition(pos);
151+
152+ item->setSize(sizeForIndex(modelIndex));
153+}
154+
155+bool OrganicGrid::removeNonVisibleItems(qreal bufferFromY, qreal bufferToY)
156+{
157+ bool changed = false;
158+
159+ // As adding, we also remove in a 6-module basis
160+ int lastModuleIndex = (m_firstVisibleIndex / 6) * 6 + 5;
161+ bool removeIndex = positionForIndex(lastModuleIndex).y() + sizeForIndex(lastModuleIndex).height() < bufferFromY;
162+ while (removeIndex && !m_visibleItems.isEmpty()) {
163+ releaseItem(m_visibleItems.takeFirst());
164+ changed = true;
165+ m_firstVisibleIndex++;
166+
167+ lastModuleIndex = (m_firstVisibleIndex / 6) * 6 + 5;
168+ removeIndex = positionForIndex(lastModuleIndex).y() + sizeForIndex(lastModuleIndex).height() < bufferFromY;
169+ }
170+
171+ int firstModuleIndex = ((m_firstVisibleIndex + m_visibleItems.count() - 1) / 6) * 6;
172+ removeIndex = positionForIndex(firstModuleIndex).y() > bufferToY;
173+ while (removeIndex && !m_visibleItems.isEmpty()) {
174+ releaseItem(m_visibleItems.takeLast());
175+ changed = true;
176+
177+ firstModuleIndex = ((m_firstVisibleIndex + m_visibleItems.count() - 1) / 6) * 6;
178+ removeIndex = positionForIndex(firstModuleIndex).y() > bufferToY;
179+ }
180+
181+ if (m_visibleItems.isEmpty()) {
182+ m_firstVisibleIndex = -1;
183+ }
184+
185+ return changed;
186+}
187+
188+void OrganicGrid::cleanupExistingItems()
189+{
190+ Q_FOREACH(QQuickItem *item, m_visibleItems)
191+ releaseItem(item);
192+ m_visibleItems.clear();
193+ m_firstVisibleIndex = -1;
194+ setImplicitHeightDirty();
195+}
196+
197+void OrganicGrid::doRelayout()
198+{
199+ const qreal moduleWidth = m_smallDelegateSize.width() * 2 + columnSpacing() * 2 + m_bigDelegateSize.width();
200+ m_numberOfModulesPerRow = floor((width() + columnSpacing()) / (moduleWidth + columnSpacing()));
201+ m_numberOfModulesPerRow = qMax(1, m_numberOfModulesPerRow);
202+
203+ int i = m_firstVisibleIndex;
204+ const QList<QQuickItem*> allItems = m_visibleItems;
205+ m_visibleItems.clear();
206+ Q_FOREACH(QQuickItem *item, allItems) {
207+ addItemToView(i, item);
208+ ++i;
209+ }
210+}
211+
212+void OrganicGrid::updateItemCulling(qreal visibleFromY, qreal visibleToY)
213+{
214+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
215+ QQuickItemPrivate::get(item)->setCulled(item->y() + item->height() <= visibleFromY || item->y() >= visibleToY);
216+ }
217+}
218+
219+void OrganicGrid::calculateImplicitHeight()
220+{
221+ const qreal moduleHeight = m_smallDelegateSize.height() + rowSpacing() + m_bigDelegateSize.height();
222+ const int itemCount = !model() ? 0 : model()->rowCount();
223+ const int itemsPerRow = m_numberOfModulesPerRow * 6;
224+ const int fullRows = floor(itemCount / itemsPerRow);
225+ const qreal fullRowsHeight = fullRows == 0 ? 0 : fullRows * moduleHeight + rowSpacing() * (fullRows - 1);
226+
227+ const int remainingItems = itemCount - fullRows * itemsPerRow;
228+ if (remainingItems == 0) {
229+ setImplicitHeight(fullRowsHeight);
230+ } else if (remainingItems <= 2) {
231+ setImplicitHeight(fullRowsHeight + m_smallDelegateSize.height() + rowSpacing());
232+ } else {
233+ setImplicitHeight(fullRowsHeight + rowSpacing() + moduleHeight);
234+ }
235+}
236+
237+void OrganicGrid::processModelRemoves(const QVector<QQmlChangeSet::Change> &removes)
238+{
239+ Q_FOREACH(const QQmlChangeSet::Change remove, removes) {
240+ for (int i = remove.count - 1; i >= 0; --i) {
241+ const int indexToRemove = remove.index + i;
242+ // We only support removing from the end
243+ const int lastIndex = m_firstVisibleIndex + m_visibleItems.count() - 1;
244+ if (indexToRemove == lastIndex) {
245+ releaseItem(m_visibleItems.takeLast());
246+ } else {
247+ if (indexToRemove < lastIndex) {
248+ qDebug() << "OrganicGrid only supports removal from the end of the model, resetting instead";
249+ cleanupExistingItems();
250+ break;
251+ }
252+ }
253+ }
254+ }
255+ if (m_visibleItems.isEmpty()) {
256+ m_firstVisibleIndex = -1;
257+ }
258+ setImplicitHeightDirty();
259+}
plugins/Dash/organicgrid.hnew file+91
@@ -0,0 +1,91 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef ORGANICGRID_H
18+#define ORGANICGRID_H
19+
20+#include "abstractdashview.h"
21+
22+ /** An Organic Grid is is a view that creates delegates
23+ * based on a model and layouts them in groups of six items (called module).
24+ *
25+ * In each module there are 4 items that are forced to the small delegate size
26+ * and two that are forced to the big delegate size.
27+ *
28+ * Example:
29+ *
30+ * +---+ +---+ +-----+
31+ * | 1 | | 2 | | |
32+ * +---+ +---+ | 5 |
33+ * +-----+ | |
34+ * | | +-----+
35+ * | 3 | +---+ +---+
36+ * | | | 4 | | 6 |
37+ * +-----+ +---+ +---+
38+ *
39+ * Modules are positioned one after the other in a grid like fashion, i.e.
40+ *
41+ * +---+ +---+
42+ * | 1 | | 2 |
43+ * +---+ +---+
44+ * +---+ +---+
45+ * | 3 | | 4 |
46+ * +---+ +---+
47+ */
48+
49+class OrganicGrid : public AbstractDashView
50+{
51+ Q_OBJECT
52+
53+ Q_PROPERTY(QSizeF smallDelegateSize READ smallDelegateSize WRITE setSmallDelegateSize NOTIFY smallDelegateSizeChanged)
54+ Q_PROPERTY(QSizeF bigDelegateSize READ bigDelegateSize WRITE setBigDelegateSize NOTIFY bigDelegateSizeChanged)
55+
56+friend class OrganicGridTest;
57+
58+public:
59+ OrganicGrid();
60+
61+ QSizeF smallDelegateSize() const;
62+ void setSmallDelegateSize(const QSizeF size);
63+
64+ QSizeF bigDelegateSize() const;
65+ void setBigDelegateSize(const QSizeF size);
66+
67+Q_SIGNALS:
68+ void smallDelegateSizeChanged();
69+ void bigDelegateSizeChanged();
70+private:
71+ QPointF positionForIndex(int modelIndex) const;
72+ QSizeF sizeForIndex(int modelIndex) const;
73+
74+ void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) override;
75+ void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) override;
76+ void addItemToView(int modelIndex, QQuickItem *item) override;
77+ bool removeNonVisibleItems(qreal bufferFromY, qreal bufferToY) override;
78+ void cleanupExistingItems() override;
79+ void doRelayout() override;
80+ void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
81+ void calculateImplicitHeight() override;
82+ void processModelRemoves(const QVector<QQmlChangeSet::Change> &removes) override;
83+
84+ QSizeF m_smallDelegateSize;
85+ QSizeF m_bigDelegateSize;
86+ int m_firstVisibleIndex;
87+ int m_numberOfModulesPerRow;
88+ QList<QQuickItem*> m_visibleItems;
89+};
90+
91+#endif
plugins/Dash/plugin.cppnew file+70
@@ -0,0 +1,70 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#include "plugin.h"
19+
20+#include "horizontaljournal.h"
21+#include "listviewwithpageheader.h"
22+#include "organicgrid.h"
23+#include "verticaljournal.h"
24+
25+#include <QAbstractItemModel>
26+#include <QUrlQuery>
27+
28+static QUrl oauthCleanedUrl(QUrl u)
29+{
30+ QUrlQuery q(u);
31+ q.removeQueryItem(QStringLiteral("oauth_nonce"));
32+ q.removeQueryItem(QStringLiteral("oauth_timestamp"));
33+ q.removeQueryItem(QStringLiteral("oauth_consumer_key"));
34+ q.removeQueryItem(QStringLiteral("oauth_signature_method"));
35+ q.removeQueryItem(QStringLiteral("oauth_version"));
36+ q.removeQueryItem(QStringLiteral("oauth_signature"));
37+ u.setQuery(q);
38+ return u;
39+}
40+
41+class AudioComparer : public QObject
42+{
43+ Q_OBJECT
44+public:
45+ Q_INVOKABLE bool compare(const QUrl &url1, const QUrl &url2)
46+ {
47+ return oauthCleanedUrl(url1) == oauthCleanedUrl(url2);
48+ }
49+};
50+
51+static QObject *audio_comparer_singleton_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
52+{
53+ Q_UNUSED(engine)
54+ Q_UNUSED(scriptEngine)
55+
56+ return new AudioComparer();
57+}
58+
59+void DashPlugin::registerTypes(const char *uri)
60+{
61+ Q_ASSERT(uri == QLatin1String("Dash"));
62+ qmlRegisterType<QAbstractItemModel>();
63+ qmlRegisterType<HorizontalJournal>(uri, 0, 1, "HorizontalJournal");
64+ qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader");
65+ qmlRegisterType<OrganicGrid>(uri, 0, 1, "OrganicGrid");
66+ qmlRegisterType<VerticalJournal>(uri, 0, 1, "VerticalJournal");
67+ qmlRegisterSingletonType<AudioComparer>(uri, 0, 1, "AudioUrlComparer", audio_comparer_singleton_provider);
68+}
69+
70+#include "plugin.moc"
plugins/Dash/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#ifndef DASH_PLUGIN_H
19+#define DASH_PLUGIN_H
20+
21+#include <QtQml/QQmlEngine>
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class DashPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri) override;
31+};
32+
33+#endif
plugins/Dash/qmldirnew file+11
@@ -0,0 +1,11 @@
1+module Dash
2+plugin Dash-qml
3+typeinfo Dash.qmltypes
4+singleton CardCreatorCache 0.1 CardCreatorCache.qml
5+singleton DashAudioPlayer 0.1 DashAudioPlayer.qml
6+ScopeStyle 0.1 ScopeStyle.qml
7+CardAttributes 0.1 CardAttributes.qml
8+CardSocialActions 0.1 CardSocialActions.qml
9+CroppedImageMinimumSourceSize 0.1 CroppedImageMinimumSourceSize.qml
10+AudioProgressBar 0.1 AudioProgressBar.qml
11+CardAudioProgress 0.1 CardAudioProgress.qml
plugins/Dash/verticaljournal.cppnew file+280
@@ -0,0 +1,280 @@
1+/*
2+ * Copyright (C) 2013, 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+/*
18+ * The implementation is centered around m_columnVisibleItems
19+ * that holds a vector of lists. There's a list for each of the
20+ * columns the view has. In the list the items of the column are
21+ * ordered as they appear topdown in the view. m_indexColumnMap is
22+ * used when re-building the list up since given a position
23+ * in the middle of the list and the need to create the previous does
24+ * not give us enough information to know in which column we have
25+ * to position the item so that when we reach the item the view is
26+ * correctly layouted at 0 for all the columns
27+ */
28+#include "verticaljournal.h"
29+
30+#include <math.h>
31+
32+#include <private/qquickitem_p.h>
33+
34+VerticalJournal::VerticalJournal()
35+ : m_columnWidth(0)
36+{
37+}
38+
39+qreal VerticalJournal::columnWidth() const
40+{
41+ return m_columnWidth;
42+}
43+
44+void VerticalJournal::setColumnWidth(qreal columnWidth)
45+{
46+ if (columnWidth != m_columnWidth) {
47+ m_columnWidth = columnWidth;
48+ Q_EMIT columnWidthChanged();
49+
50+ if (isComponentComplete()) {
51+ Q_FOREACH(const auto &column, m_columnVisibleItems) {
52+ Q_FOREACH(const ViewItem item, column) {
53+ item.m_item->setWidth(columnWidth);
54+ }
55+ }
56+ relayout();
57+ }
58+ }
59+}
60+
61+void VerticalJournal::findBottomModelIndexToAdd(int *modelIndex, qreal *yPos)
62+{
63+ *modelIndex = 0;
64+ *yPos = std::numeric_limits<qreal>::max();
65+
66+ Q_FOREACH(const auto &column, m_columnVisibleItems) {
67+ if (!column.isEmpty()) {
68+ const ViewItem &item = column.last();
69+ *yPos = qMin(*yPos, item.y() + item.height() + rowSpacing());
70+ *modelIndex = qMax(*modelIndex, item.m_modelIndex + 1);
71+ } else {
72+ *yPos = 0;
73+ }
74+ }
75+}
76+
77+void VerticalJournal::findTopModelIndexToAdd(int *modelIndex, qreal *yPos)
78+{
79+ *modelIndex = 0;
80+ *yPos = std::numeric_limits<qreal>::lowest();
81+ int columnToAddTo = -1;
82+
83+ // Find the topmost free column
84+ for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
85+ const auto &column = m_columnVisibleItems[i];
86+ if (!column.isEmpty()) {
87+ const ViewItem &item = column.first();
88+ const auto itemTopPos = item.y() - rowSpacing();
89+ if (itemTopPos > *yPos) {
90+ *yPos = itemTopPos;
91+ *modelIndex = item.m_modelIndex - 1;
92+ columnToAddTo = i;
93+ }
94+ }
95+ }
96+
97+ if (*modelIndex > 0) {
98+ Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
99+ while (*modelIndex > 0 && m_indexColumnMap[*modelIndex] != columnToAddTo) {
100+ // We found out that we have to add to columnToAddTo
101+ // and thought that we had to add *modelIndex, but history tells
102+ // it is not correct, so find up from *modelIndex until we found the index
103+ // that has to end up in columnToAddTo
104+ *modelIndex = *modelIndex - 1;
105+ Q_ASSERT(m_indexColumnMap.contains(*modelIndex));
106+ }
107+ }
108+}
109+
110+bool VerticalJournal::removeNonVisibleItems(qreal bufferFromY, qreal bufferToY)
111+{
112+ bool changed = false;
113+
114+ for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
115+ QList<ViewItem> &column = m_columnVisibleItems[i];
116+ while (!column.isEmpty() && column.first().y() + column.first().height() < bufferFromY) {
117+ releaseItem(column.takeFirst().m_item);
118+ changed = true;
119+ }
120+
121+ while (!column.isEmpty() && column.last().y() > bufferToY) {
122+ releaseItem(column.takeLast().m_item);
123+ changed = true;
124+ }
125+ }
126+
127+ return changed;
128+}
129+
130+void VerticalJournal::addItemToView(int modelIndex, QQuickItem *item)
131+{
132+ if (item->width() != m_columnWidth) {
133+ qWarning() << "Item" << modelIndex << "width is not the one that the columnWidth mandates, resetting it";
134+ item->setWidth(m_columnWidth);
135+ }
136+
137+ // Check if we add it to the bottom of existing column items
138+ const QList<ViewItem> &firstColumn = m_columnVisibleItems[0];
139+ qreal columnToAddY = !firstColumn.isEmpty() ? firstColumn.last().y() + firstColumn.last().height() : -rowSpacing();
140+ int columnToAddTo = 0;
141+ for (int i = 1; i < m_columnVisibleItems.count(); ++i) {
142+ const QList<ViewItem> &column = m_columnVisibleItems[i];
143+ const qreal iY = !column.isEmpty() ? column.last().y() + column.last().height() : -rowSpacing();
144+ if (iY < columnToAddY) {
145+ columnToAddTo = i;
146+ columnToAddY = iY;
147+ }
148+ }
149+
150+ const QList<ViewItem> &columnToAdd = m_columnVisibleItems[columnToAddTo];
151+ if (columnToAdd.isEmpty() || columnToAdd.last().m_modelIndex < modelIndex) {
152+ item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
153+ item->setY(columnToAddY + rowSpacing());
154+
155+ m_columnVisibleItems[columnToAddTo] << ViewItem(item, modelIndex);
156+ m_indexColumnMap[modelIndex] = columnToAddTo;
157+ } else {
158+ Q_ASSERT(m_indexColumnMap.contains(modelIndex));
159+ columnToAddTo = m_indexColumnMap[modelIndex];
160+ columnToAddY = m_columnVisibleItems[columnToAddTo].first().y();
161+
162+ item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
163+ item->setY(columnToAddY - rowSpacing() - item->height());
164+
165+ m_columnVisibleItems[columnToAddTo].prepend(ViewItem(item, modelIndex));
166+ }
167+}
168+
169+void VerticalJournal::cleanupExistingItems()
170+{
171+ // Cleanup the existing items
172+ for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
173+ QList<ViewItem> &column = m_columnVisibleItems[i];
174+ Q_FOREACH(const ViewItem item, column)
175+ releaseItem(item.m_item);
176+ column.clear();
177+ }
178+ m_indexColumnMap.clear();
179+ setImplicitHeightDirty();
180+}
181+
182+void VerticalJournal::calculateImplicitHeight()
183+{
184+ int lastModelIndex = -1;
185+ qreal bottomMostY = 0;
186+ Q_FOREACH(const auto &column, m_columnVisibleItems) {
187+ if (!column.isEmpty()) {
188+ const ViewItem &item = column.last();
189+ lastModelIndex = qMax(lastModelIndex, item.m_modelIndex);
190+ bottomMostY = qMax(bottomMostY, item.y() + item.height());
191+ }
192+ }
193+ if (lastModelIndex >= 0) {
194+ const double averageHeight = bottomMostY / (lastModelIndex + 1);
195+ setImplicitHeight(bottomMostY + averageHeight * (model()->rowCount() - lastModelIndex - 1));
196+ } else {
197+ setImplicitHeight(0);
198+ }
199+}
200+
201+void VerticalJournal::doRelayout()
202+{
203+ QList<ViewItem> allItems;
204+ Q_FOREACH(const auto &column, m_columnVisibleItems)
205+ allItems << column;
206+
207+ qSort(allItems);
208+
209+ const int nColumns = qMax(1., floor((double)(width() + columnSpacing()) / (m_columnWidth + columnSpacing())));
210+ m_columnVisibleItems.resize(nColumns);
211+ m_indexColumnMap.clear();
212+ for (int i = 0; i < nColumns; ++i)
213+ m_columnVisibleItems[i].clear();
214+
215+ // If the first of allItems doesn't contain index 0 we need to drop them
216+ // all since we can't consistently relayout without the first item being there
217+
218+ if (!allItems.isEmpty()) {
219+ if (allItems.first().m_modelIndex == 0) {
220+ Q_FOREACH(const ViewItem item, allItems)
221+ addItemToView(item.m_modelIndex, item.m_item);
222+ } else {
223+ Q_FOREACH(const ViewItem item, allItems)
224+ releaseItem(item.m_item);
225+ }
226+ }
227+}
228+
229+void VerticalJournal::updateItemCulling(qreal visibleFromY, qreal visibleToY)
230+{
231+ Q_FOREACH(const auto &column, m_columnVisibleItems) {
232+ Q_FOREACH(const ViewItem item, column) {
233+ const bool cull = item.y() + item.height() <= visibleFromY || item.y() >= visibleToY;
234+ QQuickItemPrivate::get(item.m_item)->setCulled(cull);
235+ }
236+ }
237+}
238+
239+void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Change> &removes)
240+{
241+ Q_FOREACH(const QQmlChangeSet::Change remove, removes) {
242+ for (int i = remove.count - 1; i >= 0; --i) {
243+ const int indexToRemove = remove.index + i;
244+ // Since we only support removing from the end, indexToRemove
245+ // must refer to the last item of one of the columns or
246+ // be bigger than them (because it's not in the viewport and
247+ // thus we have not created a delegate for it)
248+ bool found = false;
249+ int lastCreatedIndex = INT_MIN;
250+ for (int i = 0; !found && i < m_columnVisibleItems.count(); ++i) {
251+ QList<ViewItem> &column = m_columnVisibleItems[i];
252+ if (!column.isEmpty()) {
253+ const int lastColumnIndex = column.last().m_modelIndex;
254+ if (lastColumnIndex == indexToRemove) {
255+ releaseItem(column.takeLast().m_item);
256+ found = true;
257+ }
258+ lastCreatedIndex = qMax(lastCreatedIndex, lastColumnIndex);
259+ }
260+ }
261+ if (!found) {
262+ if (indexToRemove < lastCreatedIndex) {
263+ qDebug() << "VerticalJournal only supports removal from the end of the model, resetting instead";
264+ cleanupExistingItems();
265+ break;
266+ } else {
267+ setImplicitHeightDirty();
268+ }
269+ }
270+ }
271+ }
272+}
273+
274+void VerticalJournal::itemGeometryChanged(QQuickItem * /*item*/, const QRectF &newGeometry, const QRectF &oldGeometry)
275+{
276+ const qreal heightDiff = newGeometry.height() - oldGeometry.height();
277+ if (heightDiff != 0) {
278+ relayout();
279+ }
280+}
plugins/Dash/verticaljournal.hnew file+103
@@ -0,0 +1,103 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef VERTICALJOURNAL_H
18+#define VERTICALJOURNAL_H
19+
20+#include "abstractdashview.h"
21+
22+ /** A vertical journal is a view that creates delegates
23+ * based on a model and layouts them in columns following
24+ * a top-left most position rule.
25+ *
26+ * The number of columns is calculated using the width of
27+ * the view itself, the columnWidth (i.e. the width of each individual delegate)
28+ * and the columnSpacing between columns.
29+ *
30+ * All delegates are forced to columnWidth if they don't have it.
31+ *
32+ * The first nColumns items are layouted at row 0 from column 0
33+ * to column nColumns-1 in order. After that every new item
34+ * is positioned in the column which provides the free topmost
35+ * position as possible. If more than one column tie in providing
36+ * the topmost free position the leftmost column will be used.
37+ *
38+ * Example:
39+ *
40+ * +-----+ +-----+ +-----+
41+ * | | | 2 | | |
42+ * | | | | | |
43+ * | 1 | +-----+ | 3 |
44+ * | | +-----+ | |
45+ * | | | | +-----+
46+ * +-----+ | 4 | +-----+
47+ * +-----+ | | | 5 |
48+ * | 6 | +-----+ | |
49+ * | | +-----+
50+ * +-----+
51+ *
52+ */
53+
54+class VerticalJournal : public AbstractDashView
55+{
56+ Q_OBJECT
57+
58+ Q_PROPERTY(qreal columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged)
59+
60+friend class VerticalJournalTest;
61+
62+public:
63+ VerticalJournal();
64+
65+ qreal columnWidth() const;
66+ void setColumnWidth(qreal columnWidth);
67+
68+protected:
69+ void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
70+
71+Q_SIGNALS:
72+ void columnWidthChanged();
73+
74+private:
75+ class ViewItem
76+ {
77+ public:
78+ ViewItem(QQuickItem *item, int modelIndex) : m_item(item), m_modelIndex(modelIndex) {}
79+ qreal x() const { return m_item->x(); }
80+ qreal y() const { return m_item->y(); }
81+ qreal height() const { return m_item->height(); }
82+ bool operator<(const ViewItem v) const { return m_modelIndex < v.m_modelIndex; }
83+
84+ QQuickItem *m_item;
85+ int m_modelIndex;
86+ };
87+
88+ void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) override;
89+ void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) override;
90+ bool removeNonVisibleItems(qreal bufferFromY, qreal bufferToY) override;
91+ void addItemToView(int modelIndex, QQuickItem *item) override;
92+ void cleanupExistingItems() override;
93+ void calculateImplicitHeight() override;
94+ void doRelayout() override;
95+ void updateItemCulling(qreal visibleFromY, qreal visibleToY) override;
96+ void processModelRemoves(const QVector<QQmlChangeSet::Change> &removes) override;
97+
98+ QVector<QList<ViewItem>> m_columnVisibleItems;
99+ QHash<int, int> m_indexColumnMap;
100+ int m_columnWidth;
101+};
102+
103+#endif
plugins/GlobalShortcut/CMakeLists.txt+1−1
@@ -5,6 +5,6 @@ set(globalshortcutplugin_SRCS
5
5
6add_library(GlobalShortcut-qml SHARED ${globalshortcutplugin_SRCS})
6add_library(GlobalShortcut-qml SHARED ${globalshortcutplugin_SRCS})
7
7
8−target_link_libraries(GlobalShortcut-qml Qt5::Quick Qt5::Gui)
8+qt5_use_modules(GlobalShortcut-qml Quick Gui)
9
9
10add_unity8_plugin(GlobalShortcut 1.0 GlobalShortcut TARGETS GlobalShortcut-qml)
10add_unity8_plugin(GlobalShortcut 1.0 GlobalShortcut TARGETS GlobalShortcut-qml)
plugins/GlobalShortcut/globalshortcut.cpp−3
@@ -58,9 +58,6 @@ void GlobalShortcut::setActive(bool active)
58
58
59void GlobalShortcut::componentComplete()
59void GlobalShortcut::componentComplete()
60{
60{
61− if (this->window()) {
62− QMetaObject::invokeMethod(this, "setupFilterOnWindow", Q_ARG(QQuickWindow*, this->window()));
63− }
64 connect(this, &QQuickItem::windowChanged, this, &GlobalShortcut::setupFilterOnWindow);
61 connect(this, &QQuickItem::windowChanged, this, &GlobalShortcut::setupFilterOnWindow);
65}
62}
66
63
plugins/Greeter/Unity/Launcher/CMakeLists.txt+3−1
@@ -1,3 +1,4 @@
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2
3
3add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
@@ -29,7 +30,8 @@ add_library(UnityLauncherAS-qml MODULE
29target_link_libraries(UnityLauncherAS-qml
30target_link_libraries(UnityLauncherAS-qml
30 unity8-private
31 unity8-private
31 ${GSETTINGS_QT_LDFLAGS}
32 ${GSETTINGS_QT_LDFLAGS}
32− Qt5::DBus Qt5::Qml Qt5::Gui
33 )
33 )
34
34
35+qt5_use_modules(UnityLauncherAS-qml DBus Qml Gui)
36+
35add_unity8_greeter_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncherAS-qml)
37add_unity8_greeter_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncherAS-qml)
plugins/Greeter/Unity/Launcher/launcheritem.cpp−6
@@ -89,12 +89,6 @@ void LauncherItem::setKeywords(const QStringList &keywords)
89 }
89 }
90}
90}
91
91
92−uint LauncherItem::popularity() const
93−{
94− // Not exposing usage order in greeter session at this point.
95− return 0;
96−}
97−
98bool LauncherItem::pinned() const
92bool LauncherItem::pinned() const
99{
93{
100 return m_pinned;
94 return m_pinned;
plugins/Greeter/Unity/Launcher/launcheritem.h−1
@@ -35,7 +35,6 @@ public:
35 QString name() const override;
35 QString name() const override;
36 QString icon() const override;
36 QString icon() const override;
37 QStringList keywords() const override;
37 QStringList keywords() const override;
38− uint popularity() const override;
39 bool pinned() const override;
38 bool pinned() const override;
40 bool running() const override;
39 bool running() const override;
41 bool recent() const override;
40 bool recent() const override;
plugins/Greeter/Unity/Launcher/quicklistmodel.cpp−2
@@ -65,8 +65,6 @@ QVariant QuickListModel::data(const QModelIndex &index, int role) const
65 return m_list.at(index.row()).icon();
65 return m_list.at(index.row()).icon();
66 case RoleClickable:
66 case RoleClickable:
67 return m_list.at(index.row()).clickable();
67 return m_list.at(index.row()).clickable();
68− case RoleIsPrivate:
69− return false; // The greeter plugin would just not add any private entries
70 }
68 }
71 return QVariant();
69 return QVariant();
72}
70}
plugins/ImageCache/CMakeLists.txtnew file+8
@@ -0,0 +1,8 @@
1+add_library(ImageCache-qml MODULE
2+ ImageCache.cpp
3+ plugin.cpp
4+ )
5+
6+qt5_use_modules(ImageCache-qml Gui Qml Quick)
7+
8+add_unity8_plugin(ImageCache 0.1 ImageCache TARGETS ImageCache-qml)
plugins/ImageCache/ImageCache.cppnew file+135
@@ -0,0 +1,135 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QDateTime>
18+#include <QDebug>
19+#include <QDir>
20+#include <QUrl>
21+#include <QUrlQuery>
22+
23+#include "ImageCache.h"
24+
25+ImageCache::ImageCache()
26+ : QQuickImageProvider(QQmlImageProviderBase::Image,
27+ QQmlImageProviderBase::ForceAsynchronousImageLoading)
28+{
29+}
30+
31+QString ImageCache::imageCacheRoot()
32+{
33+ QString xdgCache(qgetenv("XDG_CACHE_HOME"));
34+ if (xdgCache.isEmpty()) {
35+ xdgCache = QDir::homePath() + QStringLiteral("/.cache");
36+ }
37+
38+ return QDir::cleanPath(xdgCache) + QStringLiteral("/unity8/imagecache");
39+}
40+
41+QFileInfo ImageCache::imagePath(const QUrl &image)
42+{
43+ QUrlQuery query(image);
44+
45+ auto name = query.queryItemValue(QStringLiteral("name"));
46+ if (name.isEmpty()) {
47+ name = QStringLiteral("/paths") + image.toLocalFile();
48+ } else {
49+ name = QStringLiteral("/names/") + name;
50+ }
51+
52+ return QFileInfo(imageCacheRoot() + name);
53+}
54+
55+bool ImageCache::needsUpdate(const QUrl &image, const QFileInfo &cachePath, const QSize &imageSize, const QSize &requestedSize, QSize &finalSize)
56+{
57+ if (!cachePath.exists())
58+ return true;
59+
60+ QFileInfo imageInfo(image.toLocalFile());
61+ if (imageInfo.lastModified() > cachePath.lastModified())
62+ return true;
63+
64+ QSize cacheSize(QImageReader(cachePath.filePath()).size());
65+ finalSize = calculateSize(imageSize, requestedSize);
66+ if (finalSize.isValid() && cacheSize != finalSize)
67+ return true;
68+
69+ return false;
70+}
71+
72+QSize ImageCache::calculateSize(const QSize &imageSize, const QSize &requestedSize)
73+{
74+ QSize finalSize(requestedSize);
75+
76+ if (finalSize.width() == 0) {
77+ finalSize.setWidth(imageSize.width() * (((double)finalSize.height()) / imageSize.height()));
78+ } else if (finalSize.height() == 0) {
79+ finalSize.setHeight(imageSize.height() * (((double)finalSize.width()) / imageSize.width()));
80+ }
81+
82+ return finalSize;
83+}
84+
85+QImage ImageCache::loadAndCacheImage(QImageReader &reader, const QFileInfo &cachePath, const QSize &finalSize)
86+{
87+ reader.setQuality(100);
88+ reader.setScaledSize(finalSize);
89+ auto format = reader.format(); // can't get this after reading
90+
91+ QImage loadedImage(reader.read());
92+ if (loadedImage.isNull()) {
93+ qWarning() << "ImageCache could not read image" << reader.fileName() << ":" << reader.errorString();
94+ return QImage();
95+ }
96+
97+ cachePath.dir().mkpath(QStringLiteral("."));
98+ loadedImage.save(cachePath.filePath(), format, 100);
99+
100+ return loadedImage;
101+}
102+
103+QImage ImageCache::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
104+{
105+ QUrl image(id);
106+ QImageReader imageReader(image.toLocalFile());
107+ QSize imageSize(imageReader.size());
108+ QImage result;
109+
110+ // Early exit here, with no sourceSize, scaled-up sourceSize, or bad source image
111+ if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) ||
112+ imageSize.isEmpty() ||
113+ requestedSize.height() >= imageSize.height() ||
114+ requestedSize.width() >= imageSize.width()) {
115+ // We're only interested in scaling down, not up.
116+ result = imageReader.read();
117+ *size = result.size();
118+ return result;
119+ }
120+
121+ auto cachePath = imagePath(image);
122+ QSize finalSize;
123+
124+ if (needsUpdate(image, cachePath, imageSize, requestedSize, finalSize)) {
125+ if (finalSize.isEmpty()) {
126+ finalSize = calculateSize(imageSize, requestedSize);
127+ }
128+ result = loadAndCacheImage(imageReader, cachePath, finalSize);
129+ } else {
130+ result = QImage(cachePath.filePath());
131+ }
132+
133+ *size = result.size();
134+ return result;
135+}
plugins/ImageCache/ImageCache.hnew file+53
@@ -0,0 +1,53 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#pragma once
18+
19+#include <QFileInfo>
20+#include <QImageReader>
21+#include <QQuickImageProvider>
22+#include <QSize>
23+
24+/**
25+ * This class accepts an id formulated like a URL. So you'd use something like:
26+ *
27+ * Image {
28+ * source: "image://unity8imagecache/file:///usr/share/..."
29+ * }
30+ *
31+ * Right now, we only support file:/// URLs. We do accept some flags though:
32+ *
33+ * ?name=NAME
34+ * - This will use NAME as the cache lookup key instead of the provided URL.
35+ *
36+ * We don't do any cleaning of old cached files yet. So you may want to always
37+ * provide a name to avoid leaving lots of files around.
38+ */
39+
40+class ImageCache: public QQuickImageProvider
41+{
42+public:
43+ ImageCache();
44+
45+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
46+
47+private:
48+ static QString imageCacheRoot();
49+ static QFileInfo imagePath(const QUrl &image);
50+ static bool needsUpdate(const QUrl &image, const QFileInfo &cachePath, const QSize &imageSize, const QSize &requestedSize, QSize &finalSize);
51+ static QSize calculateSize(const QSize &imageSize, const QSize &requestedSize);
52+ static QImage loadAndCacheImage(QImageReader &reader, const QFileInfo &cachePath, const QSize &finalSize);
53+};
plugins/ImageCache/plugin.cppnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QQmlEngine>
18+
19+#include "ImageCache.h"
20+#include "plugin.h"
21+
22+#include <QtQml>
23+
24+void ImageCachePlugin::registerTypes(const char *uri)
25+{
26+ Q_ASSERT(uri == QLatin1String("ImageCache"));
27+
28+ qmlRegisterTypeNotAvailable(uri, 0, 1, "__ImageCacheIgnoreMe",
29+ QStringLiteral("Ignore this: QML plugins must contain at least one type"));
30+}
31+
32+void ImageCachePlugin::initializeEngine(QQmlEngine* engine, const char* uri)
33+{
34+ Q_ASSERT(uri == QLatin1String("ImageCache"));
35+
36+ QQmlExtensionPlugin::initializeEngine(engine, uri);
37+
38+ engine->addImageProvider("unity8imagecache", new ImageCache);
39+}
plugins/ImageCache/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#pragma once
18+
19+#include <QQmlExtensionPlugin>
20+
21+class QQmlEngine;
22+
23+class ImageCachePlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char* uri) override;
30+ void initializeEngine(QQmlEngine* engine, const char* uri) override;
31+};
plugins/ImageCache/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module ImageCache
2+plugin ImageCache-qml
plugins/LightDM/CMakeLists.txt+1−1
@@ -7,6 +7,7 @@ include_directories(
7 ${CMAKE_CURRENT_SOURCE_DIR}
7 ${CMAKE_CURRENT_SOURCE_DIR}
8 ${CMAKE_CURRENT_BINARY_DIR}
8 ${CMAKE_CURRENT_BINARY_DIR}
9 ${CMAKE_SOURCE_DIR}/plugins/Utils
9 ${CMAKE_SOURCE_DIR}/plugins/Utils
10+ ${CMAKE_BINARY_DIR}/tests/mocks/LightDM/IntegratedLightDM
10 ${libunity8-private_SOURCE_DIR}
11 ${libunity8-private_SOURCE_DIR}
11 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
12 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
12)
13)
@@ -17,7 +18,6 @@ set(QMLPLUGIN_SRC
17 DBusGreeterList.cpp
18 DBusGreeterList.cpp
18 Greeter.cpp
19 Greeter.cpp
19 plugin.cpp
20 plugin.cpp
20− PromptsModel.cpp
21 SessionsModel.cpp
21 SessionsModel.cpp
22 UsersModel.cpp
22 UsersModel.cpp
23 )
23 )
plugins/LightDM/DBusGreeterList.cpp+3−3
@@ -43,10 +43,10 @@ bool DBusGreeterList::entryIsLocked() const
43 return !m_greeter->promptless();
43 return !m_greeter->promptless();
44}
44}
45
45
46−void DBusGreeterList::authenticationUserChangedHandler()
46+void DBusGreeterList::authenticationUserChangedHandler(const QString &user)
47{
47{
48− notifyPropertyChanged(QStringLiteral("ActiveEntry"), m_greeter->authenticationUser());
48+ notifyPropertyChanged(QStringLiteral("ActiveEntry"), user);
49− Q_EMIT EntrySelected(m_greeter->authenticationUser());
49+ Q_EMIT EntrySelected(user);
50}
50}
51
51
52void DBusGreeterList::promptlessChangedHandler()
52void DBusGreeterList::promptlessChangedHandler()
plugins/LightDM/DBusGreeterList.h+1−1
@@ -47,7 +47,7 @@ Q_SIGNALS:
47 void entryIsLockedChanged();
47 void entryIsLockedChanged();
48
48
49private Q_SLOTS:
49private Q_SLOTS:
50− void authenticationUserChangedHandler();
50+ void authenticationUserChangedHandler(const QString &user);
51 void promptlessChangedHandler();
51 void promptlessChangedHandler();
52
52
53private:
53private:
plugins/LightDM/FullLightDM/CMakeLists.txt+1−1
@@ -26,7 +26,7 @@ target_link_libraries(FullLightDM-qml
26 unity8-private
26 unity8-private
27 ${LIBLIGHTDM_LDFLAGS}
27 ${LIBLIGHTDM_LDFLAGS}
28 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
28 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
29− Qt5::DBus Qt5::Gui Qt5::Qml
30 )
29 )
31
30
31+qt5_use_modules(FullLightDM-qml DBus Gui Qml)
32add_unity8_plugin(FullLightDM 0.1 LightDM/FullLightDM TARGETS FullLightDM-qml)
32add_unity8_plugin(FullLightDM 0.1 LightDM/FullLightDM TARGETS FullLightDM-qml)
plugins/LightDM/Greeter.cpp+14−144
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013-2017 Canonical, Ltd.
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -17,16 +17,12 @@
17
17
18#include "Greeter.h"
18#include "Greeter.h"
19#include "GreeterPrivate.h"
19#include "GreeterPrivate.h"
20−#include <QCoreApplication>
21#include <libintl.h>
20#include <libintl.h>
22
21
23−static Greeter *singleton = nullptr;
24−
25GreeterPrivate::GreeterPrivate(Greeter* parent)
22GreeterPrivate::GreeterPrivate(Greeter* parent)
26 : m_greeter(new QLightDM::Greeter(parent)),
23 : m_greeter(new QLightDM::Greeter(parent)),
27 m_active(false),
24 m_active(false),
28− responded(false),
25+ wasPrompted(false),
29− everResponded(false),
30 promptless(false),
26 promptless(false),
31 q_ptr(parent)
27 q_ptr(parent)
32{
28{
@@ -45,32 +41,9 @@ Greeter::Greeter(QObject* parent)
45 connect(d->m_greeter, &QLightDM::Greeter::authenticationComplete,
41 connect(d->m_greeter, &QLightDM::Greeter::authenticationComplete,
46 this, &Greeter::authenticationCompleteFilter);
42 this, &Greeter::authenticationCompleteFilter);
47
43
48− // Don't get stuck waiting for PAM as we shut down.
49− connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
50− d->m_greeter, &QLightDM::Greeter::cancelAuthentication);
51−
52 d->m_greeter->connectSync();
44 d->m_greeter->connectSync();
53}
45}
54
46
55−Greeter::~Greeter()
56−{
57− singleton = nullptr;
58−}
59−
60−Greeter *Greeter::instance()
61−{
62− if (!singleton) {
63− singleton = new Greeter;
64− }
65− return singleton;
66−}
67−
68−PromptsModel *Greeter::promptsModel()
69−{
70− Q_D(Greeter);
71− return &d->prompts;
72−}
73−
74bool Greeter::isActive() const
47bool Greeter::isActive() const
75{
48{
76 Q_D(const Greeter);
49 Q_D(const Greeter);
@@ -95,16 +68,7 @@ bool Greeter::isAuthenticated() const
95QString Greeter::authenticationUser() const
68QString Greeter::authenticationUser() const
96{
69{
97 Q_D(const Greeter);
70 Q_D(const Greeter);
98− return d->cachedAuthUser;
99−}
100−
101−void Greeter::checkAuthenticationUser()
102−{
103− Q_D(Greeter);
104− if (d->cachedAuthUser != d->m_greeter->authenticationUser()) {
105− d->cachedAuthUser = d->m_greeter->authenticationUser();
71+ return d->m_greeter->authenticationUser();
106− Q_EMIT authenticationUserChanged();
107− }
108}
72}
109
73
110QString Greeter::defaultSessionHint() const
74QString Greeter::defaultSessionHint() const
@@ -122,65 +86,26 @@ bool Greeter::promptless() const
122QString Greeter::selectUser() const
86QString Greeter::selectUser() const
123{
87{
124 Q_D(const Greeter);
88 Q_D(const Greeter);
125− if (hasGuestAccount() && d->m_greeter->selectGuestHint()) {
126− return QStringLiteral("*guest");
127− } else {
128− return d->m_greeter->selectUserHint();
89+ return d->m_greeter->selectUserHint();
129− }
130−}
131−
132−bool Greeter::hasGuestAccount() const
133−{
134− Q_D(const Greeter);
135− return d->m_greeter->hasGuestAccountHint();
136−}
137−
138−bool Greeter::showManualLoginHint() const
139−{
140− Q_D(const Greeter);
141− return d->m_greeter->showManualLoginHint();
142−}
143−
144−bool Greeter::hideUsersHint() const
145−{
146− Q_D(const Greeter);
147− return d->m_greeter->hideUsersHint();
148}
90}
149
91
150void Greeter::authenticate(const QString &username)
92void Greeter::authenticate(const QString &username)
151{
93{
152 Q_D(Greeter);
94 Q_D(Greeter);
153− d->prompts.clear();
95+ d->wasPrompted = false;
154− d->responded = false;
155− d->everResponded = false;
156 if (d->promptless) {
96 if (d->promptless) {
157 d->promptless = false;
97 d->promptless = false;
158 Q_EMIT promptlessChanged();
98 Q_EMIT promptlessChanged();
159 }
99 }
160
100
161− if (authenticationUser() == username) {
162− d->prompts = d->leftovers;
163− }
164− d->leftovers.clear();
165−
166− if (username == QStringLiteral("*guest")) {
167− d->m_greeter->authenticateAsGuest();
168− } else if (username == QStringLiteral("*other")) {
169− d->m_greeter->authenticate(nullptr);
101+ d->m_greeter->authenticate(username);
170− } else {
171− d->m_greeter->authenticate(username);
172− }
173−
174− Q_EMIT authenticationStarted();
175 Q_EMIT isAuthenticatedChanged();
102 Q_EMIT isAuthenticatedChanged();
176− checkAuthenticationUser();
103+ Q_EMIT authenticationUserChanged(username);
177}
104}
178
105
179void Greeter::respond(const QString &response)
106void Greeter::respond(const QString &response)
180{
107{
181 Q_D(Greeter);
108 Q_D(Greeter);
182− d->responded = true;
183− d->everResponded = true;
184 d->m_greeter->respond(response);
109 d->m_greeter->respond(response);
185}
110}
186
111
@@ -193,87 +118,32 @@ bool Greeter::startSessionSync(const QString &session)
193void Greeter::showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type)
118void Greeter::showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type)
194{
119{
195 Q_D(Greeter);
120 Q_D(Greeter);
196−
121+ d->wasPrompted = true;
197− checkAuthenticationUser(); // may have changed in liblightdm
198
122
199 bool isDefaultPrompt = (text == dgettext("Linux-PAM", "Password: "));
123 bool isDefaultPrompt = (text == dgettext("Linux-PAM", "Password: "));
200− bool isSecret = type == QLightDM::Greeter::PromptTypeSecret;
201−
202− QString trimmedText;
203− if (!isDefaultPrompt)
204− trimmedText = text.trimmed();
205
124
206 // Strip prompt of any colons at the end
125 // Strip prompt of any colons at the end
126+ QString trimmedText = text.trimmed();
207 if (trimmedText.endsWith(':') || trimmedText.endsWith(QStringLiteral(":"))) {
127 if (trimmedText.endsWith(':') || trimmedText.endsWith(QStringLiteral(":"))) {
208 trimmedText.chop(1);
128 trimmedText.chop(1);
209 }
129 }
210
130
211− if (trimmedText == "login") {
131+ Q_EMIT showPrompt(trimmedText, type == QLightDM::Greeter::PromptTypeSecret, isDefaultPrompt);
212− // 'login' is provided untranslated by LightDM when asking for a manual
213− // login username.
214− trimmedText = gettext("Username");
215− }
216−
217− if (d->responded) {
218− d->prompts.clear();
219− d->responded = false;
220− }
221−
222− d->prompts.append(trimmedText, isSecret ? PromptsModel::Secret : PromptsModel::Question);
223}
132}
224
133
225void Greeter::showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type)
134void Greeter::showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type)
226{
135{
227− Q_D(Greeter);
228−
229− checkAuthenticationUser(); // may have changed in liblightdm
230−
231− bool isError = type == QLightDM::Greeter::MessageTypeError;
136+ Q_EMIT showMessage(text, type == QLightDM::Greeter::MessageTypeError);
232−
233− if (d->responded) {
234− d->prompts.clear();
235− d->responded = false;
236− }
237− d->prompts.append(text, isError? PromptsModel::Error : PromptsModel::Message);
238}
137}
239
138
240void Greeter::authenticationCompleteFilter()
139void Greeter::authenticationCompleteFilter()
241{
140{
242 Q_D(Greeter);
141 Q_D(Greeter);
243−
142+ if (!d->wasPrompted) {
244− Q_EMIT isAuthenticatedChanged();
245−
246− bool automatic = !d->everResponded;
247− bool pamHasLeftoverMessages = !d->prompts.hasPrompt() && d->prompts.rowCount() > 0;
248−
249− if (isAuthenticated() && automatic) {
250 d->promptless = true;
143 d->promptless = true;
251 Q_EMIT promptlessChanged();
144 Q_EMIT promptlessChanged();
252 }
145 }
253
146
254− if (!isAuthenticated()) {
147+ Q_EMIT isAuthenticatedChanged();
255− if (pamHasLeftoverMessages) {
148+ Q_EMIT authenticationComplete();
256− d->leftovers = d->prompts; // Prefer PAM's messages
257− } else if (automatic) {
258− d->leftovers.append(gettext("Failed to authenticate"), PromptsModel::Error);
259− } else {
260− d->leftovers.append(gettext("Invalid password, please try again"), PromptsModel::Error);
261− }
262− } else if (pamHasLeftoverMessages) {
263− automatic = true; // treat this successful login as automatic, so user sees message
264− d->leftovers = d->prompts;
265− }
266−
267− if (automatic) {
268− d->prompts = d->leftovers; // OK, we'll just use these now
269− d->leftovers.clear();
270− d->prompts.append(isAuthenticated() ? gettext("Log In") : gettext("Retry"),
271− PromptsModel::Button);
272− }
273−
274− if (isAuthenticated()) {
275− Q_EMIT loginSuccess(automatic);
276− } else {
277− Q_EMIT loginError(automatic);
278− }
279}
149}
plugins/LightDM/Greeter.h+10−17
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012-2016 Canonical, Ltd.
2+ * Copyright (C) 2012,2013,2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -21,13 +21,13 @@
21 such edits in the future, and by inserting ourselves here, we have more
21 such edits in the future, and by inserting ourselves here, we have more
22 control. */
22 control. */
23
23
24−#pragma once
24+#ifndef UNITY_GREETER_H
25+#define UNITY_GREETER_H
25
26
26#include <QLightDM/Greeter>
27#include <QLightDM/Greeter>
27#include <QtCore/QObject>
28#include <QtCore/QObject>
28
29
29class GreeterPrivate;
30class GreeterPrivate;
30−class PromptsModel;
31
31
32class Greeter : public QObject
32class Greeter : public QObject
33{
33{
@@ -41,8 +41,7 @@ class Greeter : public QObject
41 Q_PROPERTY(QString selectUser READ selectUser CONSTANT)
41 Q_PROPERTY(QString selectUser READ selectUser CONSTANT)
42
42
43public:
43public:
44− static Greeter *instance();
44+ explicit Greeter(QObject* parent=0);
45− virtual ~Greeter();
46
45
47 bool isActive() const;
46 bool isActive() const;
48 bool isAuthenticated() const;
47 bool isAuthenticated() const;
@@ -50,11 +49,6 @@ public:
50 QString defaultSessionHint() const;
49 QString defaultSessionHint() const;
51 bool promptless() const;
50 bool promptless() const;
52 QString selectUser() const;
51 QString selectUser() const;
53− bool hasGuestAccount() const;
54− bool showManualLoginHint() const;
55− bool hideUsersHint() const;
56−
57− PromptsModel *promptsModel();
58
52
59public Q_SLOTS:
53public Q_SLOTS:
60 void authenticate(const QString &username=QString());
54 void authenticate(const QString &username=QString());
@@ -63,23 +57,21 @@ public Q_SLOTS:
63 void setIsActive(bool isActive);
57 void setIsActive(bool isActive);
64
58
65Q_SIGNALS:
59Q_SIGNALS:
60+ void showMessage(const QString &text, bool isError);
61+ void showPrompt(const QString &text, bool isSecret, bool isDefaultPrompt);
62+ void authenticationComplete();
66− void authenticationUserChanged();
63+ void authenticationUserChanged(const QString &user);
67 void isActiveChanged();
64 void isActiveChanged();
68 void isAuthenticatedChanged();
65 void isAuthenticatedChanged();
69 void promptlessChanged();
66 void promptlessChanged();
70 void showGreeter();
67 void showGreeter();
71 void hideGreeter();
68 void hideGreeter();
72− void loginError(bool automatic);
73− void loginSuccess(bool automatic);
74− void authenticationStarted(); // useful for testing
75
69
76 // This signal is emitted by external agents like indicators, and the UI
70 // This signal is emitted by external agents like indicators, and the UI
77 // should switch to this user if possible.
71 // should switch to this user if possible.
78 void requestAuthenticationUser(const QString &user);
72 void requestAuthenticationUser(const QString &user);
79
73
80protected:
74protected:
81− explicit Greeter(QObject* parent=0);
82−
83 GreeterPrivate * const d_ptr;
75 GreeterPrivate * const d_ptr;
84
76
85 Q_DECLARE_PRIVATE(Greeter)
77 Q_DECLARE_PRIVATE(Greeter)
@@ -88,5 +80,6 @@ private Q_SLOTS:
88 void showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type);
80 void showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type);
89 void showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type);
81 void showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type);
90 void authenticationCompleteFilter();
82 void authenticationCompleteFilter();
91− void checkAuthenticationUser();
92};
83};
84+
85+#endif
plugins/LightDM/GreeterPrivate.h+7−13
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015-2017 Canonical, Ltd.
2+ * Copyright (C) 2014 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -14,14 +14,10 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#pragma once
17+#ifndef UNITY_GREETER_PRIVATE_H
18+#define UNITY_GREETER_PRIVATE_H
18
19
19−#include "PromptsModel.h"
20−#include <QObject>
21−
22−namespace QLightDM {
20+#include <QLightDM/Greeter>
23− class Greeter;
24−}
25
21
26class GreeterPrivate
22class GreeterPrivate
27{
23{
@@ -30,12 +26,8 @@ public:
30
26
31 QLightDM::Greeter *m_greeter;
27 QLightDM::Greeter *m_greeter;
32 bool m_active;
28 bool m_active;
33− PromptsModel prompts;
29+ bool wasPrompted;
34− PromptsModel leftovers; // prompts to show during next auth for same user
35− bool responded;
36− bool everResponded;
37 bool promptless;
30 bool promptless;
38− QString cachedAuthUser;
39
31
40protected:
32protected:
41 Greeter * const q_ptr;
33 Greeter * const q_ptr;
@@ -43,3 +35,5 @@ protected:
43private:
35private:
44 Q_DECLARE_PUBLIC(Greeter)
36 Q_DECLARE_PUBLIC(Greeter)
45};
37};
38+
39+#endif // UNITY_GREETER_PRIVATE_H
plugins/LightDM/IntegratedLightDM/CMakeLists.txt+1−1
@@ -25,9 +25,9 @@ target_link_libraries(IntegratedLightDM-qml
25 integratedLightDM
25 integratedLightDM
26 unity8-private
26 unity8-private
27 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
27 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
28− Qt5::DBus Qt5::Gui Qt5::Qml
29 )
28 )
30
29
30+qt5_use_modules(IntegratedLightDM-qml DBus Gui Qml)
31add_unity8_plugin(IntegratedLightDM 0.1 LightDM/IntegratedLightDM TARGETS IntegratedLightDM-qml)
31add_unity8_plugin(IntegratedLightDM 0.1 LightDM/IntegratedLightDM TARGETS IntegratedLightDM-qml)
32
32
33add_subdirectory(liblightdm)
33add_subdirectory(liblightdm)
plugins/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt+4−3
@@ -26,21 +26,22 @@ target_link_libraries(integratedLightDM
26 ${GLIB_LIBRARIES}
26 ${GLIB_LIBRARIES}
27 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
27 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
28 -lpam
28 -lpam
29− Qt5::Concurrent Qt5::DBus Qt5::Gui
30)
29)
31target_link_libraries(integratedLightDMSession
30target_link_libraries(integratedLightDMSession
32 ${GLIB_LIBRARIES}
31 ${GLIB_LIBRARIES}
33 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
32 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
34 -lpam
33 -lpam
35− Qt5::Concurrent Qt5::DBus Qt5::Gui
36)
34)
37target_link_libraries(MockLightDM-demo-shared
35target_link_libraries(MockLightDM-demo-shared
38 ${GLIB_LIBRARIES}
36 ${GLIB_LIBRARIES}
39 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
37 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
40 -lpam
38 -lpam
41− Qt5::Concurrent Qt5::DBus Qt5::Gui
42)
39)
43
40
41+qt5_use_modules(integratedLightDM Concurrent DBus Gui)
42+qt5_use_modules(integratedLightDMSession Concurrent DBus Gui)
43+qt5_use_modules(MockLightDM-demo-shared Concurrent DBus Gui)
44+
44set_target_properties(integratedLightDM PROPERTIES
45set_target_properties(integratedLightDM PROPERTIES
45 COMPILE_FLAGS "-DSM_BUSNAME=systemBus -fPIC")
46 COMPILE_FLAGS "-DSM_BUSNAME=systemBus -fPIC")
46set_target_properties(integratedLightDMSession PROPERTIES
47set_target_properties(integratedLightDMSession PROPERTIES
plugins/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp+4−7
@@ -49,7 +49,7 @@ QString Greeter::authenticationUser() const
49
49
50bool Greeter::hasGuestAccountHint() const
50bool Greeter::hasGuestAccountHint() const
51{
51{
52− return false;
52+ return true;
53}
53}
54
54
55QString Greeter::getHint(const QString &name) const
55QString Greeter::getHint(const QString &name) const
@@ -70,12 +70,12 @@ bool Greeter::hideUsersHint() const
70
70
71bool Greeter::showManualLoginHint() const
71bool Greeter::showManualLoginHint() const
72{
72{
73− return false;
73+ return true;
74}
74}
75
75
76bool Greeter::showRemoteLoginHint() const
76bool Greeter::showRemoteLoginHint() const
77{
77{
78− return false;
78+ return true;
79}
79}
80
80
81QString Greeter::selectUserHint() const
81QString Greeter::selectUserHint() const
@@ -146,10 +146,7 @@ void Greeter::authenticateRemote(const QString &session, const QString &username
146}
146}
147
147
148void Greeter::cancelAuthentication()
148void Greeter::cancelAuthentication()
149−{
149+{}
150− Q_D(Greeter);
151− d->cancelAuthentication();
152−}
153
150
154void Greeter::setLanguage (const QString &language)
151void Greeter::setLanguage (const QString &language)
155{
152{
plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.cpp+22−27
@@ -206,28 +206,6 @@ public Q_SLOTS:
206 }
206 }
207 }
207 }
208
208
209− void cancelPam()
210− {
211− if (pamHandle != nullptr) {
212− QFuture<int> pamFuture = futureWatcher.future();
213− pam_handle *handle = pamHandle;
214− pamHandle = nullptr; // to disable normal finishPam() handling
215− pamFuture.cancel();
216−
217− // Note the empty loop, we just want to clear the futures queue.
218− // Any further prompts from the pam thread will be immediately
219− // responded to/dismissed in handlePrompt().
220− while (respond(QString()));
221−
222− // Now let signal/slot handling happen so the thread can finish
223− while (!pamFuture.isFinished()) {
224− QCoreApplication::processEvents();
225− }
226−
227− pam_end(handle, PAM_CONV_ERR);
228− }
229− }
230−
231Q_SIGNALS:
209Q_SIGNALS:
232 void showMessage(pam_handle *handle, QString text, QLightDM::Greeter::MessageType type);
210 void showMessage(pam_handle *handle, QString text, QLightDM::Greeter::MessageType type);
233 void showPrompt(pam_handle *handle, QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
211 void showPrompt(pam_handle *handle, QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
@@ -269,6 +247,28 @@ private Q_SLOTS:
269 }
247 }
270
248
271private:
249private:
250+ void cancelPam()
251+ {
252+ if (pamHandle != nullptr) {
253+ QFuture<int> pamFuture = futureWatcher.future();
254+ pam_handle *handle = pamHandle;
255+ pamHandle = nullptr; // to disable normal finishPam() handling
256+ pamFuture.cancel();
257+
258+ // Note the empty loop, we just want to clear the futures queue.
259+ // Any further prompts from the pam thread will be immediately
260+ // responded to/dismissed in handlePrompt().
261+ while (respond(QString()));
262+
263+ // Now let signal/slot handling happen so the thread can finish
264+ while (!pamFuture.isFinished()) {
265+ QCoreApplication::processEvents();
266+ }
267+
268+ pam_end(handle, PAM_CONV_ERR);
269+ }
270+ }
271+
272 Greeter *greeter;
272 Greeter *greeter;
273 GreeterPrivate *greeterPrivate;
273 GreeterPrivate *greeterPrivate;
274 pam_handle* pamHandle;
274 pam_handle* pamHandle;
@@ -299,11 +299,6 @@ void GreeterPrivate::handleRespond(const QString &response)
299 m_impl->respond(response);
299 m_impl->respond(response);
300}
300}
301
301
302−void GreeterPrivate::cancelAuthentication()
303−{
304− m_impl->cancelPam();
305−}
306−
307}
302}
308
303
309#include "GreeterPrivate.moc"
304#include "GreeterPrivate.moc"
plugins/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.h−1
@@ -38,7 +38,6 @@ public:
38
38
39 void handleAuthenticate();
39 void handleAuthenticate();
40 void handleRespond(const QString &response);
40 void handleRespond(const QString &response);
41− void cancelAuthentication();
42
41
43protected:
42protected:
44 GreeterImpl *m_impl; // if the backend needs more private data
43 GreeterImpl *m_impl; // if the backend needs more private data
plugins/LightDM/PromptsModel.cppdeleted−97
@@ -1,97 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− */
17−
18−#include "PromptsModel.h"
19−
20−PromptsModel::PromptsModel(QObject* parent)
21− : QAbstractListModel(parent)
22−{
23− m_roleNames[TypeRole] = "type";
24− m_roleNames[TextRole] = "text";
25−}
26−
27−PromptsModel& PromptsModel::operator=(const PromptsModel &other)
28−{
29− beginResetModel();
30− m_prompts = other.m_prompts;
31− endResetModel();
32− Q_EMIT countChanged();
33− return *this;
34−}
35−
36−int PromptsModel::rowCount(const QModelIndex &parent) const
37−{
38− if (parent.isValid())
39− return 0;
40−
41− return m_prompts.size();
42−}
43−
44−QVariant PromptsModel::data(const QModelIndex &index, int role) const
45−{
46− if (!index.isValid() || index.column() > 0 || index.row() >= m_prompts.size())
47− return QVariant();
48−
49− switch (role) {
50− case Qt::DisplayRole: // fallthrough
51− case TextRole: return m_prompts[index.row()].prompt;
52− case TypeRole: return m_prompts[index.row()].type;
53− default: return QVariant();
54− }
55−}
56−
57−QHash<int, QByteArray> PromptsModel::roleNames() const
58−{
59− return m_roleNames;
60−}
61−
62−void PromptsModel::prepend(const QString &text, PromptType type)
63−{
64− beginInsertRows(QModelIndex(), 0, 0);
65− m_prompts.prepend(PromptInfo{text, type});
66− endInsertRows();
67−
68− Q_EMIT countChanged();
69−}
70−
71−void PromptsModel::append(const QString &text, PromptType type)
72−{
73− beginInsertRows(QModelIndex(), m_prompts.size(), m_prompts.size());
74− m_prompts.append(PromptInfo{text, type});
75− endInsertRows();
76−
77− Q_EMIT countChanged();
78−}
79−
80−void PromptsModel::clear()
81−{
82− beginResetModel();
83− m_prompts.clear();
84− endResetModel();
85−
86− Q_EMIT countChanged();
87−}
88−
89−bool PromptsModel::hasPrompt() const
90−{
91− Q_FOREACH(const PromptInfo &info, m_prompts) {
92− if (info.type == PromptType::Secret || info.type == PromptType::Question) {
93− return true;
94− }
95− }
96− return false;
97−}
plugins/LightDM/PromptsModel.hdeleted−70
@@ -1,70 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− */
17−
18−#pragma once
19−
20−#include <QAbstractListModel>
21−
22−class PromptsModel : public QAbstractListModel
23−{
24− Q_OBJECT
25−
26− Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
27−
28−public:
29− enum PromptsModelRoles {
30− TypeRole = Qt::UserRole,
31− TextRole,
32− };
33− Q_ENUM(PromptsModelRoles)
34−
35− enum PromptType {
36− Message,
37− Error,
38− Secret,
39− Question,
40− Button,
41− };
42− Q_ENUM(PromptType)
43−
44− explicit PromptsModel(QObject* parent=0);
45−
46− PromptsModel& operator=(const PromptsModel &other);
47−
48− int rowCount(const QModelIndex &parent = QModelIndex()) const override;
49− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
50− QHash<int, QByteArray> roleNames() const override;
51−
52− Q_INVOKABLE void prepend(const QString &text, PromptType type);
53− Q_INVOKABLE void append(const QString &text, PromptType type);
54−
55− void clear();
56−
57− bool hasPrompt() const;
58−
59−Q_SIGNALS:
60− void countChanged();
61−
62−private:
63− struct PromptInfo {
64− QString prompt;
65− PromptType type;
66− };
67−
68− QList<PromptInfo> m_prompts;
69− QHash<int, QByteArray> m_roleNames;
70−};
plugins/LightDM/SessionsModel.cpp+2−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015-2016 Canonical, Ltd.
2+ * Copyright (C) 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -128,6 +128,7 @@ SessionsModel::SessionsModel(QObject* parent)
128 }
128 }
129
129
130 setModel(m_model);
130 setModel(m_model);
131+ setSourceModel(m_model);
131 setSortCaseSensitivity(Qt::CaseInsensitive);
132 setSortCaseSensitivity(Qt::CaseInsensitive);
132 setSortLocaleAware(true);
133 setSortLocaleAware(true);
133 setSortRole(Qt::DisplayRole);
134 setSortRole(Qt::DisplayRole);
plugins/LightDM/SessionsModel.h+5−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015-2016 Canonical, Ltd.
2+ * Copyright (C) 2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -15,7 +15,8 @@
15 *
15 *
16 */
16 */
17
17
18−#pragma once
18+#ifndef UNITY_SESSIONSMODEL_H
19+#define UNITY_SESSIONSMODEL_H
19
20
20#include <unitysortfilterproxymodelqml.h>
21#include <unitysortfilterproxymodelqml.h>
21#include <QLightDM/SessionsModel>
22#include <QLightDM/SessionsModel>
@@ -29,7 +30,6 @@ class SessionsModel : public UnitySortFilterProxyModelQML
29
30
30 Q_PROPERTY(QList<QUrl> iconSearchDirectories READ iconSearchDirectories
31 Q_PROPERTY(QList<QUrl> iconSearchDirectories READ iconSearchDirectories
31 WRITE setIconSearchDirectories NOTIFY iconSearchDirectoriesChanged)
32 WRITE setIconSearchDirectories NOTIFY iconSearchDirectoriesChanged)
32−
33Q_SIGNALS:
33Q_SIGNALS:
34 void iconSearchDirectoriesChanged();
34 void iconSearchDirectoriesChanged();
35
35
@@ -54,7 +54,6 @@ public:
54 Q_INVOKABLE QUrl iconUrl(const QString sessionName) const;
54 Q_INVOKABLE QUrl iconUrl(const QString sessionName) const;
55
55
56 void setIconSearchDirectories(const QList<QUrl> searchDirectories);
56 void setIconSearchDirectories(const QList<QUrl> searchDirectories);
57−
58private:
57private:
59 QLightDM::SessionsModel* m_model;
58 QLightDM::SessionsModel* m_model;
60 QHash<int, QByteArray> m_roleNames;
59 QHash<int, QByteArray> m_roleNames;
@@ -64,3 +63,5 @@ private:
64 QUrl("/usr/share/unity-greeter/")};
63 QUrl("/usr/share/unity-greeter/")};
65
64
66};
65};
66+
67+#endif // UNITY_SESSIONSMODEL_H
plugins/LightDM/UsersModel.cpp+9−176
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2015-2016 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -12,22 +12,20 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
15 */
17 */
16
18
17−#include "Greeter.h"
18#include "UsersModel.h"
19#include "UsersModel.h"
19−#include <QIdentityProxyModel>
20#include <QLightDM/UsersModel>
20#include <QLightDM/UsersModel>
21−
21+#include <QtCore/QSortFilterProxyModel>
22−#include <libintl.h>
23
22
24// First, we define an internal class that wraps LightDM's UsersModel. This
23// First, we define an internal class that wraps LightDM's UsersModel. This
25// class will modify some of the data coming from LightDM. For example, we
24// class will modify some of the data coming from LightDM. For example, we
26−// modify any empty Real Names into just normal Names. We also add optional
25+// modify any empty Real Names into just normal Names.
27−// rows, depending on configuration.
28// (We can't modify the data directly in UsersModel below because it won't sort
26// (We can't modify the data directly in UsersModel below because it won't sort
29// using the modified data.)
27// using the modified data.)
30−class MangleModel : public QIdentityProxyModel
28+class MangleModel : public QSortFilterProxyModel
31{
29{
32 Q_OBJECT
30 Q_OBJECT
33
31
@@ -35,177 +33,29 @@ public:
35 explicit MangleModel(QObject* parent=0);
33 explicit MangleModel(QObject* parent=0);
36
34
37 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
35 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
38− int rowCount(const QModelIndex &parent = QModelIndex()) const override;
39− QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
40−
41−private:
42− struct CustomRow {
43− QString name;
44− QString realName;
45− };
46−
47− int sourceRowCount() const;
48−
49− void updateGuestRow();
50− void updateManualRow();
51− void updateCustomRows();
52−
53− void addCustomRow(const CustomRow &newRow);
54− void removeCustomRow(const QString &rowName);
55−
56− QList<CustomRow> m_customRows;
57− bool m_updatingCustomRows;
58};
36};
59
37
60MangleModel::MangleModel(QObject* parent)
38MangleModel::MangleModel(QObject* parent)
61− : QIdentityProxyModel(parent)
39+ : QSortFilterProxyModel(parent)
62− , m_updatingCustomRows(false)
63{
40{
64 setSourceModel(new QLightDM::UsersModel(this));
41 setSourceModel(new QLightDM::UsersModel(this));
65−
66− updateCustomRows();
67−
68− // Would be nice if there were a rowCountChanged signal in the base class.
69− // We redo all custom rows on any row count change, because (A) some of
70− // custom rows (manual login) use row count information and (B) when
71− // testing, we use a modelReset signal as a way to indicate that a custom
72− // row has been toggled off or on.
73− connect(this, &QIdentityProxyModel::modelReset,
74− this, &MangleModel::updateCustomRows);
75− connect(this, &QIdentityProxyModel::rowsInserted,
76− this, &MangleModel::updateCustomRows);
77− connect(this, &QIdentityProxyModel::rowsRemoved,
78− this, &MangleModel::updateCustomRows);
79}
42}
80
43
81QVariant MangleModel::data(const QModelIndex &index, int role) const
44QVariant MangleModel::data(const QModelIndex &index, int role) const
82{
45{
83− QVariant variantData;
46+ QVariant variantData = QSortFilterProxyModel::data(index, role);
84−
85− if (index.row() >= rowCount())
86− return QVariant();
87−
88− bool isCustomRow = index.row() >= sourceRowCount();
89− if (isCustomRow && index.column() == 0) {
90− int customIndex = index.row() - sourceRowCount();
91− if (role == QLightDM::UsersModel::NameRole) {
92− variantData = m_customRows[customIndex].name;
93− } else if (role == QLightDM::UsersModel::RealNameRole) {
94− variantData = m_customRows[customIndex].realName;
95− } else if (role == QLightDM::UsersModel::LoggedInRole) {
96− variantData = false;
97− } else if (role == QLightDM::UsersModel::SessionRole) {
98− variantData = Greeter::instance()->defaultSessionHint();
99− }
100− } else {
101− variantData = QIdentityProxyModel::data(index, role);
102− }
103
47
104 // If user's real name is empty, switch to unix name
48 // If user's real name is empty, switch to unix name
105 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
49 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
106− variantData = data(index, QLightDM::UsersModel::NameRole);
50+ variantData = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole);
107 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
51 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
108 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
52 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
109 variantData = stringData;
53 variantData = stringData;
110 }
54 }
111
55
112− // Workaround for liblightdm returning "" when a user has no default session
113− if (Q_UNLIKELY(role == QLightDM::UsersModel::SessionRole && variantData.toString().isEmpty())) {
114− variantData = Greeter::instance()->defaultSessionHint();
115− }
116−
117 return variantData;
56 return variantData;
118}
57}
119
58
120−void MangleModel::addCustomRow(const CustomRow &newRow)
121−{
122− for (int i = 0; i < m_customRows.size(); i++) {
123− if (m_customRows[i].name == newRow.name) {
124− return; // we don't have custom rows that change content yet
125− }
126− }
127−
128− beginInsertRows(QModelIndex(), rowCount(), rowCount());
129− m_customRows << newRow;
130− endInsertRows();
131−}
132−
133−void MangleModel::removeCustomRow(const QString &rowName)
134−{
135− for (int i = 0; i < m_customRows.size(); i++) {
136− if (m_customRows[i].name == rowName) {
137− int rowNum = sourceRowCount() + i;
138− beginRemoveRows(QModelIndex(), rowNum, rowNum);
139− m_customRows.removeAt(i);
140− endRemoveRows();
141− break;
142− }
143− }
144−}
145−
146−void MangleModel::updateManualRow()
147−{
148− bool hasAnotherEntry = sourceRowCount() > 0;
149− for (int i = 0; !hasAnotherEntry && i < m_customRows.size(); i++) {
150− if (m_customRows[i].name != QStringLiteral("*other")) {
151− hasAnotherEntry = true;
152− }
153− }
154−
155− // Show manual login if we are asked to OR if no other entry exists
156− if (Greeter::instance()->showManualLoginHint() || !hasAnotherEntry)
157− addCustomRow({QStringLiteral("*other"), gettext("Login")});
158− else
159− removeCustomRow(QStringLiteral("*other"));
160−}
161−
162−void MangleModel::updateGuestRow()
163−{
164− if (Greeter::instance()->hasGuestAccount())
165− addCustomRow({QStringLiteral("*guest"), gettext("Guest Session")});
166− else
167− removeCustomRow(QStringLiteral("*guest"));
168−}
169−
170−void MangleModel::updateCustomRows()
171−{
172− // We update when rowCount changes, but we also insert/remove rows here.
173− // So guard this function to avoid recursion.
174− if (m_updatingCustomRows)
175− return;
176−
177− m_updatingCustomRows = true;
178− updateGuestRow();
179− updateManualRow();
180− m_updatingCustomRows = false;
181−}
182−
183−int MangleModel::rowCount(const QModelIndex &parent) const
184−{
185− if (parent.isValid())
186− return 0;
187− else
188− return sourceRowCount() + m_customRows.size();
189−}
190−
191−int MangleModel::sourceRowCount() const
192−{
193− return Greeter::instance()->hideUsersHint() ? 0 : sourceModel()->rowCount();
194−}
195−
196−QModelIndex MangleModel::index(int row, int column, const QModelIndex &parent) const
197−{
198− if (row >= rowCount())
199− return QModelIndex();
200−
201− bool isCustomRow = row >= sourceRowCount();
202− if (isCustomRow && !parent.isValid()) {
203− return createIndex(row, column);
204− } else {
205− return QIdentityProxyModel::index(row, column, parent);
206− }
207−}
208−
209// **** Now we continue with actual UsersModel class ****
59// **** Now we continue with actual UsersModel class ****
210
60
211UsersModel::UsersModel(QObject* parent)
61UsersModel::UsersModel(QObject* parent)
@@ -218,21 +68,4 @@ UsersModel::UsersModel(QObject* parent)
218 sort(0);
68 sort(0);
219}
69}
220
70
221−bool UsersModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
222−{
223− auto leftName = source_left.data(QLightDM::UsersModel::NameRole);
224− auto rightName = source_right.data(QLightDM::UsersModel::NameRole);
225−
226− if (leftName == QStringLiteral("*guest"))
227− return false;
228− if (rightName == QStringLiteral("*guest"))
229− return true;
230− if (leftName == QStringLiteral("*other"))
231− return false;
232− if (rightName == QStringLiteral("*other"))
233− return true;
234−
235− return UnitySortFilterProxyModelQML::lessThan(source_left, source_right);
236−}
237−
238#include "UsersModel.moc"
71#include "UsersModel.moc"
plugins/LightDM/UsersModel.h+8−6
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012-2013,2015-2016 Canonical, Ltd.
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -12,16 +12,19 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
15 */
17 */
16
18
17/* This class is a really tiny filter around QLightDM::UsersModel. There are
19/* This class is a really tiny filter around QLightDM::UsersModel. There are
18 some operations that we want to edit a bit for the benefit of Qml.
20 some operations that we want to edit a bit for the benefit of Qml.
19 Specifically, we want to sort users according to realName. */
21 Specifically, we want to sort users according to realName. */
20
22
21−#pragma once
23+#ifndef UNITY_USERSMODEL_H
24+#define UNITY_USERSMODEL_H
22
25
23#include <unitysortfilterproxymodelqml.h>
26#include <unitysortfilterproxymodelqml.h>
24−#include <QObject>
27+#include <QtCore/QObject>
25
28
26class UsersModel : public UnitySortFilterProxyModelQML
29class UsersModel : public UnitySortFilterProxyModelQML
27{
30{
@@ -29,7 +32,6 @@ class UsersModel : public UnitySortFilterProxyModelQML
29
32
30public:
33public:
31 explicit UsersModel(QObject* parent=0);
34 explicit UsersModel(QObject* parent=0);
32−
33−protected:
34− bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
35};
35};
36+
37+#endif
plugins/LightDM/plugin.cpp+4−12
@@ -19,7 +19,6 @@
19#include "DBusGreeter.h"
19#include "DBusGreeter.h"
20#include "DBusGreeterList.h"
20#include "DBusGreeterList.h"
21#include "Greeter.h"
21#include "Greeter.h"
22−#include "PromptsModel.h"
23#include "SessionsModel.h"
22#include "SessionsModel.h"
24#include "UsersModel.h"
23#include "UsersModel.h"
25#include <libusermetricsoutput/ColorTheme.h>
24#include <libusermetricsoutput/ColorTheme.h>
@@ -33,24 +32,16 @@
33
32
34static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
33static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
35{
34{
35+ Q_UNUSED(engine)
36 Q_UNUSED(scriptEngine)
36 Q_UNUSED(scriptEngine)
37
37
38− Greeter *greeter = Greeter::instance();
38+ Greeter *greeter = new Greeter();
39 new DBusGreeter(greeter, QStringLiteral("/"));
39 new DBusGreeter(greeter, QStringLiteral("/"));
40 new DBusGreeterList(greeter, QStringLiteral("/list"));
40 new DBusGreeterList(greeter, QStringLiteral("/list"));
41
41
42− engine->setObjectOwnership(greeter, QQmlEngine::CppOwnership);
43−
44 return greeter;
42 return greeter;
45}
43}
46
44
47−static QObject *prompts_provider(QQmlEngine *engine, QJSEngine *)
48−{
49− auto model = Greeter::instance()->promptsModel();
50− engine->setObjectOwnership(model, QQmlEngine::CppOwnership);
51− return model;
52−}
53−
54static QObject *sessions_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
45static QObject *sessions_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
55{
46{
56 Q_UNUSED(engine)
47 Q_UNUSED(engine)
@@ -87,7 +78,8 @@ void PLUGIN_CLASSNAME::registerTypes(const char *uri)
87 #error No library defined in LightDM plugin
78 #error No library defined in LightDM plugin
88#endif
79#endif
89
80
90− qmlRegisterSingletonType<PromptsModel>(uri, 0, 1, "Prompts", prompts_provider);
81+ qRegisterMetaType<QLightDM::Greeter::MessageType>("QLightDM::Greeter::MessageType");
82+ qRegisterMetaType<QLightDM::Greeter::PromptType>("QLightDM::Greeter::PromptType");
91
83
92 qmlRegisterSingletonType<SessionsModel>(uri, 0, 1, "Sessions", sessions_provider);
84 qmlRegisterSingletonType<SessionsModel>(uri, 0, 1, "Sessions", sessions_provider);
93 qmlRegisterUncreatableType<QLightDM::SessionsModel>(uri, 0, 1, "SessionRoles", QStringLiteral("Type is not instantiable"));
85 qmlRegisterUncreatableType<QLightDM::SessionsModel>(uri, 0, 1, "SessionRoles", QStringLiteral("Type is not instantiable"));
plugins/Lights/CMakeLists.txt+2−8
@@ -1,6 +1,5 @@
1pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers)
1pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers)
2pkg_check_modules(ANDROID_HARDWARE REQUIRED libhardware)
2pkg_check_modules(ANDROID_HARDWARE REQUIRED libhardware)
3−pkg_check_modules(ANDROID_PROPERTIES REQUIRED libandroid-properties)
4
3
5include_directories(
4include_directories(
6 SYSTEM
5 SYSTEM
@@ -10,14 +9,9 @@ include_directories(
10add_library(Lights-qml MODULE
9add_library(Lights-qml MODULE
11 plugin.cpp
10 plugin.cpp
12 Lights.cpp
11 Lights.cpp
13− LegacyLights.cpp
14− HfdLights.cpp
15 )
12 )
16
13
17−target_link_libraries(Lights-qml
14+qt5_use_modules(Lights-qml Qml Gui)
18− Qt5::Qml Qt5::Gui Qt5::DBus
19− ${ANDROID_HARDWARE_LIBRARIES}
15+target_link_libraries(Lights-qml ${ANDROID_HARDWARE_LIBRARIES})
20− ${ANDROID_PROPERTIES_LIBRARIES}
21− )
22
16
23add_unity8_plugin(Lights 0.1 Lights TARGETS Lights-qml)
17add_unity8_plugin(Lights 0.1 Lights TARGETS Lights-qml)
plugins/Lights/HfdLights.cppdeleted−62
@@ -1,62 +0,0 @@
1−/*
2− * Copyright (C) 2021 UBports Foundation.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Florian Leeber <florian@ubports.com>
17− */
18−
19−#include "HfdLights.h"
20−#include <QtCore/QDebug>
21−#include <QDBusArgument>
22−#include <QDBusConnection>
23−#include <iostream>
24−
25−#define HFD_SERVICE_NAME "com.lomiri.hfd"
26−#define HFD_SERVICE_PATH "/com/lomiri/hfd"
27−#define HFD_SERVICE_INTERFACE "com.lomiri.hfd.Leds"
28−
29−HfdLights::HfdLights(QObject* parent)
30− : Lights(parent)
31−{
32− m_hfdInterface = new QDBusInterface(
33− QStringLiteral(HFD_SERVICE_NAME),
34− QStringLiteral(HFD_SERVICE_PATH),
35− QStringLiteral(HFD_SERVICE_INTERFACE),
36− QDBusConnection::systemBus(),
37− this
38− );
39−}
40−
41−bool HfdLights::init()
42−{
43− // hfd does not need any initalization to be used
44− return true;
45−}
46−
47−void HfdLights::turnOn()
48−{
49− m_hfdInterface->call(QStringLiteral("setState"), 0);
50− m_hfdInterface->call(QStringLiteral("setColor"), (quint32)m_color.rgba());
51− m_hfdInterface->call(QStringLiteral("setOnMs"), m_onMs);
52− m_hfdInterface->call(QStringLiteral("setOffMs"), m_offMs);
53− m_hfdInterface->call(QStringLiteral("setState"), 1);
54−}
55−
56−void HfdLights::turnOff()
57−{
58− m_hfdInterface->call(QStringLiteral("setState"), 0);
59− m_hfdInterface->call(QStringLiteral("setColor"), (quint32)0);
60− m_hfdInterface->call(QStringLiteral("setOnMs"), 0);
61− m_hfdInterface->call(QStringLiteral("setOffMs"), 0);
62−}
plugins/Lights/LegacyLights.cppdeleted−91
@@ -1,91 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− * Copyright (C) 2021 UBports Foundation.
4− *
5− * This program is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published by
7− * the Free Software Foundation; version 3.
8− *
9− * This program is distributed in the hope that it will be useful,
10− * but WITHOUT ANY WARRANTY; without even the implied warranty of
11− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12− * GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− *
17− * Author: Renato Araujo Oliveira Filho <renato.filho@canonical.com>
18− */
19−
20−#include "LegacyLights.h"
21−#include <QtCore/QDebug>
22−
23−extern "C" {
24−#include "android-hardware.h"
25−#include <string.h>
26−}
27−
28−LegacyLights::~LegacyLights()
29−{
30− if (m_lightDevice) {
31− hw_device_t* device = (hw_device_t*) m_lightDevice;
32− device->close(device);
33− }
34−}
35−
36−bool LegacyLights::init()
37−{
38− if (m_lightDevice) {
39− return true;
40− }
41−
42− int err;
43− hw_module_t* module;
44−
45− err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
46− if (err == 0) {
47− hw_device_t* device;
48− err = module->methods->open(module, LIGHT_ID_NOTIFICATIONS, &device);
49− if (err == 0) {
50− m_lightDevice = (light_device_t*)device;
51− turnOff();
52− return true;
53− } else {
54− qWarning() << "Failed to access notification lights";
55− }
56− } else {
57− qWarning() << "Failed to initialize lights hardware.";
58− }
59− return false;
60−}
61−
62−void LegacyLights::turnOn()
63−{
64− // pulse
65− light_state_t state;
66− memset(&state, 0, sizeof(light_state_t));
67− state.color = m_color.rgba();
68− state.flashMode = LIGHT_FLASH_TIMED;
69− state.flashOnMS = m_onMs;
70− state.flashOffMS = m_offMs;
71− state.brightnessMode = BRIGHTNESS_MODE_USER;
72−
73− if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
74− qWarning() << "Failed to turn the light off";
75− }
76−}
77−
78−void LegacyLights::turnOff()
79−{
80− light_state_t state;
81− memset(&state, 0, sizeof(light_state_t));
82− state.color = 0x00000000;
83− state.flashMode = LIGHT_FLASH_NONE;
84− state.flashOnMS = 0;
85− state.flashOffMS = 0;
86− state.brightnessMode = 0;
87−
88− if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
89− qWarning() << "Failed to turn the light off";
90− }
91−}
plugins/Lights/Lights.cpp+65
@@ -26,12 +26,20 @@ extern "C" {
26
26
27Lights::Lights(QObject* parent)
27Lights::Lights(QObject* parent)
28 : QObject(parent),
28 : QObject(parent),
29+ m_lightDevice(0),
29 m_color("blue"),
30 m_color("blue"),
30 m_state(Lights::Off),
31 m_state(Lights::Off),
31 m_onMs(1000),
32 m_onMs(1000),
32 m_offMs(3000)
33 m_offMs(3000)
33{
34{
35+}
34
36
37+Lights::~Lights()
38+{
39+ if (m_lightDevice) {
40+ hw_device_t* device = (hw_device_t*) m_lightDevice;
41+ device->close(device);
42+ }
35}
43}
36
44
37void Lights::setState(Lights::State newState)
45void Lights::setState(Lights::State newState)
@@ -99,3 +107,60 @@ void Lights::setOffMillisec(int offMs)
99 // FIXME: update the property if the light is already on
107 // FIXME: update the property if the light is already on
100 }
108 }
101}
109}
110+
111+bool Lights::init()
112+{
113+ if (m_lightDevice) {
114+ return true;
115+ }
116+
117+ int err;
118+ hw_module_t* module;
119+
120+ err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
121+ if (err == 0) {
122+ hw_device_t* device;
123+ err = module->methods->open(module, LIGHT_ID_NOTIFICATIONS, &device);
124+ if (err == 0) {
125+ m_lightDevice = (light_device_t*)device;
126+ turnOff();
127+ return true;
128+ } else {
129+ qWarning() << "Failed to access notification lights";
130+ }
131+ } else {
132+ qWarning() << "Failed to initialize lights hardware.";
133+ }
134+ return false;
135+}
136+
137+void Lights::turnOn()
138+{
139+ // pulse
140+ light_state_t state;
141+ memset(&state, 0, sizeof(light_state_t));
142+ state.color = m_color.rgba();
143+ state.flashMode = LIGHT_FLASH_TIMED;
144+ state.flashOnMS = m_onMs;
145+ state.flashOffMS = m_offMs;
146+ state.brightnessMode = BRIGHTNESS_MODE_USER;
147+
148+ if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
149+ qWarning() << "Failed to turn the light off";
150+ }
151+}
152+
153+void Lights::turnOff()
154+{
155+ light_state_t state;
156+ memset(&state, 0, sizeof(light_state_t));
157+ state.color = 0x00000000;
158+ state.flashMode = LIGHT_FLASH_NONE;
159+ state.flashOnMS = 0;
160+ state.flashOffMS = 0;
161+ state.brightnessMode = 0;
162+
163+ if (m_lightDevice->set_light(m_lightDevice, &state) != 0) {
164+ qWarning() << "Failed to turn the light off";
165+ }
166+}
plugins/Lights/Lights.h+8−4
@@ -22,6 +22,8 @@
22#include <QtCore/QObject>
22#include <QtCore/QObject>
23#include <QtGui/QColor>
23#include <QtGui/QColor>
24
24
25+struct light_device_t;
26+
25class Lights: public QObject
27class Lights: public QObject
26{
28{
27 Q_OBJECT
29 Q_OBJECT
@@ -38,6 +40,7 @@ public:
38 Q_ENUM(State)
40 Q_ENUM(State)
39
41
40 explicit Lights(QObject *parent = 0);
42 explicit Lights(QObject *parent = 0);
43+ ~Lights();
41
44
42 void setState(State newState);
45 void setState(State newState);
43 State state() const;
46 State state() const;
@@ -57,15 +60,16 @@ Q_SIGNALS:
57 void onMillisecChanged(int onMs);
60 void onMillisecChanged(int onMs);
58 void offMillisecChanged(int offMs);
61 void offMillisecChanged(int offMs);
59
62
60−protected:
63+private:
64+ light_device_t* m_lightDevice;
61 QColor m_color;
65 QColor m_color;
62 State m_state;
66 State m_state;
63 int m_onMs;
67 int m_onMs;
64 int m_offMs;
68 int m_offMs;
65
69
66− virtual bool init() = 0;
70+ bool init();
67− virtual void turnOff() = 0;
71+ void turnOff();
68− virtual void turnOn() = 0;
72+ void turnOn();
69};
73};
70
74
71#endif
75#endif
plugins/Lights/plugin.cpp+1−20
@@ -18,11 +18,6 @@
18
18
19#include "plugin.h"
19#include "plugin.h"
20#include "Lights.h"
20#include "Lights.h"
21−#include "HfdLights.h"
22−#include "LegacyLights.h"
23−
24−// libandroid-properties
25−#include <hybris/properties/properties.h>
26
21
27#include <QtQml/qqml.h>
22#include <QtQml/qqml.h>
28
23
@@ -30,21 +25,7 @@ static QObject *lights_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
30{
25{
31 Q_UNUSED(engine)
26 Q_UNUSED(engine)
32 Q_UNUSED(scriptEngine)
27 Q_UNUSED(scriptEngine)
33−
34− bool use_hfd = false;
35− char buffer[PROP_VALUE_MAX];
36− auto result = property_get("ro.build.version.sdk", buffer, "0");
37− if (result) {
38− auto sdkVersion = QString(buffer).toInt();
39− if (sdkVersion >= 27 || sdkVersion == 0) {
40− use_hfd = true;
41− }
42− }
43− if (use_hfd) {
44− return new HfdLights();
28+ return new Lights();
45− } else {
46− return new LegacyLights();
47− }
48}
29}
49
30
50void LightsPlugin::registerTypes(const char *uri)
31void LightsPlugin::registerTypes(const char *uri)
plugins/Powerd/CMakeLists.txt+2−4
@@ -9,9 +9,7 @@ add_library(Powerd-qml MODULE
9 Powerd.cpp
9 Powerd.cpp
10 )
10 )
11
11
12−target_link_libraries(Powerd-qml
12+qt5_use_modules(Powerd-qml DBus Qml)
13− Qt5::DBus Qt5::Qml
14− ${GIO_LDFLAGS}
13+target_link_libraries(Powerd-qml ${GIO_LDFLAGS})
15− )
16
14
17add_unity8_plugin(Powerd 0.1 Powerd TARGETS Powerd-qml)
15add_unity8_plugin(Powerd 0.1 Powerd TARGETS Powerd-qml)
plugins/ScreenshotDirectory/CMakeLists.txt+1−1
@@ -4,6 +4,6 @@ set(PLUGIN_SOURCES
4)
4)
5
5
6add_library(ScreenshotDirectory-qml MODULE ${PLUGIN_SOURCES})
6add_library(ScreenshotDirectory-qml MODULE ${PLUGIN_SOURCES})
7−target_link_libraries(ScreenshotDirectory-qml Qt5::Qml Qt5::Gui Qt5::Quick)
7+qt5_use_modules(ScreenshotDirectory-qml Qml Gui Quick)
8
8
9add_unity8_plugin(ScreenshotDirectory 0.1 ScreenshotDirectory TARGETS ScreenshotDirectory-qml)
9add_unity8_plugin(ScreenshotDirectory 0.1 ScreenshotDirectory TARGETS ScreenshotDirectory-qml)
plugins/SessionBroadcast/CMakeLists.txt+2−1
@@ -6,8 +6,9 @@ add_library(SessionBroadcast-qml MODULE
6 plugin.cpp
6 plugin.cpp
7 )
7 )
8
8
9+qt5_use_modules(SessionBroadcast-qml DBus Qml)
10+
9target_link_libraries(SessionBroadcast-qml
11target_link_libraries(SessionBroadcast-qml
10− Qt5::DBus Qt5::Qml
11 ${GLIB_LIBRARIES}
12 ${GLIB_LIBRARIES}
12 )
13 )
13
14
plugins/UInput/CMakeLists.txt+1−1
@@ -3,5 +3,5 @@ add_library(UInput-qml MODULE
3 uinput.cpp
3 uinput.cpp
4)
4)
5
5
6−target_link_libraries(UInput-qml Qt5::Qml)
6+qt5_use_modules(UInput-qml Qml)
7add_unity8_plugin(UInput 0.1 UInput TARGETS UInput-qml)
7add_unity8_plugin(UInput 0.1 UInput TARGETS UInput-qml)
plugins/Ubuntu/CMakeLists.txt+1
@@ -1,2 +1,3 @@
1add_subdirectory(Gestures)
1add_subdirectory(Gestures)
2add_subdirectory(DownloadDaemonListener)
2add_subdirectory(DownloadDaemonListener)
3+add_subdirectory(SystemImage)
plugins/Ubuntu/DownloadDaemonListener/CMakeLists.txt+2−4
@@ -11,10 +11,8 @@ set(DOWNLOADDAEMONLISTENER_SOURCES
11
11
12add_library(DownloadDaemonListener MODULE ${DOWNLOADDAEMONLISTENER_SOURCES})
12add_library(DownloadDaemonListener MODULE ${DOWNLOADDAEMONLISTENER_SOURCES})
13
13
14+qt5_use_modules(DownloadDaemonListener Qml Quick DBus Core)
14pkg_check_modules(DDLADAPTER REQUIRED udm-common)
15pkg_check_modules(DDLADAPTER REQUIRED udm-common)
15add_definitions(${DDLADAPTER_CFLAGS} ${DDLADAPTER_CFLAGS_OTHER})
16add_definitions(${DDLADAPTER_CFLAGS} ${DDLADAPTER_CFLAGS_OTHER})
16−target_link_libraries(DownloadDaemonListener
17+target_link_libraries(DownloadDaemonListener ${DDLADAPTER_LIBRARIES})
17− Qt5::Qml Qt5::Quick Qt5::DBus Qt5::Core
18− ${DDLADAPTER_LIBRARIES}
19− )
20add_unity8_plugin(Ubuntu.DownloadDaemonListener 0.1 Ubuntu/DownloadDaemonListener TARGETS DownloadDaemonListener)
18add_unity8_plugin(Ubuntu.DownloadDaemonListener 0.1 Ubuntu/DownloadDaemonListener TARGETS DownloadDaemonListener)
plugins/Ubuntu/Gestures/CMakeLists.txt+3−1
@@ -17,7 +17,9 @@ pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
18
18
19add_library(UbuntuGesturesQml SHARED ${UbuntuGesturesQml_SOURCES})
19add_library(UbuntuGesturesQml SHARED ${UbuntuGesturesQml_SOURCES})
20−target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES} Qt5::Core Qt5::Quick)
20+target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
21+
22+qt5_use_modules(UbuntuGesturesQml Core Quick)
21
23
22# So that Foo.cpp can #include "Foo.moc"
24# So that Foo.cpp can #include "Foo.moc"
23include_directories(${CMAKE_CURRENT_BINARY_DIR})
25include_directories(${CMAKE_CURRENT_BINARY_DIR})
plugins/Ubuntu/Gestures/TouchGestureArea.cpp+5−6
@@ -328,12 +328,6 @@ void TouchGestureArea::touchEvent_rejected(QTouchEvent *event)
328 }
328 }
329 }
329 }
330 }
330 }
331−
332− // If this event is a new touch, ignore it and let the item below have it.
333− // We won't recognize any new touch until the whole current gesture is done
334− // i.e. we're in WaitingForTouch state.
335− // And even if it isn't, just ignore it anyway; we don't care about it.
336− event->ignore();
337}
331}
338
332
339void TouchGestureArea::unownedTouchEvent(QTouchEvent *unownedTouchEvent)
333void TouchGestureArea::unownedTouchEvent(QTouchEvent *unownedTouchEvent)
@@ -741,6 +735,7 @@ void TouchGestureArea::resyncCachedTouchPoints()
741 bool added = false;
735 bool added = false;
742 bool ended = false;
736 bool ended = false;
743 bool moved = false;
737 bool moved = false;
738+ bool wantsDrag = false;
744
739
745 // list of deletes
740 // list of deletes
746 QMutableHashIterator<int, GestureTouchPoint*> removeIter(m_cachedTouchPoints);
741 QMutableHashIterator<int, GestureTouchPoint*> removeIter(m_cachedTouchPoints);
@@ -770,6 +765,10 @@ void TouchGestureArea::resyncCachedTouchPoints()
770 }
765 }
771 }
766 }
772
767
768+ if (wantsDrag && !dragging()) {
769+ setDragging(true);
770+ }
771+
773 if (ended) {
772 if (ended) {
774 if (m_cachedTouchPoints.isEmpty()) {
773 if (m_cachedTouchPoints.isEmpty()) {
775 if (!dragging()) Q_EMIT clicked();
774 if (!dragging()) Q_EMIT clicked();
plugins/Ubuntu/SystemImage/CMakeLists.txtnew file+15
@@ -0,0 +1,15 @@
1+include_directories(
2+ ${GLIB_INCLUDE_DIRS}
3+)
4+
5+set(SYSTEMIMAGE_SOURCES
6+ plugin.cpp
7+ SystemImage.cpp
8+)
9+
10+add_library(SystemImage MODULE ${SYSTEMIMAGE_SOURCES})
11+
12+qt5_use_modules(SystemImage Qml DBus Core)
13+target_link_libraries(SystemImage ${GLIB_LIBRARIES})
14+
15+add_unity8_plugin(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS SystemImage)
plugins/Ubuntu/SystemImage/SystemImage.cppnew file+155
@@ -0,0 +1,155 @@
1+/*
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QDBusConnection>
18+#include <QDBusPendingCall>
19+#include <QDBusReply>
20+#include <QDebug>
21+
22+#include <glib.h>
23+
24+#include "SystemImage.h"
25+
26+#define SYSTEMIMAGE_SERVICE QStringLiteral("com.canonical.SystemImage")
27+#define SYSTEMIMAGE_PATH QStringLiteral("/Service")
28+#define SYSTEMIMAGE_IFACE QStringLiteral("com.canonical.SystemImage")
29+
30+Q_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN, "unity8.systemimage", QtWarningMsg)
31+
32+#define DEBUG_MSG qCDebug(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
33+#define WARNING_MSG qCWarning(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
34+
35+SystemImage::SystemImage(QObject *parent)
36+ : QObject(parent)
37+{
38+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateAvailableStatus"),
39+ this, SLOT(onUpdateAvailableStatus(bool,bool,QString,int,QString,QString)));
40+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateDownloaded"),
41+ this, SLOT(onUpdateDownloaded()));
42+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateFailed"),
43+ this, SLOT(onUpdateFailed(int,QString)));
44+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Applied"),
45+ this, SLOT(onUpdateApplied(bool)));
46+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Rebooting"),
47+ this, SLOT(onRebooting(bool)));
48+}
49+
50+void SystemImage::checkForUpdate()
51+{
52+ DEBUG_MSG << "Checking for update";
53+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
54+ QStringLiteral("CheckForUpdate"));
55+ QDBusConnection::systemBus().asyncCall(msg);
56+}
57+
58+void SystemImage::applyUpdate()
59+{
60+ DEBUG_MSG << "Applying update";
61+ setUpdateApplying(true);
62+
63+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
64+ QStringLiteral("ApplyUpdate"));
65+ QDBusConnection::systemBus().asyncCall(msg);
66+}
67+
68+void SystemImage::factoryReset()
69+{
70+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
71+ QStringLiteral("FactoryReset"));
72+ QDBusConnection::systemBus().asyncCall(msg);
73+}
74+
75+void SystemImage::onUpdateAvailableStatus(bool is_available, bool downloading, const QString &available_version, int update_size,
76+ const QString &last_update_date, const QString &error_reason)
77+{
78+ DEBUG_MSG << "A new update is " << (is_available ? "" : "NOT") << "available";
79+
80+ if (is_available == m_updateAvailable) {
81+ return;
82+ }
83+
84+ m_updateAvailable = is_available;
85+ m_downloading = downloading;
86+ m_availableVersion = available_version;
87+ m_updateSize = formatSize(update_size);
88+ m_lastUpdateDate = last_update_date;
89+ m_errorReason = error_reason;
90+ Q_EMIT updateAvailableStatus();
91+
92+ DEBUG_MSG << "Downloading: " << downloading << ", version: " << available_version << ", last update: " << last_update_date <<
93+ ", size: " << m_updateSize;
94+}
95+
96+void SystemImage::onUpdateDownloaded()
97+{
98+ DEBUG_MSG << "Update downloaded";
99+
100+ m_downloaded = true;
101+ Q_EMIT updateDownloadedChanged();
102+}
103+
104+void SystemImage::onUpdateFailed(int /*consecutive_failure_count*/, const QString &last_reason)
105+{
106+ WARNING_MSG << "System Update failed: " << last_reason;
107+ setUpdateApplying(false);
108+}
109+
110+void SystemImage::onUpdateApplied(bool applied)
111+{
112+ DEBUG_MSG << "System Update applied with status: " << applied;
113+ setUpdateApplying(false);
114+ if (applied) {
115+ resetUpdateStatus();
116+ Q_EMIT updateAvailableStatus();
117+ }
118+}
119+
120+void SystemImage::onRebooting(bool status)
121+{
122+ setUpdateApplying(false);
123+ DEBUG_MSG << "Rebooting: " << status;
124+}
125+
126+void SystemImage::setUpdateApplying(bool status)
127+{
128+ if (status != m_updateApplying) {
129+ m_updateApplying = status;
130+ Q_EMIT updateApplyingChanged();
131+ }
132+}
133+
134+void SystemImage::resetUpdateStatus()
135+{
136+ m_updateAvailable = false;
137+ m_updateApplying = false;
138+ m_downloading = false;
139+ m_downloaded = false;
140+ m_availableVersion.clear();
141+ m_updateSize.clear();
142+ m_lastUpdateDate.clear();
143+ m_errorReason.clear();
144+}
145+
146+QString SystemImage::formatSize(quint64 size) const
147+{
148+ guint64 g_size = size;
149+
150+ gchar * formatted_size = g_format_size(g_size);
151+ QString q_formatted_size = QString::fromLocal8Bit(formatted_size);
152+ g_free(formatted_size);
153+
154+ return q_formatted_size;
155+}
plugins/Ubuntu/SystemImage/SystemImage.hnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SYSTEMIMAGE_H
18+#define SYSTEMIMAGE_H
19+
20+#include <QObject>
21+#include <QLoggingCategory>
22+
23+Q_DECLARE_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN)
24+
25+class SystemImage : public QObject
26+{
27+ Q_OBJECT
28+ Q_DISABLE_COPY(SystemImage)
29+
30+ Q_PROPERTY(bool updateAvailable READ updateAvailable NOTIFY updateAvailableStatus)
31+ Q_PROPERTY(bool updateDownloading READ updateDownloading NOTIFY updateAvailableStatus)
32+ Q_PROPERTY(QString availableVersion READ availableVersion NOTIFY updateAvailableStatus)
33+ Q_PROPERTY(QString updateSize READ updateSize NOTIFY updateAvailableStatus)
34+ Q_PROPERTY(bool updateApplying READ updateApplying NOTIFY updateApplyingChanged)
35+ Q_PROPERTY(bool updateDownloaded READ updateDownloaded NOTIFY updateDownloadedChanged)
36+
37+public:
38+ explicit SystemImage(QObject *parent = nullptr);
39+ ~SystemImage() = default;
40+
41+ bool updateAvailable() const { return m_updateAvailable; }
42+ bool updateDownloading() const { return m_downloading; }
43+ QString availableVersion() const { return m_availableVersion; }
44+ QString updateSize() const { return m_updateSize; }
45+ bool updateApplying() const { return m_updateApplying; }
46+ bool updateDownloaded() const { return m_downloaded; }
47+
48+public Q_SLOTS:
49+ Q_INVOKABLE void checkForUpdate();
50+ Q_INVOKABLE void applyUpdate();
51+ Q_INVOKABLE void factoryReset();
52+
53+private Q_SLOTS:
54+ void onUpdateAvailableStatus(bool is_available, bool updateDownloading, const QString &available_version,
55+ int update_size, const QString &last_update_date, const QString &error_reason);
56+ void onUpdateDownloaded();
57+ void onUpdateFailed(int consecutive_failure_count, const QString & last_reason);
58+ void onUpdateApplied(bool applied);
59+ void onRebooting(bool status);
60+
61+Q_SIGNALS:
62+ void updateAvailableStatus();
63+ void updateDownloadedChanged();
64+ void updateApplyingChanged();
65+
66+private Q_SLOTS:
67+ void setUpdateApplying(bool status);
68+
69+private:
70+ void resetUpdateStatus();
71+ QString formatSize(quint64 size) const;
72+
73+private:
74+ bool m_updateAvailable = false;
75+ bool m_updateApplying = false;
76+ bool m_downloading = false;
77+ bool m_downloaded = false;
78+ QString m_availableVersion;
79+ QString m_updateSize;
80+ QString m_lastUpdateDate;
81+ QString m_errorReason;
82+};
83+
84+#endif // SYSTEMIMAGE_H
plugins/Ubuntu/SystemImage/plugin.cppnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "SystemImage.h"
19+
20+#include <QtQml>
21+
22+void BackendPlugin::registerTypes(const char *uri)
23+{
24+ Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
25+
26+ qmlRegisterSingletonType<SystemImage>(uri, 0, 1, "SystemImage",
27+ [](QQmlEngine*, QJSEngine*) -> QObject* { return new SystemImage; });
28+}
plugins/Ubuntu/SystemImage/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SYSTEMIMAGE_PLUGIN_H
18+#define SYSTEMIMAGE_PLUGIN_H
19+
20+#include <QQmlExtensionPlugin>
21+
22+class BackendPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
26+
27+public:
28+ void registerTypes(const char *uri) override;
29+};
30+
31+#endif // SYSTEMIMAGE_PLUGIN_H
plugins/Ubuntu/SystemImage/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Ubuntu.SystemImage
2+plugin SystemImage
3+typeinfo SystemImage.qmltypes
plugins/Unity/ApplicationMenu/CMakeLists.txt+1−1
@@ -14,6 +14,6 @@ qt5_add_dbus_adaptor(applicationMenu_SRCS com.ubuntu.MenuRegistrar.xml dbusappli
14
14
15add_library(ApplicationMenu-qml MODULE ${applicationMenu_SRCS})
15add_library(ApplicationMenu-qml MODULE ${applicationMenu_SRCS})
16
16
17−target_link_libraries(ApplicationMenu-qml Qt5::DBus Qt5::Qml)
17+qt5_use_modules(ApplicationMenu-qml DBus Qml)
18
18
19add_unity8_plugin(Unity.ApplicationMenu 0.1 Unity/ApplicationMenu TARGETS ApplicationMenu-qml)
19add_unity8_plugin(Unity.ApplicationMenu 0.1 Unity/ApplicationMenu TARGETS ApplicationMenu-qml)
plugins/Unity/CMakeLists.txt+1
@@ -3,5 +3,6 @@ add_subdirectory(Connectivity)
3add_subdirectory(Indicators)
3add_subdirectory(Indicators)
4add_subdirectory(Launcher)
4add_subdirectory(Launcher)
5add_subdirectory(Session)
5add_subdirectory(Session)
6+add_subdirectory(DashCommunicator)
6add_subdirectory(InputInfo)
7add_subdirectory(InputInfo)
7add_subdirectory(Platform)
8add_subdirectory(Platform)
plugins/Unity/Connectivity/CMakeLists.txt+1−1
@@ -5,6 +5,6 @@ set(CONNECTIVITY_SOURCES
5
5
6add_library(Connectivity MODULE ${CONNECTIVITY_SOURCES})
6add_library(Connectivity MODULE ${CONNECTIVITY_SOURCES})
7
7
8−target_link_libraries(Connectivity Qt5::Qml Qt5::DBus Qt5::Core)
8+qt5_use_modules(Connectivity Qml DBus Core)
9
9
10add_unity8_plugin(Unity.Connectivity 0.1 Unity/Connectivity TARGETS Connectivity)
10add_unity8_plugin(Unity.Connectivity 0.1 Unity/Connectivity TARGETS Connectivity)
plugins/Unity/DashCommunicator/CMakeLists.txtnew file+26
@@ -0,0 +1,26 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+ ${CMAKE_CURRENT_BINARY_DIR}
4+ ${libunity8-private_SOURCE_DIR}
5+)
6+
7+set(QMLDASHCOMMUNICATORPLUGIN_SRC
8+ plugin.cpp
9+ dbusdashcommunicatorservice.cpp
10+ dashcommunicatorservice.cpp
11+ dashcommunicator.cpp
12+ dashconnection.cpp
13+)
14+
15+add_library(DashCommunicator-qml MODULE
16+ ${QMLDASHCOMMUNICATORPLUGIN_SRC}
17+)
18+
19+qt5_use_modules(DashCommunicator-qml DBus Qml)
20+
21+target_link_libraries(DashCommunicator-qml
22+ unity8-private
23+)
24+
25+# export the qmldir and qmltypes files
26+add_unity8_plugin(Unity.DashCommunicator 0.1 Unity/DashCommunicator TARGETS DashCommunicator-qml)
plugins/Unity/DashCommunicator/dashcommunicator.cppnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicator.h"
18+#include "dashconnection.h"
19+
20+#include <QObject>
21+
22+DashCommunicator::DashCommunicator(QObject *parent):
23+ QThread(parent),
24+ m_dashConnection(nullptr),
25+ m_created(false)
26+{
27+ start();
28+}
29+
30+DashCommunicator::~DashCommunicator()
31+{
32+ quit();
33+ wait();
34+}
35+
36+void DashCommunicator::setCurrentScope(int index, bool animate, bool isSwipe)
37+{
38+ m_mutex.lock();
39+ if (m_created) {
40+ QMetaObject::invokeMethod(m_dashConnection, "setCurrentScope",
41+ Q_ARG(int, index),
42+ Q_ARG(bool, animate),
43+ Q_ARG(bool, isSwipe));
44+ }
45+ m_mutex.unlock();
46+}
47+
48+void DashCommunicator::run()
49+{
50+ m_dashConnection = new DashConnection(QStringLiteral("com.canonical.UnityDash"),
51+ QStringLiteral("/com/canonical/UnityDash"),
52+ QLatin1String(""), this);
53+ m_mutex.lock();
54+ m_created = true;
55+ m_mutex.unlock();
56+
57+ exec();
58+}
plugins/WindowManager/AvailableDesktopArea.h → plugins/Unity/DashCommunicator/dashcommunicator.hrenamed+21−14
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2017 Canonical, Ltd.
2+ * Copyright (C) 2014 Canonical, Ltd.
3 *
3 *
4 * This program is free software: you can redistribute it and/or modify it under
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -14,25 +14,32 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef AVAILABLEDESKTOPAREA_H
17+#ifndef DASHCOMMUNICATOR_H
18−#define AVAILABLEDESKTOPAREA_H
18+#define DASHCOMMUNICATOR_H
19
19
20+// Qt
20−#include <QQuickItem>
21+#include <QThread>
22+#include <QMutex>
21
23
22−/**
24+class DashConnection;
23− @brief Used to inform qtmir/miral about the available desktop area of shell
24
25
25− So that qtmir/miral can take correct window management decisions.
26+class DashCommunicator: public QThread
26− */
27−class AvailableDesktopArea : public QQuickItem
28{
27{
29 Q_OBJECT
28 Q_OBJECT
30public:
29public:
31− AvailableDesktopArea(QQuickItem *parent = nullptr);
30+ explicit DashCommunicator(QObject *parent = 0);
31+ ~DashCommunicator();
32+
33+public Q_SLOTS:
34+ void setCurrentScope(int index, bool animate, bool isSwipe);
35+
32protected:
36protected:
33− void itemChange(ItemChange change, const ItemChangeData &value) override;
37+ void run() override;
38+
34−private Q_SLOTS:
39+private:
35− void updatePlatformWindowProperty();
40+ DashConnection *m_dashConnection;
41+ bool m_created;
42+ QMutex m_mutex;
36};
43};
37
44
38−#endif // AVAILABLEDESKTOPAREA_H
45+#endif
plugins/Unity/DashCommunicator/dashcommunicatorservice.cppnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashcommunicatorservice.h"
18+
19+DashCommunicatorService::DashCommunicatorService(QObject *parent):
20+ QObject(parent),
21+ m_dbusService(new DBusDashCommunicatorService(this))
22+{
23+ connect(m_dbusService, &DBusDashCommunicatorService::setCurrentScopeRequested, this, &DashCommunicatorService::setCurrentScopeRequested);
24+}
25+
26+
27+DashCommunicatorService::~DashCommunicatorService()
28+{
29+
30+}
plugins/Unity/DashCommunicator/dashcommunicatorservice.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DASHCOMMUNICATORSERVICE_H
18+#define DASHCOMMUNICATORSERVICE_H
19+
20+#include "dbusdashcommunicatorservice.h"
21+
22+#include <QObject>
23+
24+class DashCommunicatorService: public QObject
25+{
26+ Q_OBJECT
27+public:
28+ DashCommunicatorService(QObject *parent = 0);
29+ ~DashCommunicatorService();
30+
31+Q_SIGNALS:
32+ void setCurrentScopeRequested(int index, bool animate, bool isSwipe);
33+
34+private:
35+ DBusDashCommunicatorService *m_dbusService;
36+};
37+
38+#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Unity/DashCommunicator/dashconnection.cppnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dashconnection.h"
18+
19+#include <QDBusInterface>
20+#include <QDBusPendingCall>
21+
22+/* The default implementation of AbstractDBusServiceMonitor creates a QDBusInterface when the service
23+ * appears on the bus.
24+ *
25+ * On construction QDBusInterface synchronously introspects the service, which will block the GUI
26+ * thread of this process if the service is busy. QDBusAbstractInterface does not perform this
27+ * introspection, so let's subclass that and avoid the blocking scenario.
28+ *
29+ * However we lose Qt's wrapping of the DBus service with a MetaObject, with the result that we
30+ * cannot easily connect to DBus signals with the usual connect() calls. So this approach only
31+ * suited to push communication with the DBus service.
32+ */
33+class AsyncDBusInterface : public QDBusAbstractInterface
34+{
35+ Q_OBJECT
36+public:
37+ AsyncDBusInterface(const QString &service, const QString &path,
38+ const QString &interface, const QDBusConnection &connection,
39+ QObject *parent = 0)
40+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
41+ {}
42+ ~AsyncDBusInterface() = default;
43+};
44+
45+
46+DashConnection::DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent):
47+ AbstractDBusServiceMonitor(service, path, interface, SessionBus, parent)
48+{
49+
50+}
51+
52+/* Override the default implementation to create a non-blocking DBus interface (see note above). */
53+QDBusAbstractInterface* DashConnection::createInterface(const QString &service, const QString &path,
54+ const QString &interface, const QDBusConnection &connection)
55+{
56+ return new AsyncDBusInterface(service, path, interface, connection);
57+}
58+
59+void DashConnection::setCurrentScope(int index, bool animate, bool isSwipe)
60+{
61+ if (dbusInterface()) {
62+ dbusInterface()->asyncCall(QStringLiteral("SetCurrentScope"), index, animate, isSwipe);
63+ }
64+}
65+
66+#include "dashconnection.moc"
plugins/Unity/DashCommunicator/dashconnection.hnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef THREADEDDASHCONNECTION_H
18+#define THREADEDDASHCONNECTION_H
19+
20+// local
21+#include "abstractdbusservicemonitor.h"
22+
23+class DashConnection: public AbstractDBusServiceMonitor
24+{
25+ Q_OBJECT
26+public:
27+ DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent = 0);
28+
29+public Q_SLOTS:
30+ void setCurrentScope(int index, bool animate, bool isSwipe);
31+
32+private:
33+ QDBusAbstractInterface* createInterface(const QString &service, const QString &path,
34+ const QString &interface, const QDBusConnection &connection) override;
35+};
36+
37+#endif
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "dbusdashcommunicatorservice.h"
18+
19+#include <QDBusConnection>
20+#include <QDBusInterface>
21+#include <QDebug>
22+
23+DBusDashCommunicatorService::DBusDashCommunicatorService(QObject *parent):
24+ UnityDBusObject(QStringLiteral("/com/canonical/UnityDash"), QStringLiteral("com.canonical.UnityDash"), false, parent)
25+{
26+}
27+
28+DBusDashCommunicatorService::~DBusDashCommunicatorService()
29+{
30+}
31+
32+void DBusDashCommunicatorService::SetCurrentScope(int index, bool animate, bool isSwipe)
33+{
34+ Q_EMIT setCurrentScopeRequested(index, animate, isSwipe);
35+}
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.hnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef DBUSDASHCOMMUNICATORSERVICE_H
18+#define DBUSDASHCOMMUNICATORSERVICE_H
19+
20+#include "unitydbusobject.h"
21+
22+class DBusDashCommunicatorService: public UnityDBusObject
23+{
24+ Q_OBJECT
25+ Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity.DashCommunicator")
26+
27+public:
28+ DBusDashCommunicatorService(QObject *parent = 0);
29+ ~DBusDashCommunicatorService();
30+
31+Q_SIGNALS:
32+ void setCurrentScopeRequested(int index, bool animate, bool isSwipe);
33+
34+public Q_SLOTS:
35+ Q_SCRIPTABLE void SetCurrentScope(int index, bool animate, bool isSwipe);
36+
37+};
38+
39+#endif // DBUSDASHCOMMUNICATORSERVICE_H
tests/mocks/LightDMController/plugin.cpp → plugins/Unity/DashCommunicator/plugin.cpprenamed+11−14
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2017 Canonical, Ltd.
2+ * Copyright (C) 2014 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -12,24 +12,21 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
15 */
17 */
16
18
17#include "plugin.h"
19#include "plugin.h"
20+#include "dashcommunicator.h"
21+#include "dashcommunicatorservice.h"
18
22
19−#include "MockController.h"
23+#include <QDBusConnection>
20−
21#include <QtQml/qqml.h>
24#include <QtQml/qqml.h>
22
25
23−static QObject *mock_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24−{
25− Q_UNUSED(scriptEngine)
26− auto controller = QLightDM::MockController::instance();
27− engine->setObjectOwnership(controller, QQmlEngine::CppOwnership);
28− return controller;
29−}
30−
31−void LightDMControllerPlugin::registerTypes(const char *uri)
26+void DashCommunicatorPlugin::registerTypes(const char *uri)
32{
27{
33− Q_ASSERT(uri == QLatin1String("LightDMController"));
28+ // @uri Unity.DashCommunicator
34− qmlRegisterSingletonType<QLightDM::MockController>(uri, 0, 1, "LightDMController", mock_provider);
29+ Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
30+ qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
31+ qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
35}
32}
plugins/Lights/LegacyLights.h → plugins/Unity/DashCommunicator/plugin.hrenamed+8−19
@@ -1,6 +1,5 @@
1/*
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
2 * Copyright (C) 2014 Canonical, Ltd.
3− * Copyright (C) 2021 UBports Foundation.
4 *
3 *
5 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -14,32 +13,22 @@
14 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
15 *
17− * Author: Renato Araujo Oliveira Filho <renato.filho@canonical.com>
16+ * Authors: Michael Zanetti <michael.zanetti@canonical.com>
18 */
17 */
19
18
20−#ifndef UNITY_LEGACYLIGHTS_H
19+#ifndef DASHCOMMUNICATOR_PLUGIN_H
21−#define UNITY_LEGACYLIGHTS_H
20+#define DASHCOMMUNICATOR_PLUGIN_H
22
21
23−#include <QtCore/QObject>
22+#include <QtQml/QQmlEngine>
24−#include "Lights.h"
23+#include <QtQml/QQmlExtensionPlugin>
25
24
26−struct light_device_t;
25+class DashCommunicatorPlugin : public QQmlExtensionPlugin
27−
28−class LegacyLights: public Lights
29{
26{
30 Q_OBJECT
27 Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
31
29
32public:
30public:
33− ~LegacyLights();
31+ void registerTypes(const char *uri) override;
34−
35−protected:
36− bool init() override;
37− void turnOff() override;
38− void turnOn() override;
39−
40−private:
41− light_device_t* m_lightDevice;
42−
43};
32};
44
33
45#endif
34#endif
plugins/Unity/DashCommunicator/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.DashCommunicator
2+plugin DashCommunicator-qml
3+typeinfo DashCommunicator.qmltypes
plugins/Unity/Indicators/CMakeLists.txt+2−1
@@ -44,7 +44,8 @@ target_link_libraries(IndicatorsQml
44 ${GLIB_LIBRARIES}
44 ${GLIB_LIBRARIES}
45 ${GIO_LIBRARIES}
45 ${GIO_LIBRARIES}
46 ${QMENUMODEL_LDFLAGS}
46 ${QMENUMODEL_LDFLAGS}
47− Qt5::Core Qt5::Qml Qt5::Quick Qt5::DBus
48)
47)
49
48
49+qt5_use_modules(IndicatorsQml Core Qml Quick DBus)
50+
50add_unity8_plugin(Unity.Indicators 0.1 Unity/Indicators TARGETS IndicatorsQml)
51add_unity8_plugin(Unity.Indicators 0.1 Unity/Indicators TARGETS IndicatorsQml)
plugins/Unity/Indicators/indicatorsmodel.cpp−13
@@ -103,19 +103,6 @@ void IndicatorsModel::setProfile(const QString &profile)
103 m_manager->setProfile(profile);
103 m_manager->setProfile(profile);
104}
104}
105
105
106−bool IndicatorsModel::light() const
107−{
108− return m_light;
109−}
110−
111−void IndicatorsModel::setLight(const bool &light)
112−{
113− if (m_light != light) {
114− m_light = light;
115− Q_EMIT lightChanged();
116− }
117−}
118−
119/*!
106/*!
120 \qmlmethod IndicatorsModel::unload()
107 \qmlmethod IndicatorsModel::unload()
121
108
plugins/Unity/Indicators/indicatorsmodel.h−9
@@ -35,9 +35,6 @@ class UNITYINDICATORS_EXPORT IndicatorsModel : public QAbstractListModel
35 Q_PROPERTY(int count READ count NOTIFY countChanged)
35 Q_PROPERTY(int count READ count NOTIFY countChanged)
36 Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
36 Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
37
37
38− // Used for tests
39− Q_PROPERTY(bool light READ light WRITE setLight NOTIFY lightChanged)
40−
41public:
38public:
42
39
43 IndicatorsModel(QObject *parent=nullptr);
40 IndicatorsModel(QObject *parent=nullptr);
@@ -51,9 +48,6 @@ public:
51 QString profile() const;
48 QString profile() const;
52 void setProfile(const QString& profile);
49 void setProfile(const QString& profile);
53
50
54− bool light() const;
55− void setLight(const bool &light);
56−
57 /* QAbstractItemModel */
51 /* QAbstractItemModel */
58 QHash<int, QByteArray> roleNames() const override;
52 QHash<int, QByteArray> roleNames() const override;
59 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
53 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -66,7 +60,6 @@ Q_SIGNALS:
66 void countChanged();
60 void countChanged();
67 void profileChanged();
61 void profileChanged();
68 void indicatorDataChanged(const QVariant& data);
62 void indicatorDataChanged(const QVariant& data);
69− void lightChanged();
70
63
71private Q_SLOTS:
64private Q_SLOTS:
72 void onIdentifierChanged();
65 void onIdentifierChanged();
@@ -81,8 +74,6 @@ private:
81
74
82 void notifyDataChanged(QObject *sender, int role);
75 void notifyDataChanged(QObject *sender, int role);
83 int count() const;
76 int count() const;
84−
85− bool m_light;
86};
77};
87
78
88#endif // INDICATORSMODEL_H
79#endif // INDICATORSMODEL_H
plugins/Unity/InputInfo/CMakeLists.txt+2−1
@@ -32,7 +32,8 @@ add_library(InputInfo SHARED
32target_link_libraries(InputInfo
32target_link_libraries(InputInfo
33 ${LIBUDEV_LDFLAGS}
33 ${LIBUDEV_LDFLAGS}
34 ${LIBEVDEV_LDFLAGS}
34 ${LIBEVDEV_LDFLAGS}
35− Qt5::Core Qt5::Qml Qt5::Quick
36)
35)
37
36
37+qt5_use_modules(InputInfo Core Qml Quick)
38+
38add_unity8_plugin(Unity.InputInfo 0.1 Unity/InputInfo TARGETS InputInfo)
39add_unity8_plugin(Unity.InputInfo 0.1 Unity/InputInfo TARGETS InputInfo)
plugins/Unity/Launcher/CMakeLists.txt+3−4
@@ -1,3 +1,4 @@
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2
3
3add_definitions(-DSM_BUSNAME=systemBus)
4add_definitions(-DSM_BUSNAME=systemBus)
@@ -26,13 +27,10 @@ set(QMLLAUNCHERPLUGIN_SRC
26 asadapter.cpp
27 asadapter.cpp
27 appdrawermodel.cpp
28 appdrawermodel.cpp
28 ualwrapper.cpp
29 ualwrapper.cpp
29− xdgwatcher.cpp
30 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
30 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
33 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
33 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
34− ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
35− ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
38 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
@@ -48,7 +46,8 @@ target_link_libraries(UnityLauncher-qml
48 ${GSETTINGS_QT_LDFLAGS}
46 ${GSETTINGS_QT_LDFLAGS}
49 ${GLIB_LIBRARIES}
47 ${GLIB_LIBRARIES}
50 ${UAL_LIBRARIES}
48 ${UAL_LIBRARIES}
51− Qt5::DBus Qt5::Qml Qt5::Gui Qt5::Concurrent
52 )
49 )
53
50
51+qt5_use_modules(UnityLauncher-qml DBus Qml Gui)
52+
54add_unity8_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncher-qml)
53add_unity8_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncher-qml)
plugins/Unity/Launcher/appdrawermodel.cpp+14−144
@@ -1,6 +1,5 @@
1/*
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
2 * Copyright (C) 2016 Canonical, Ltd.
3− * Copyright (C) 2020 UBports Foundation.
4 *
3 *
5 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -17,35 +16,23 @@
17
16
18#include "appdrawermodel.h"
17#include "appdrawermodel.h"
19#include "ualwrapper.h"
18#include "ualwrapper.h"
20−#include "xdgwatcher.h"
21
19
22#include <QDebug>
20#include <QDebug>
23#include <QDateTime>
21#include <QDateTime>
24−#include <QtConcurrentRun>
25−
26−static std::shared_ptr<LauncherItem> makeSharedLauncherItem(
27− const QString &appId, const QString &name, const QString &icon, QObject * parent)
28−{
29− return std::shared_ptr<LauncherItem>(
30− new LauncherItem(appId, name, icon, parent),
31− [] (LauncherItem *item) { item->deleteLater(); });
32−}
33
22
34AppDrawerModel::AppDrawerModel(QObject *parent):
23AppDrawerModel::AppDrawerModel(QObject *parent):
35− AppDrawerModelInterface(parent),
24+ AppDrawerModelInterface(parent)
36− m_ual(new UalWrapper(this)),
37− m_xdgWatcher(new XdgWatcher(this)),
38− m_refreshing(false)
39{
25{
40− connect(&m_refreshFutureWatcher, &QFutureWatcher<ItemList>::finished,
26+ Q_FOREACH (const QString &appId, UalWrapper::installedApps()) {
41− this, &AppDrawerModel::onRefreshFinished);
27+ UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
42−
28+ if (!info.valid) {
43− // keep this a queued connection as it's coming from another thread.
29+ qWarning() << "Failed to get app info for app" << appId;
44− connect(m_xdgWatcher, &XdgWatcher::appAdded, this, &AppDrawerModel::appAdded, Qt::QueuedConnection);
30+ continue;
45− connect(m_xdgWatcher, &XdgWatcher::appRemoved, this, &AppDrawerModel::appRemoved, Qt::QueuedConnection);
31+ }
46− connect(m_xdgWatcher, &XdgWatcher::appInfoChanged, this, &AppDrawerModel::appInfoChanged, Qt::QueuedConnection);
32+ m_list.append(new LauncherItem(appId, info.name, info.icon, this));
47−
33+ m_list.last()->setKeywords(info.keywords);
48− refresh();
34+ }
35+ qsrand(QDateTime::currentMSecsSinceEpoch() / 100);
49}
36}
50
37
51int AppDrawerModel::rowCount(const QModelIndex &parent) const
38int AppDrawerModel::rowCount(const QModelIndex &parent) const
@@ -66,127 +53,10 @@ QVariant AppDrawerModel::data(const QModelIndex &index, int role) const
66 case RoleKeywords:
53 case RoleKeywords:
67 return m_list.at(index.row())->keywords();
54 return m_list.at(index.row())->keywords();
68 case RoleUsage:
55 case RoleUsage:
69− return m_list.at(index.row())->popularity();
56+ // FIXME: u-a-l needs to provide API for usage stats.
57+ // don't forget to drop the qsrand() call in the ctor when dropping this.
58+ return qrand();
70 }
59 }
71
60
72 return QVariant();
61 return QVariant();
73}
62}
74−
75−void AppDrawerModel::appAdded(const QString &appId)
76−{
77− if (m_refreshing)
78− // Will be replaced by the refresh result anyway.
79− return;
80−
81− UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
82− if (!info.valid) {
83− qWarning() << "App added signal received but failed to get app info for app" << appId;
84− return;
85− }
86−
87− beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
88− auto item = makeSharedLauncherItem(appId, info.name, info.icon, /* parent */ nullptr);
89− item->setKeywords(info.keywords);
90− item->setPopularity(info.popularity);
91− m_list.append(std::move(item));
92− endInsertRows();
93−}
94−
95−void AppDrawerModel::appRemoved(const QString &appId)
96−{
97− if (m_refreshing)
98− // Will be replaced by the refresh result anyway.
99− return;
100−
101− int idx = -1;
102− for (int i = 0; i < m_list.count(); i++) {
103− if (m_list.at(i)->appId() == appId) {
104− idx = i;
105− break;
106− }
107− }
108− if (idx < 0) {
109− qWarning() << "App removed signal received but app doesn't seem to be in the drawer model";
110− return;
111− }
112− beginRemoveRows(QModelIndex(), idx, idx);
113− m_list.removeAt(idx);
114− endRemoveRows();
115−}
116−
117−void AppDrawerModel::appInfoChanged(const QString &appId)
118−{
119− if (m_refreshing)
120− // Will be replaced by the refresh result anyway.
121− return;
122−
123− std::shared_ptr<LauncherItem> item;
124− int idx = -1;
125−
126− for(int i = 0; i < m_list.count(); i++) {
127− if (m_list.at(i)->appId() == appId) {
128− item = m_list.at(i);
129− idx = i;
130− break;
131− }
132− }
133−
134− if (!item) {
135− return;
136− }
137−
138− UalWrapper::AppInfo info = m_ual->getApplicationInfo(appId);
139− item->setPopularity(info.popularity);
140− Q_EMIT dataChanged(index(idx), index(idx), {AppDrawerModelInterface::RoleUsage});
141−}
142−
143−bool AppDrawerModel::refreshing() {
144− return m_refreshing;
145−}
146−
147−void AppDrawerModel::refresh() {
148− if (m_refreshing)
149− return;
150−
151− m_refreshFutureWatcher.setFuture(QtConcurrent::run([](QThread *thread) {
152− ItemList list;
153−
154− Q_FOREACH (const QString &appId, UalWrapper::installedApps()) {
155− UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
156− if (!info.valid) {
157− qWarning() << "Failed to get app info for app" << appId;
158− continue;
159− }
160− // We don't pass parent in because this may run after the model is destroyed.
161− // (And, in fact, we can't, because the model is in a diferent thread.)
162− auto item = makeSharedLauncherItem(appId, info.name, info.icon, /* parent */ nullptr);
163− item->setKeywords(info.keywords);
164− item->setPopularity(info.popularity);
165− item->moveToThread(thread);
166− list.append(std::move(item));
167− }
168−
169− return list;
170− }, this->thread()));
171−
172− m_refreshing = true;
173− Q_EMIT refreshingChanged();
174−}
175−
176−void AppDrawerModel::onRefreshFinished() {
177− if (m_refreshFutureWatcher.isCanceled())
178− // This is the result of setting canceled future below.
179− return;
180−
181− beginResetModel();
182−
183− m_list = m_refreshFutureWatcher.result();
184− // Remove the future & its result, so that future modifications won't
185− // create a copy.
186− m_refreshFutureWatcher.setFuture(QFuture<ItemList>());
187−
188− endResetModel();
189−
190− m_refreshing = false;
191− Q_EMIT refreshingChanged();
192−}
plugins/Unity/Launcher/appdrawermodel.h+2−33
@@ -1,6 +1,5 @@
1/*
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
2 * Copyright (C) 2016 Canonical, Ltd.
3− * Copyright (C) 2020 UBports Foundation.
4 *
3 *
5 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -15,50 +14,20 @@
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
15 */
17
16
18−#include <memory>
17+
19−#include <QFutureWatcher>
20#include <unity/shell/launcher/AppDrawerModelInterface.h>
18#include <unity/shell/launcher/AppDrawerModelInterface.h>
21
19
22#include "launcheritem.h"
20#include "launcheritem.h"
23
21
24−class UalWrapper;
25−class XdgWatcher;
26−
27class AppDrawerModel: public AppDrawerModelInterface
22class AppDrawerModel: public AppDrawerModelInterface
28{
23{
29 Q_OBJECT
24 Q_OBJECT
30− // TODO: Add this to AppDrawerModelInterface in unity-api.
31− // Or, better yet, remove AppDrawerModelInterface from unity-api.
32− Q_PROPERTY(bool refreshing READ refreshing NOTIFY refreshingChanged)
33public:
25public:
34 AppDrawerModel(QObject* parent = nullptr);
26 AppDrawerModel(QObject* parent = nullptr);
35
27
36 int rowCount(const QModelIndex &parent) const override;
28 int rowCount(const QModelIndex &parent) const override;
37 QVariant data(const QModelIndex &index, int role) const override;
29 QVariant data(const QModelIndex &index, int role) const override;
38
30
39− // TODO: add these to AppDrawerModelInterface too.
40− bool refreshing();
41− Q_INVOKABLE void refresh();
42−
43−Q_SIGNALS:
44− void refreshingChanged();
45−
46−private Q_SLOTS:
47− void appAdded(const QString &appId);
48− void appRemoved(const QString &appId);
49− void appInfoChanged(const QString &appId);
50−
51− void onRefreshFinished();
52−
53private:
31private:
54− // Using shared_ptr is unavoidable in order to share the refresh result
55− // from the worker thread safely without a memory leak, in case the model
56− // is destructed before the worker finishes.
57− typedef QList<std::shared_ptr<LauncherItem>> ItemList;
32+ QList<LauncherItem*> m_list;
58−
59− ItemList m_list;
60− UalWrapper *m_ual;
61− XdgWatcher *m_xdgWatcher;
62− QFutureWatcher<ItemList> m_refreshFutureWatcher;
63− bool m_refreshing;
64};
33};
plugins/Unity/Launcher/launcheritem.cpp+7−43
@@ -35,8 +35,10 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
35 m_countVisible(false),
35 m_countVisible(false),
36 m_focused(false),
36 m_focused(false),
37 m_alerting(false),
37 m_alerting(false),
38+ m_surfaceCount(0),
38 m_quickList(new QuickListModel(this))
39 m_quickList(new QuickListModel(this))
39{
40{
41+ Q_ASSERT(parent != nullptr);
40 QuickListEntry nameAction;
42 QuickListEntry nameAction;
41 nameAction.setActionId(QStringLiteral("launch_item"));
43 nameAction.setActionId(QStringLiteral("launch_item"));
42 nameAction.setText(m_name);
44 nameAction.setText(m_name);
@@ -46,13 +48,11 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
46 QuickListEntry pinningAction;
48 QuickListEntry pinningAction;
47 pinningAction.setActionId(QStringLiteral("pin_item"));
49 pinningAction.setActionId(QStringLiteral("pin_item"));
48 pinningAction.setText(gettext("Pin shortcut"));
50 pinningAction.setText(gettext("Pin shortcut"));
49− pinningAction.setIsPrivate(true);
50 m_quickList->appendAction(pinningAction);
51 m_quickList->appendAction(pinningAction);
51
52
52 m_quitAction.setActionId(QStringLiteral("stop_item"));
53 m_quitAction.setActionId(QStringLiteral("stop_item"));
53 m_quitAction.setIcon(QStringLiteral("application-exit"));
54 m_quitAction.setIcon(QStringLiteral("application-exit"));
54 m_quitAction.setText(gettext("Quit"));
55 m_quitAction.setText(gettext("Quit"));
55− m_quitAction.setIsPrivate(true);
56}
56}
57
57
58QString LauncherItem::appId() const
58QString LauncherItem::appId() const
@@ -120,7 +120,6 @@ void LauncherItem::setPinned(bool pinned)
120 QuickListEntry entry;
120 QuickListEntry entry;
121 entry.setActionId(QStringLiteral("pin_item"));
121 entry.setActionId(QStringLiteral("pin_item"));
122 entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
122 entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
123− entry.setIsPrivate(true);
124 m_quickList->updateAction(entry);
123 m_quickList->updateAction(entry);
125}
124}
126
125
@@ -222,49 +221,14 @@ void LauncherItem::setAlerting(bool alerting)
222
221
223int LauncherItem::surfaceCount() const
222int LauncherItem::surfaceCount() const
224{
223{
225− return m_surfaces.count();
224+ return m_surfaceCount;
226}
225}
227
226
228−void LauncherItem::setSurfaces(const QList<QPair<QString, QString> > &surfaces)
227+void LauncherItem::setSurfaceCount(int surfaceCount)
229{
228{
230− if (m_surfaces != surfaces) {
229+ if (m_surfaceCount != surfaceCount) {
231− m_surfaces = surfaces;
230+ m_surfaceCount = surfaceCount;
232−
233− QList<QuickListEntry> removedEntries;
234− for (int i = 0; i < m_quickList->rowCount(); ++i) {
235− QuickListEntry entry = m_quickList->get(i);
236− if (entry.actionId().startsWith(QStringLiteral("surface_"))) {
237− removedEntries.append(entry);
238− }
239− }
240− Q_FOREACH (const QuickListEntry &entry, removedEntries) {
241− m_quickList->removeAction(entry);
242− }
243− for (int i = 0; i < surfaces.count(); ++i) {
244− QuickListEntry entry;
245− entry.setActionId(QStringLiteral("surface_") + surfaces.at(i).first);
246− entry.setText(surfaces.at(i).second);
247− entry.setIsPrivate(true);
248− if (i == surfaces.count() - 1) {
249− entry.setHasSeparator(true);
250− }
251− m_quickList->insertAction(entry, i + 1);
252− }
253−
254− Q_EMIT surfaceCountChanged(m_surfaces.count());
231+ Q_EMIT surfaceCountChanged(surfaceCount);
255− }
256−}
257−
258−uint LauncherItem::popularity() const
259−{
260− return m_popularity;
261−}
262−
263−void LauncherItem::setPopularity(uint popularity)
264−{
265− if (m_popularity != popularity) {
266− m_popularity = popularity;
267− Q_EMIT popularityChanged(popularity);
268 }
232 }
269}
233}
270
234
plugins/Unity/Launcher/launcheritem.h+2−6
@@ -23,7 +23,6 @@
23#include "quicklistmodel.h"
23#include "quicklistmodel.h"
24
24
25#include <unity/shell/launcher/LauncherItemInterface.h>
25#include <unity/shell/launcher/LauncherItemInterface.h>
26−#include <unity/shell/application/MirSurfaceInterface.h>
27
26
28class QuickListModel;
27class QuickListModel;
29
28
@@ -39,7 +38,6 @@ public:
39 QString name() const override;
38 QString name() const override;
40 QString icon() const override;
39 QString icon() const override;
41 QStringList keywords() const override;
40 QStringList keywords() const override;
42− uint popularity() const override;
43 bool pinned() const override;
41 bool pinned() const override;
44 bool running() const override;
42 bool running() const override;
45 bool recent() const override;
43 bool recent() const override;
@@ -56,7 +54,6 @@ private:
56 void setName(const QString &name);
54 void setName(const QString &name);
57 void setIcon(const QString &icon);
55 void setIcon(const QString &icon);
58 void setKeywords(const QStringList &keywords);
56 void setKeywords(const QStringList &keywords);
59− void setPopularity(uint popularity);
60 void setPinned(bool pinned);
57 void setPinned(bool pinned);
61 void setRunning(bool running);
58 void setRunning(bool running);
62 void setRecent(bool recent);
59 void setRecent(bool recent);
@@ -65,14 +62,13 @@ private:
65 void setCountVisible(bool countVisible);
62 void setCountVisible(bool countVisible);
66 void setFocused(bool focused);
63 void setFocused(bool focused);
67 void setAlerting(bool alerting);
64 void setAlerting(bool alerting);
68− void setSurfaces(const QList<QPair<QString, QString >> &surfaces);
65+ void setSurfaceCount(int surfaceCount);
69
66
70private:
67private:
71 QString m_appId;
68 QString m_appId;
72 QString m_name;
69 QString m_name;
73 QString m_icon;
70 QString m_icon;
74 QStringList m_keywords;
71 QStringList m_keywords;
75− uint m_popularity;
76 bool m_pinned;
72 bool m_pinned;
77 bool m_running;
73 bool m_running;
78 bool m_recent;
74 bool m_recent;
@@ -81,7 +77,7 @@ private:
81 bool m_countVisible;
77 bool m_countVisible;
82 bool m_focused;
78 bool m_focused;
83 bool m_alerting;
79 bool m_alerting;
84− QList<QPair<QString, QString> > m_surfaces;
80+ int m_surfaceCount;
85 QuickListModel *m_quickList;
81 QuickListModel *m_quickList;
86 QuickListEntry m_quitAction;
82 QuickListEntry m_quitAction;
87
83
plugins/Unity/Launcher/launchermodel.cpp+20−51
@@ -23,7 +23,6 @@
23
23
24#include <unity/shell/application/ApplicationInfoInterface.h>
24#include <unity/shell/application/ApplicationInfoInterface.h>
25#include <unity/shell/application/MirSurfaceListInterface.h>
25#include <unity/shell/application/MirSurfaceListInterface.h>
26−#include <unity/shell/application/MirSurfaceInterface.h>
27
26
28#include <QDesktopServices>
27#include <QDesktopServices>
29#include <QDebug>
28#include <QDebug>
@@ -167,7 +166,6 @@ void LauncherModel::pin(const QString &appId, int index)
167 appInfo.icon,
166 appInfo.icon,
168 this);
167 this);
169 item->setPinned(true);
168 item->setPinned(true);
170− item->setPopularity(appInfo.popularity);
171 m_list.insert(index, item);
169 m_list.insert(index, item);
172 endInsertRows();
170 endInsertRows();
173 }
171 }
@@ -200,26 +198,12 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
200 } else {
198 } else {
201 pin(appId);
199 pin(appId);
202 }
200 }
203− } else if (actionId == QStringLiteral("launch_item")) {
201+ } else if (actionId == QLatin1String("launch_item")) {
204 QDesktopServices::openUrl(getUrlForAppId(appId));
202 QDesktopServices::openUrl(getUrlForAppId(appId));
205− } else if (actionId == QStringLiteral("stop_item")) { // Quit
203+ } else if (actionId == QLatin1String("stop_item")) { // Quit
206 if (m_appManager) {
204 if (m_appManager) {
207 m_appManager->stopApplication(appId);
205 m_appManager->stopApplication(appId);
208 }
206 }
209− } else if (actionId.startsWith(QStringLiteral("surface_"))){
210− ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
211− if (appInfo) {
212− for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
213− MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
214− QString id = actionId;
215− id.remove(QRegExp("^surface_"));
216− if (id == iface->persistentId()) {
217− iface->activate();
218− }
219− }
220− } else {
221− qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
222− }
223 // Nope, we don't know this action, let the backend forward it to the application
207 // Nope, we don't know this action, let the backend forward it to the application
224 } else {
208 } else {
225 // TODO: forward quicklist action to app, possibly via m_dbusIface
209 // TODO: forward quicklist action to app, possibly via m_dbusIface
@@ -230,6 +214,7 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
230void LauncherModel::setUser(const QString &username)
214void LauncherModel::setUser(const QString &username)
231{
215{
232 Q_UNUSED(username)
216 Q_UNUSED(username)
217+ qWarning() << "This backend doesn't support multiple users";
233}
218}
234
219
235QString LauncherModel::getUrlForAppId(const QString &appId) const
220QString LauncherModel::getUrlForAppId(const QString &appId) const
@@ -521,6 +506,11 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
521 return;
506 return;
522 }
507 }
523
508
509+ if (app->appId() == QLatin1String("unity8-dash")) {
510+ // Not adding the dash app
511+ return;
512+ }
513+
524 const int itemIndex = findApplication(app->appId());
514 const int itemIndex = findApplication(app->appId());
525 if (itemIndex != -1) {
515 if (itemIndex != -1) {
526 LauncherItem *item = m_list.at(itemIndex);
516 LauncherItem *item = m_list.at(itemIndex);
@@ -528,61 +518,40 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
528 item->setRecent(true);
518 item->setRecent(true);
529 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
519 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
530 }
520 }
521+ if (item->surfaceCount() != app->surfaceCount()) {
522+ item->setSurfaceCount(app->surfaceCount());
523+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleSurfaceCount});
524+ }
525+
531 item->setRunning(true);
526 item->setRunning(true);
532 } else {
527 } else {
533 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
528 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
534 item->setRecent(true);
529 item->setRecent(true);
535 item->setRunning(true);
530 item->setRunning(true);
536 item->setFocused(app->focused());
531 item->setFocused(app->focused());
532+ item->setSurfaceCount(app->surfaceCount());
537 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
533 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
538 m_list.append(item);
534 m_list.append(item);
539 endInsertRows();
535 endInsertRows();
540 }
536 }
541− connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::updateSurfaceList);
537+ connect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
542 m_asAdapter->syncItems(m_list);
538 m_asAdapter->syncItems(m_list);
543 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
539 Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
544}
540}
545
541
546−void LauncherModel::updateSurfaceList()
542+void LauncherModel::applicationSurfaceCountChanged(int count)
547{
543{
548 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
544 ApplicationInfoInterface *app = static_cast<ApplicationInfoInterface*>(sender());
549− updateSurfaceListForApp(app);
550−}
551−
552−void LauncherModel::updateSurfaceListForSurface()
553−{
554− MirSurfaceInterface *iface = static_cast<MirSurfaceInterface*>(sender());
555− ApplicationInfoInterface* app = m_appManager->findApplication(iface->appId());
556− if (!app) {
557− return;
558− }
559− updateSurfaceListForApp(app);
560−}
561−
562−void LauncherModel::updateSurfaceListForApp(ApplicationInfoInterface* app)
563−{
564 int idx = findApplication(app->appId());
545 int idx = findApplication(app->appId());
565 if (idx < 0) {
546 if (idx < 0) {
566 qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
547 qWarning() << "Received a surface count changed event from an app that's not in the Launcher model";
567 return;
548 return;
568 }
549 }
569 LauncherItem *item = m_list.at(idx);
550 LauncherItem *item = m_list.at(idx);
570− QList<QPair<QString, QString> > surfaces;
551+ if (item->surfaceCount() != count) {
571− for (int i = 0; i < app->surfaceList()->count(); ++i) {
552+ item->setSurfaceCount(count);
572− MirSurfaceInterface* iface = app->surfaceList()->get(i);
553+ Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
573− if (iface->type() == Mir::NormalType || iface->type() == Mir::DialogType) {
574− // Avoid duplicate connections, so let's just disconnect first to be sure
575− disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
576− connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
577− QString name = iface->name();
578− if (name.isEmpty()) {
579− name = app->name();
580− }
581− surfaces.append({iface->persistentId(), name});
582− }
583 }
554 }
584− item->setSurfaces(surfaces);
585− Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
586}
555}
587
556
588void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
557void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
@@ -603,7 +572,7 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
603 return;
572 return;
604 }
573 }
605
574
606− disconnect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::updateSurfaceList);
575+ disconnect(app, &ApplicationInfoInterface::surfaceCountChanged, this, &LauncherModel::applicationSurfaceCountChanged);
607
576
608 LauncherItem * item = m_list.at(appIndex);
577 LauncherItem * item = m_list.at(appIndex);
609
578
plugins/Unity/Launcher/launchermodel.h+1−3
@@ -75,9 +75,7 @@ private Q_SLOTS:
75 void applicationAdded(const QModelIndex &parent, int row);
75 void applicationAdded(const QModelIndex &parent, int row);
76 void applicationRemoved(const QModelIndex &parent, int row);
76 void applicationRemoved(const QModelIndex &parent, int row);
77 void focusedAppIdChanged();
77 void focusedAppIdChanged();
78− void updateSurfaceList();
78+ void applicationSurfaceCountChanged(int);
79− void updateSurfaceListForApp(ApplicationInfoInterface *app);
80− void updateSurfaceListForSurface();
81
79
82private:
80private:
83 QList<LauncherItem*> m_list;
81 QList<LauncherItem*> m_list;
plugins/Unity/Launcher/quicklistentry.cpp−11
@@ -20,7 +20,6 @@
20
20
21QuickListEntry::QuickListEntry()
21QuickListEntry::QuickListEntry()
22 : m_hasSeparator(false)
22 : m_hasSeparator(false)
23− , m_isPrivate(false)
24{
23{
25}
24}
26
25
@@ -73,13 +72,3 @@ bool QuickListEntry::operator==(const QuickListEntry &other)
73{
72{
74 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
73 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
75}
74}
76−
77−bool QuickListEntry::isPrivate() const
78−{
79− return m_isPrivate;
80−}
81−
82−void QuickListEntry::setIsPrivate(bool isPrivate)
83−{
84− m_isPrivate = isPrivate;
85−}
plugins/Unity/Launcher/quicklistentry.h−4
@@ -42,15 +42,11 @@ public:
42
42
43 bool operator==(const QuickListEntry & other);
43 bool operator==(const QuickListEntry & other);
44
44
45− bool isPrivate() const;
46− void setIsPrivate(bool isPrivate);
47−
48private:
45private:
49 QString m_actionId;
46 QString m_actionId;
50 QString m_text;
47 QString m_text;
51 QString m_icon;
48 QString m_icon;
52 bool m_hasSeparator;
49 bool m_hasSeparator;
53− bool m_isPrivate;
54};
50};
55
51
56#endif // QUICKLISTENTRY
52#endif // QUICKLISTENTRY
plugins/Unity/Launcher/quicklistmodel.cpp−9
@@ -37,13 +37,6 @@ void QuickListModel::appendAction(const QuickListEntry &entry)
37 endInsertRows();
37 endInsertRows();
38}
38}
39
39
40−void QuickListModel::insertAction(const QuickListEntry &entry, int index)
41−{
42− beginInsertRows(QModelIndex(), index, index);
43− m_list.insert(index, entry);
44− endInsertRows();
45−}
46−
47void QuickListModel::updateAction(const QuickListEntry &entry)
40void QuickListModel::updateAction(const QuickListEntry &entry)
48{
41{
49 for (int i = 0; i < m_list.count(); ++i) {
42 for (int i = 0; i < m_list.count(); ++i) {
@@ -88,8 +81,6 @@ QVariant QuickListModel::data(const QModelIndex &index, int role) const
88 return m_list.at(index.row()).clickable();
81 return m_list.at(index.row()).clickable();
89 case RoleHasSeparator:
82 case RoleHasSeparator:
90 return m_list.at(index.row()).hasSeparator();
83 return m_list.at(index.row()).hasSeparator();
91− case RoleIsPrivate:
92− return m_list.at(index.row()).isPrivate();
93 }
84 }
94 return QVariant();
85 return QVariant();
95}
86}
plugins/Unity/Launcher/quicklistmodel.h−1
@@ -36,7 +36,6 @@ public:
36 ~QuickListModel();
36 ~QuickListModel();
37
37
38 void appendAction(const QuickListEntry &entry);
38 void appendAction(const QuickListEntry &entry);
39− void insertAction(const QuickListEntry &entry, int index);
40
39
41 /**
40 /**
42 * @brief Update an existing action
41 * @brief Update an existing action
plugins/Unity/Launcher/ualwrapper.cpp+2−3
@@ -24,6 +24,7 @@ using namespace ubuntu::app_launch;
24UalWrapper::UalWrapper(QObject *parent):
24UalWrapper::UalWrapper(QObject *parent):
25 QObject(parent)
25 QObject(parent)
26{
26{
27+
27}
28}
28
29
29QStringList UalWrapper::installedApps()
30QStringList UalWrapper::installedApps()
@@ -38,7 +39,7 @@ QStringList UalWrapper::installedApps()
38 }
39 }
39 }
40 }
40 } catch (const std::runtime_error &e) {
41 } catch (const std::runtime_error &e) {
41− qWarning() << "ubuntu-app-launch threw an exception listing apps:" << e.what();
42+ qWarning() << "ubuntu-all-launch threw an exception listing apps:" << e.what();
42 }
43 }
43
44
44 return appIds;
45 return appIds;
@@ -58,13 +59,11 @@ UalWrapper::AppInfo UalWrapper::getApplicationInfo(const QString &appId)
58 std::shared_ptr<Application> ualApp;
59 std::shared_ptr<Application> ualApp;
59 ualApp = Application::create(ualAppId, Registry::getDefault());
60 ualApp = Application::create(ualAppId, Registry::getDefault());
60
61
61− info.appId = appId;
62 info.name = QString::fromStdString(ualApp->info()->name());
62 info.name = QString::fromStdString(ualApp->info()->name());
63 info.icon = QString::fromStdString(ualApp->info()->iconPath());
63 info.icon = QString::fromStdString(ualApp->info()->iconPath());
64 for (const std::string &keyword : ualApp->info()->keywords().value()) {
64 for (const std::string &keyword : ualApp->info()->keywords().value()) {
65 info.keywords << QString::fromStdString(keyword);
65 info.keywords << QString::fromStdString(keyword);
66 }
66 }
67− //info.popularity = ualApp->info()->popularity();
68 info.valid = true;
67 info.valid = true;
69 } catch (const std::runtime_error &e) {
68 } catch (const std::runtime_error &e) {
70 qWarning() << "ubuntu-app-launch threw an exception getting app info for appId:" << appId << ":" << e.what();
69 qWarning() << "ubuntu-app-launch threw an exception getting app info for appId:" << appId << ":" << e.what();
plugins/Unity/Launcher/ualwrapper.h+1−2
@@ -21,16 +21,15 @@ class UalWrapper: public QObject
21 Q_OBJECT
21 Q_OBJECT
22public:
22public:
23 struct AppInfo {
23 struct AppInfo {
24− QString appId;
25 bool valid = false;
24 bool valid = false;
26 QString name;
25 QString name;
27 QString icon;
26 QString icon;
28 QStringList keywords;
27 QStringList keywords;
29− uint popularity = 0;
30 };
28 };
31
29
32 UalWrapper(QObject* parent = nullptr);
30 UalWrapper(QObject* parent = nullptr);
33
31
34 static QStringList installedApps();
32 static QStringList installedApps();
35 static AppInfo getApplicationInfo(const QString &appId);
33 static AppInfo getApplicationInfo(const QString &appId);
34+
36};
35};
plugins/Unity/Launcher/xdgwatcher.cppdeleted−129
@@ -1,129 +0,0 @@
1−/*
2− * Copyright (C) 2019 UBports Foundation
3− * Author(s): Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published by
7− * the Free Software Foundation; version 3.
8− *
9− * This program is distributed in the hope that it will be useful,
10− * but WITHOUT ANY WARRANTY; without even the implied warranty of
11− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12− * GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#include "xdgwatcher.h"
19−
20−#include <QDebug>
21−#include <QDir>
22−#include <QFile>
23−#include <QStandardPaths>
24−#include <QTextStream>
25−
26−XdgWatcher::XdgWatcher(QObject* parent)
27− : QObject(parent),
28− m_watcher(new QFileSystemWatcher(this))
29−{
30− connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &XdgWatcher::onDirectoryChanged);
31− connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &XdgWatcher::onFileChanged);
32−
33− const auto paths = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
34− for (const auto &path: paths) {
35− const auto qdir = QDir(path);
36− if (!qdir.exists()) {
37− continue;
38− }
39−
40− // Add the path itself to watch for newly added apps
41− m_watcher->addPath(path);
42−
43− // Add watcher for eatch app to watch for changes
44− const auto files = qdir.entryInfoList(QDir::Files);
45− for (const auto &file: files) {
46− if (file.suffix() == "desktop") {
47− const auto path = file.absoluteFilePath();
48− m_watcher->addPath(path);
49− m_registry.insert(path, getAppId(file));
50− }
51− }
52− }
53−}
54−
55−// "Ubuntu style" appID is filename without versionNumber after last "_"
56−const QString XdgWatcher::stripAppIdVersion(const QString rawAppID) const {
57− auto appIdComponents = rawAppID.split("_");
58− appIdComponents.removeLast();
59− return appIdComponents.join("_");
60−}
61−
62−// Standard appID see:
63−// https://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id
64−const QString XdgWatcher::toStandardAppId(const QFileInfo fileInfo) const {
65− const auto paths = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
66− for (const auto &path: paths) {
67− if (fileInfo.absolutePath() == path) {
68− break;
69− }
70− if (fileInfo.absolutePath().contains(path)) {
71− auto fileStr = fileInfo.absoluteFilePath();
72− fileStr.replace(path, "");
73− fileStr.replace("/", "-");
74− fileStr.replace(".desktop", "");
75− return fileStr;
76− }
77− }
78− return fileInfo.completeBaseName();
79−}
80−
81−const QString XdgWatcher::getAppId(const QFileInfo fileInfo) const {
82− // We need to open the file to check if its and Ual application
83− // as we cant just rely on the app name as "normal" apps can also
84− // contain 3 _ causing us to belive its an ubuntu app
85− // Example kde_org_kate would become kde_org
86− QFile qFile(fileInfo.absoluteFilePath());
87− qFile.open(QIODevice::ReadOnly);
88− QTextStream fileStream(&qFile);
89− QString line;
90− while (fileStream.readLineInto(&line)) {
91− if (line.startsWith("X-Ubuntu-Application-ID=")) {
92− auto rawAppID = line.replace("X-Ubuntu-Application-ID=", "");
93− qFile.close();
94− return stripAppIdVersion(rawAppID);
95− }
96− }
97− qFile.close();
98−
99− // If it's not an "Ubuntu" appID, we follow freedesktop standard
100− return toStandardAppId(fileInfo);
101−}
102−
103−// Watch for newly added apps
104−void XdgWatcher::onDirectoryChanged(const QString &path) {
105− const auto files = QDir(path).entryInfoList(QDir::Files);
106− const auto watchedFiles = m_watcher->files();
107− for (const auto &file: files) {
108− const auto appPath = file.absoluteFilePath();
109− if (file.suffix() == "desktop" && !watchedFiles.contains(appPath)) {
110− m_watcher->addPath(appPath);
111−
112− const auto appId = getAppId(file);
113− m_registry.insert(appPath, appId);
114− Q_EMIT appAdded(appId);
115− }
116− }
117−}
118−
119−void XdgWatcher::onFileChanged(const QString &path) {
120− QFileInfo file(path);
121− if (file.exists()) {
122− // The file exists, this must be an modify event
123− Q_EMIT appInfoChanged(m_registry.value(path));
124− } else {
125− // File does not exist, assume this is an remove event.
126− // onDirectoryChanged will handle rename event
127− Q_EMIT appRemoved(m_registry.take(path));
128− }
129−}
plugins/Unity/Launcher/xdgwatcher.hdeleted−46
@@ -1,46 +0,0 @@
1−/*
2− * Copyright (C) 2019 UBports Foundation
3− * Author(s): Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published by
7− * the Free Software Foundation; version 3.
8− *
9− * This program is distributed in the hope that it will be useful,
10− * but WITHOUT ANY WARRANTY; without even the implied warranty of
11− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12− * GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#include <QFileSystemWatcher>
19−#include <QHash>
20−#include <QFileInfo>
21−
22−class QFileInfo;
23−
24−class XdgWatcher: public QObject
25−{
26− Q_OBJECT
27−public:
28− XdgWatcher(QObject* parent = nullptr);
29−
30−Q_SIGNALS:
31− void appAdded(const QString &appId);
32− void appRemoved(const QString &appId);
33− void appInfoChanged(const QString &appId);
34−
35−private Q_SLOTS:
36− void onDirectoryChanged(const QString &path);
37− void onFileChanged(const QString &path);
38−
39−private:
40− const QString toStandardAppId(const QFileInfo fileInfo) const;
41− const QString getAppId(const QFileInfo file) const;
42− const QString stripAppIdVersion(const QString rawAppID) const;
43−
44− QFileSystemWatcher* m_watcher;
45− QHash<const QString, QString> m_registry;
46−};
plugins/Unity/Platform/CMakeLists.txt+1−1
@@ -6,6 +6,6 @@ set(platformplugin_SRCS
6
6
7add_library(Platform-qml SHARED ${platformplugin_SRCS})
7add_library(Platform-qml SHARED ${platformplugin_SRCS})
8
8
9−target_link_libraries(Platform-qml Qt5::DBus Qt5::Qml)
9+qt5_use_modules(Platform-qml DBus Qml)
10
10
11add_unity8_plugin(Unity.Platform 1.0 Unity/Platform TARGETS Platform-qml)
11add_unity8_plugin(Unity.Platform 1.0 Unity/Platform TARGETS Platform-qml)
plugins/Unity/Platform/platform.cpp+2−16
@@ -17,11 +17,9 @@
17#include "platform.h"
17#include "platform.h"
18
18
19#include <QDBusConnection>
19#include <QDBusConnection>
20−#include <QSet>
21−#include <QString>
22
20
23Platform::Platform(QObject *parent)
21Platform::Platform(QObject *parent)
24− : QObject(parent), m_isPC(true), m_isMultiSession(true)
22+ : QObject(parent)
25{
23{
26 QMetaObject::invokeMethod(this, "init");
24 QMetaObject::invokeMethod(this, "init");
27}
25}
@@ -33,20 +31,8 @@ void Platform::init()
33 QDBusInterface seatIface("org.freedesktop.login1", "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat",
31 QDBusInterface seatIface("org.freedesktop.login1", "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat",
34 QDBusConnection::systemBus(), this);
32 QDBusConnection::systemBus(), this);
35
33
36− // From the source at https://cgit.freedesktop.org/systemd/systemd/tree/src/hostname/hostnamed.c#n130
37− // "vm\0"
38− // "container\0"
39− // "desktop\0"
40− // "laptop\0"
41− // "server\0"
42− // "tablet\0"
43− // "handset\0"
44− // "watch\0"
45− // "embedded\0",
46 m_chassis = iface.property("Chassis").toString();
34 m_chassis = iface.property("Chassis").toString();
47−
35+ m_isPC = (m_chassis == "desktop" || m_chassis == "laptop" || m_chassis == "server");
48− // A PC is not a handset, tablet or watch.
49− m_isPC = !QSet<QString>{"handset", "tablet", "watch"}.contains(m_chassis);
50 m_isMultiSession = seatIface.property("CanMultiSession").toBool() && seatIface.property("CanGraphical").toBool();
36 m_isMultiSession = seatIface.property("CanMultiSession").toBool() && seatIface.property("CanGraphical").toBool();
51}
37}
52
38
plugins/Unity/Session/CMakeLists.txt+1−1
@@ -18,8 +18,8 @@ add_library(UnitySession-qml MODULE
18 ${QMLSESSIONPLUGIN_SRC}
18 ${QMLSESSIONPLUGIN_SRC}
19 )
19 )
20
20
21+qt5_use_modules(UnitySession-qml DBus Qml)
21target_link_libraries(UnitySession-qml
22target_link_libraries(UnitySession-qml
22− Qt5::DBus Qt5::Qml
23 unity8-private
23 unity8-private
24 ${GIO_LDFLAGS}
24 ${GIO_LDFLAGS}
25 ${GLIB_LIBRARIES}
25 ${GLIB_LIBRARIES}
plugins/Unity/Session/dbusunitysessionservice.cpp+4−75
@@ -18,7 +18,6 @@
18#include "dbusunitysessionservice.h"
18#include "dbusunitysessionservice.h"
19
19
20// system
20// system
21−#include <grp.h>
22#include <sys/types.h>
21#include <sys/types.h>
23#include <unistd.h>
22#include <unistd.h>
24#include <pwd.h>
23#include <pwd.h>
@@ -212,23 +211,6 @@ public:
212 QDBusConnection::SM_BUSNAME().asyncCall(msg);
211 QDBusConnection::SM_BUSNAME().asyncCall(msg);
213 }
212 }
214
213
215− bool isUserInGroup(const QString &user, const QString &groupName) const
216− {
217− auto group = getgrnam(groupName.toUtf8().data());
218−
219− if (group && group->gr_mem)
220− {
221− for (int i = 0; group->gr_mem[i]; ++i)
222− {
223− if (g_strcmp0(group->gr_mem[i], user.toUtf8().data()) == 0) {
224− return true;
225− }
226− }
227− }
228−
229− return false;
230− }
231−
232private Q_SLOTS:
214private Q_SLOTS:
233 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
215 void onPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps)
234 {
216 {
@@ -315,13 +297,7 @@ bool DBusUnitySessionService::CanShutdown() const
315
297
316bool DBusUnitySessionService::CanLock() const
298bool DBusUnitySessionService::CanLock() const
317{
299{
318− auto user = UserName();
319− if (user.startsWith(QStringLiteral("guest-")) ||
320− d->isUserInGroup(user, QStringLiteral("nopasswdlogin"))) {
321− return false;
322− } else {
323− return true;
300+ return true; // FIXME
324− }
325}
301}
326
302
327QString DBusUnitySessionService::UserName() const
303QString DBusUnitySessionService::UserName() const
@@ -359,10 +335,8 @@ void DBusUnitySessionService::PromptLock()
359 // Prompt as in quick. No locking animation needed. Usually used by
335 // Prompt as in quick. No locking animation needed. Usually used by
360 // indicator-session in combination with a switch to greeter or other
336 // indicator-session in combination with a switch to greeter or other
361 // user session.
337 // user session.
362− if (CanLock()) {
363− Q_EMIT LockRequested();
338+ Q_EMIT LockRequested();
364− Q_EMIT lockRequested();
339+ Q_EMIT lockRequested();
365− }
366}
340}
367
341
368void DBusUnitySessionService::Lock()
342void DBusUnitySessionService::Lock()
@@ -494,56 +468,11 @@ void performAsyncUnityCall(const QString &method)
494
468
495
469
496DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
470DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
497− : UnityDBusObject(QStringLiteral("/org/gnome/SessionManager"), QStringLiteral("org.gnome.SessionManager"))
498−{
499−}
500−
501−void DBusGnomeSessionManagerWrapper::Logout(quint32 mode)
502−{
503− auto call = QStringLiteral("RequestLogout");
504−
505− // These modes are documented as bitwise flags, not an enum, even though
506− // they only ever seem to be used as enums.
507−
508− if (mode & 1) // without dialog
509− call = QStringLiteral("Logout");
510− if (mode & 2) // without dialog, ignoring inhibitors (which we don't have)
511− call = QStringLiteral("Logout");
512−
513− performAsyncUnityCall(call);
514−}
515−
516−void DBusGnomeSessionManagerWrapper::Reboot()
517−{
518− // GNOME's Reboot means with dialog (they use Request differently than us).
519− performAsyncUnityCall(QStringLiteral("RequestReboot"));
520−}
521−
522−void DBusGnomeSessionManagerWrapper::RequestReboot()
523−{
524− // GNOME's RequestReboot means no dialog (they use Request differently than us).
525− performAsyncUnityCall(QStringLiteral("Reboot"));
526−}
527−
528−void DBusGnomeSessionManagerWrapper::RequestShutdown()
529−{
530− // GNOME's RequestShutdown means no dialog (they use Request differently than us).
531− performAsyncUnityCall(QStringLiteral("Shutdown"));
532−}
533−
534−void DBusGnomeSessionManagerWrapper::Shutdown()
535−{
536− // GNOME's Shutdown means with dialog (they use Request differently than us).
537− performAsyncUnityCall(QStringLiteral("RequestShutdown"));
538−}
539−
540−
541−DBusGnomeSessionManagerDialogWrapper::DBusGnomeSessionManagerDialogWrapper()
542 : UnityDBusObject(QStringLiteral("/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral("com.canonical.Unity"))
471 : UnityDBusObject(QStringLiteral("/org/gnome/SessionManager/EndSessionDialog"), QStringLiteral("com.canonical.Unity"))
543{
472{
544}
473}
545
474
546−void DBusGnomeSessionManagerDialogWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
475+void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
547{
476{
548 Q_UNUSED(arg_1);
477 Q_UNUSED(arg_1);
549 Q_UNUSED(max_wait);
478 Q_UNUSED(max_wait);
plugins/Unity/Session/dbusunitysessionservice.h+4−18
@@ -270,31 +270,17 @@ private:
270class DBusGnomeSessionManagerWrapper : public UnityDBusObject
270class DBusGnomeSessionManagerWrapper : public UnityDBusObject
271{
271{
272 Q_OBJECT
272 Q_OBJECT
273− Q_CLASSINFO("D-Bus Interface", "org.gnome.SessionManager")
273+ Q_CLASSINFO("D-Bus Interface", "org.gnome.SessionManager.EndSessionDialog")
274
274
275public:
275public:
276 DBusGnomeSessionManagerWrapper();
276 DBusGnomeSessionManagerWrapper();
277 ~DBusGnomeSessionManagerWrapper() = default;
277 ~DBusGnomeSessionManagerWrapper() = default;
278
278
279−public Q_SLOTS:
280− Q_SCRIPTABLE void Logout(quint32 mode);
281− Q_SCRIPTABLE void Reboot();
282− Q_SCRIPTABLE void RequestReboot();
283− Q_SCRIPTABLE void RequestShutdown();
284− Q_SCRIPTABLE void Shutdown();
285−};
286−
287−class DBusGnomeSessionManagerDialogWrapper : public UnityDBusObject
288−{
289− Q_OBJECT
290− Q_CLASSINFO("D-Bus Interface", "org.gnome.SessionManager.EndSessionDialog")
291−
292−public:
293− DBusGnomeSessionManagerDialogWrapper();
294− ~DBusGnomeSessionManagerDialogWrapper() = default;
295−
296public Q_SLOTS:
279public Q_SLOTS:
297 Q_SCRIPTABLE void Open(const unsigned int type, const unsigned int arg_1, const unsigned int max_wait, const QList<QDBusObjectPath> &inhibitors);
280 Q_SCRIPTABLE void Open(const unsigned int type, const unsigned int arg_1, const unsigned int max_wait, const QList<QDBusObjectPath> &inhibitors);
281+
282+private:
283+ void performAsyncCall(const QString &method);
298};
284};
299
285
300class DBusGnomeScreensaverWrapper: public UnityDBusObject
286class DBusGnomeScreensaverWrapper: public UnityDBusObject
plugins/Unity/Session/plugin.cpp−1
@@ -26,7 +26,6 @@
26
26
27static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
27static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
28{
28{
29− new DBusGnomeSessionManagerDialogWrapper();
30 new DBusGnomeSessionManagerWrapper();
29 new DBusGnomeSessionManagerWrapper();
31 new DBusGnomeScreensaverWrapper();
30 new DBusGnomeScreensaverWrapper();
32 new DBusScreensaverWrapper();
31 new DBusScreensaverWrapper();
plugins/Utils/CMakeLists.txt+4−6
@@ -7,6 +7,7 @@ include_directories(
7 SYSTEM
7 SYSTEM
8 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
8 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
9 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
9 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
10+ ${GIO_INCLUDE_DIRS}
10)
11)
11
12
12set(QMLPLUGIN_SRC
13set(QMLPLUGIN_SRC
@@ -33,9 +34,6 @@ set(QMLPLUGIN_SRC
33 deviceconfigparser.cpp
34 deviceconfigparser.cpp
34 globalfunctions.cpp
35 globalfunctions.cpp
35 URLDispatcher.cpp
36 URLDispatcher.cpp
36− tabfocusfence.cpp
37− expressionfiltermodel.cpp
38− quicklistproxymodel.cpp
39 plugin.cpp
37 plugin.cpp
40 )
38 )
41
39
@@ -43,9 +41,7 @@ add_library(Utils-qml SHARED
43 ${QMLPLUGIN_SRC}
41 ${QMLPLUGIN_SRC}
44 )
42 )
45
43
46−target_link_libraries(Utils-qml
44+target_link_libraries(Utils-qml ${GIO_LDFLAGS})
47− Qt5::Qml Qt5::Quick Qt5::DBus Qt5::Network Qt5::Gui Qt5::Sql Qt5::Concurrent
48− )
49
45
50# Because this is an internal support library, we want
46# Because this is an internal support library, we want
51# to expose all symbols in it. Consider changing this
47# to expose all symbols in it. Consider changing this
@@ -53,4 +49,6 @@ target_link_libraries(Utils-qml
53# files directly in targets.
49# files directly in targets.
54set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
50set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
55
51
52+qt5_use_modules(Utils-qml Qml Quick DBus Network Gui Sql Concurrent)
53+
56add_unity8_plugin(Utils 0.1 Utils TARGETS Utils-qml)
54add_unity8_plugin(Utils 0.1 Utils TARGETS Utils-qml)
plugins/Utils/URLDispatcher.cpp+2−5
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
17#include "URLDispatcher.h"
17#include "URLDispatcher.h"
18
18
19#include <QDBusConnection>
19#include <QDBusConnection>
20−#include <QDebug>
21
20
22class URLDispatcherInterface : public QObject
21class URLDispatcherInterface : public QObject
23{
22{
@@ -64,9 +63,7 @@ void URLDispatcher::setActive(bool value)
64 connection.registerObject(QStringLiteral("/com/canonical/URLDispatcher"),
63 connection.registerObject(QStringLiteral("/com/canonical/URLDispatcher"),
65 dispatcher,
64 dispatcher,
66 QDBusConnection::ExportScriptableContents);
65 QDBusConnection::ExportScriptableContents);
67− if (!connection.registerService(QStringLiteral("com.canonical.URLDispatcher"))) {
66+ connection.registerService(QStringLiteral("com.canonical.URLDispatcher"));
68− qWarning() << "Unable to register DBus service com.canonical.URLDispatcher";
69− }
70 m_dispatcher = dispatcher;
67 m_dispatcher = dispatcher;
71 } else {
68 } else {
72 connection.unregisterService(QStringLiteral("com.canonical.URLDispatcher"));
69 connection.unregisterService(QStringLiteral("com.canonical.URLDispatcher"));
plugins/Utils/WindowInputMonitor.cpp−3
@@ -73,9 +73,6 @@ void WindowInputMonitor::update(QEvent *event)
73 && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
73 && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
74 m_pressedHomeKey = keyEvent->key();
74 m_pressedHomeKey = keyEvent->key();
75 m_activationTimer->start();
75 m_activationTimer->start();
76− } else if (m_pressedHomeKey != 0 && !m_homeKeys.contains(keyEvent->key())) {
77− // something else came in... cancel activation
78− m_activationTimer->stop();
79 }
76 }
80
77
81 } else if (event->type() == QEvent::KeyRelease) {
78 } else if (event->type() == QEvent::KeyRelease) {
plugins/Utils/appdrawerproxymodel.cpp+4−4
@@ -43,8 +43,8 @@ void AppDrawerProxyModel::setSource(QAbstractItemModel *source)
43 m_source = source;
43 m_source = source;
44 setSourceModel(m_source);
44 setSourceModel(m_source);
45 setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
45 setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
46− connect(m_source, &QAbstractItemModel::rowsRemoved, this, &AppDrawerProxyModel::invalidate);
46+ connect(m_source, &QAbstractItemModel::rowsRemoved, this, &AppDrawerProxyModel::invalidateFilter);
47− connect(m_source, &QAbstractItemModel::rowsInserted, this, &AppDrawerProxyModel::invalidate);
47+ connect(m_source, &QAbstractItemModel::rowsInserted, this, &AppDrawerProxyModel::invalidateFilter);
48 Q_EMIT sourceChanged();
48 Q_EMIT sourceChanged();
49 }
49 }
50}
50}
@@ -158,7 +158,7 @@ bool AppDrawerProxyModel::filterAcceptsRow(int source_row, const QModelIndex &so
158 allWords.prepend(m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString());
158 allWords.prepend(m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString());
159 bool found = false;
159 bool found = false;
160 Q_FOREACH (const QString &currentWord, allWords) {
160 Q_FOREACH (const QString &currentWord, allWords) {
161− if (currentWord.contains(m_filterString, Qt::CaseInsensitive)) {
161+ if (currentWord.startsWith(m_filterString, Qt::CaseInsensitive)) {
162 found = true;
162 found = true;
163 break;
163 break;
164 }
164 }
@@ -185,5 +185,5 @@ QString AppDrawerProxyModel::appId(int index) const
185 return adpm->appId(sourceIndex.row());
185 return adpm->appId(sourceIndex.row());
186 }
186 }
187 }
187 }
188− return QString();
188+ return nullptr;
189}
189}
plugins/Utils/deviceconfigparser.cpp−18
@@ -116,24 +116,6 @@ QString DeviceConfigParser::category() const
116 return value;
116 return value;
117}
117}
118
118
119−bool DeviceConfigParser::supportsMultiColorLed() const
120−{
121− return readBoolFromConfig("SupportsMultiColorLed", true);
122−}
123−
124−bool DeviceConfigParser::readBoolFromConfig(const QString &key, bool defaultValue) const
125−{
126− m_config->beginGroup(m_name);
127−
128− bool ret = defaultValue;
129− if (m_config->contains(key)) {
130− ret = m_config->value(key).toBool();
131− }
132−
133− m_config->endGroup();
134− return ret;
135−}
136−
137QStringList DeviceConfigParser::readOrientationsFromConfig(const QString &key) const
119QStringList DeviceConfigParser::readOrientationsFromConfig(const QString &key) const
138{
120{
139 m_config->beginGroup(m_name);
121 m_config->beginGroup(m_name);
plugins/Utils/deviceconfigparser.h−3
@@ -33,7 +33,6 @@ class DeviceConfigParser: public QObject
33 Q_PROPERTY(Qt::ScreenOrientation portraitOrientation READ portraitOrientation NOTIFY changed)
33 Q_PROPERTY(Qt::ScreenOrientation portraitOrientation READ portraitOrientation NOTIFY changed)
34 Q_PROPERTY(Qt::ScreenOrientation invertedPortraitOrientation READ invertedPortraitOrientation NOTIFY changed)
34 Q_PROPERTY(Qt::ScreenOrientation invertedPortraitOrientation READ invertedPortraitOrientation NOTIFY changed)
35 Q_PROPERTY(QString category READ category NOTIFY changed)
35 Q_PROPERTY(QString category READ category NOTIFY changed)
36− Q_PROPERTY(bool supportsMultiColorLed READ supportsMultiColorLed NOTIFY changed)
37
36
38public:
37public:
39 DeviceConfigParser(QObject *parent = nullptr);
38 DeviceConfigParser(QObject *parent = nullptr);
@@ -48,7 +47,6 @@ public:
48 Qt::ScreenOrientation portraitOrientation() const;
47 Qt::ScreenOrientation portraitOrientation() const;
49 Qt::ScreenOrientation invertedPortraitOrientation() const;
48 Qt::ScreenOrientation invertedPortraitOrientation() const;
50 QString category() const;
49 QString category() const;
51− bool supportsMultiColorLed() const;
52
50
53Q_SIGNALS:
51Q_SIGNALS:
54 void changed();
52 void changed();
@@ -60,7 +58,6 @@ private:
60 QStringList readOrientationsFromConfig(const QString &key) const;
58 QStringList readOrientationsFromConfig(const QString &key) const;
61 QString readOrientationFromConfig(const QString &key) const;
59 QString readOrientationFromConfig(const QString &key) const;
62 Qt::ScreenOrientation stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const;
60 Qt::ScreenOrientation stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const;
63− bool readBoolFromConfig(const QString &key, bool defaultValue) const;
64};
61};
65
62
66#endif
63#endif
plugins/Utils/expressionfiltermodel.cppdeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "expressionfiltermodel.h"
18−
19−ExpressionFilterModel::ExpressionFilterModel(QObject *parent)
20− : UnitySortFilterProxyModelQML(parent)
21−{
22−}
23−
24−QJSValue ExpressionFilterModel::matchExpression() const
25−{
26− return m_matchExpression;
27−}
28−
29−void ExpressionFilterModel::setMatchExpression(const QJSValue &value)
30−{
31− m_matchExpression = value;
32− invalidateFilter();
33−}
34−
35−bool
36−ExpressionFilterModel::filterAcceptsRow(int sourceRow,
37− const QModelIndex &sourceParent) const
38−{
39− if (m_matchExpression.isCallable()) {
40− QJSValueList args;
41− args << sourceRow;
42− QJSValue ret = m_matchExpression.call(args);
43− if (ret.isBool()) {
44− return ret.toBool();
45− }
46− }
47−
48− return UnitySortFilterProxyModelQML::filterAcceptsRow(sourceRow, sourceParent);
49−}
plugins/Utils/expressionfiltermodel.hdeleted−42
@@ -1,42 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef EXPRESSIONFILTERMODEL_H
18−#define EXPRESSIONFILTERMODEL_H
19−
20−#include "unitysortfilterproxymodelqml.h"
21−#include <QJSValue>
22−
23−class ExpressionFilterModel : public UnitySortFilterProxyModelQML
24−{
25− Q_OBJECT
26− Q_PROPERTY(QJSValue matchExpression READ matchExpression WRITE setMatchExpression NOTIFY matchExpressionChanged)
27−public:
28− explicit ExpressionFilterModel(QObject *parent = 0);
29−
30− bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
31−
32− QJSValue matchExpression() const;
33− void setMatchExpression(const QJSValue& value);
34−
35−Q_SIGNALS:
36− void matchExpressionChanged();
37−
38−private:
39− mutable QJSValue m_matchExpression;
40−};
41−
42−#endif // EXPRESSIONFILTERMODEL_H
plugins/Utils/plugin.cpp+1−7
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012-2017 Canonical, Ltd.
2+ * Copyright (C) 2012-2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -40,9 +40,6 @@
40#include "globalfunctions.h"
40#include "globalfunctions.h"
41#include "URLDispatcher.h"
41#include "URLDispatcher.h"
42#include "appdrawerproxymodel.h"
42#include "appdrawerproxymodel.h"
43−#include "tabfocusfence.h"
44−#include "expressionfiltermodel.h"
45−#include "quicklistproxymodel.h"
46
43
47static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
44static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
48{
45{
@@ -87,7 +84,4 @@ void UtilsPlugin::registerTypes(const char *uri)
87 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
88 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
89 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
86 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
90− qmlRegisterType<TabFocusFenceItem>(uri, 0, 1, "TabFocusFence");
91− qmlRegisterType<ExpressionFilterModel>(uri, 0, 1, "ExpressionFilterModel");
92− qmlRegisterType<QuickListProxyModel>(uri, 0, 1, "QuickListProxyModel");
93}
87}
plugins/Utils/quicklistproxymodel.cppdeleted−72
@@ -1,72 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "quicklistproxymodel.h"
18−
19−#include <QDebug>
20−
21−QuickListProxyModel::QuickListProxyModel(QObject *parent):
22− QSortFilterProxyModel(parent)
23−{
24− connect(this, &QAbstractListModel::rowsInserted, this, &QuickListProxyModel::countChanged);
25− connect(this, &QAbstractListModel::rowsRemoved, this, &QuickListProxyModel::countChanged);
26− connect(this, &QAbstractListModel::layoutChanged, this, &QuickListProxyModel::countChanged);
27−}
28−
29−QAbstractItemModel *QuickListProxyModel::source() const
30−{
31− return m_source;
32−}
33−
34−bool QuickListProxyModel::privateMode() const
35−{
36− return m_privateMode;
37−}
38−
39−void QuickListProxyModel::setPrivateMode(bool privateMode)
40−{
41− if (m_privateMode != privateMode) {
42− m_privateMode = privateMode;
43− invalidateFilter();
44− Q_EMIT privateModeChanged();
45− }
46−}
47−
48−void QuickListProxyModel::setSource(QAbstractItemModel *source)
49−{
50− if (m_source != source) {
51− m_source = source;
52− setSourceModel(m_source);
53− connect(m_source, &QAbstractItemModel::rowsRemoved, this, &QuickListProxyModel::invalidate);
54− connect(m_source, &QAbstractItemModel::rowsInserted, this, &QuickListProxyModel::invalidate);
55− Q_EMIT sourceChanged();
56− }
57−}
58−
59−int QuickListProxyModel::count() const
60−{
61− return rowCount();
62−}
63−
64−bool QuickListProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
65−{
66− Q_UNUSED(source_parent)
67−
68− if (m_privateMode) {
69− return !m_source->data(m_source->index(source_row, 0), QuickListModelInterface::RoleIsPrivate).toBool();
70− }
71− return true;
72−}
plugins/Utils/quicklistproxymodel.hdeleted−52
@@ -1,52 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QSortFilterProxyModel>
18−
19−#include <unity/shell/launcher/QuickListModelInterface.h>
20−
21−using namespace unity::shell::launcher;
22−
23−class QuickListProxyModel: public QSortFilterProxyModel
24−{
25− Q_OBJECT
26− Q_PROPERTY(QAbstractItemModel* source READ source WRITE setSource NOTIFY sourceChanged)
27− Q_PROPERTY(bool privateMode READ privateMode WRITE setPrivateMode NOTIFY privateModeChanged)
28− Q_PROPERTY(int count READ count NOTIFY countChanged)
29−
30−public:
31− QuickListProxyModel(QObject* parent = nullptr);
32−
33− QAbstractItemModel* source() const;
34− void setSource(QAbstractItemModel* source);
35−
36− bool privateMode() const;
37− void setPrivateMode(bool privateMode);
38−
39− int count() const;
40−
41−protected:
42− bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
43−
44−Q_SIGNALS:
45− void sourceChanged();
46− void privateModeChanged();
47− void countChanged();
48−
49−private:
50− QAbstractItemModel* m_source = nullptr;
51− bool m_privateMode = false;
52−};
plugins/Utils/tabfocusfence.cppdeleted−72
@@ -1,72 +0,0 @@
1−/*
2− * Copyright 2017 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15−*/
16−
17−#include "tabfocusfence.h"
18−
19−#include <private/qquickitem_p.h>
20−
21−TabFocusFenceItem::TabFocusFenceItem(QQuickItem *parent) : QQuickItem(parent)
22−{
23− QQuickItemPrivate *d = QQuickItemPrivate::get(this);
24− d->isTabFence = true;
25− setFlag(ItemIsFocusScope);
26−}
27−
28−bool TabFocusFenceItem::focusNext()
29−{
30− QQuickItem * current = scopedFocusItem();
31− if (current) {
32− QQuickItem * next = current->nextItemInFocusChain(true);
33− if (next) {
34− next->setFocus(true, Qt::TabFocusReason);
35− return true;
36− }
37− }
38− return false;
39−}
40−
41−bool TabFocusFenceItem::focusPrev()
42−{
43− QQuickItem * current = scopedFocusItem();
44− if (current) {
45− QQuickItem * prev = current->nextItemInFocusChain(false);
46− if (prev) {
47− prev->setFocus(true, Qt::BacktabFocusReason);
48− return true;
49− }
50− }
51− return false;
52−}
53−
54−void TabFocusFenceItem::keyPressEvent(QKeyEvent *event)
55−{
56− // Needed so we eat Tab keys when there's only one item inside the fence
57− if (event->key() == Qt::Key_Tab) {
58− event->accept();
59− } else {
60− QQuickItem::keyPressEvent(event);
61− }
62−}
63−
64−void TabFocusFenceItem::keyReleaseEvent(QKeyEvent *event)
65−{
66− // Needed so we eat Tab keys when there's only one item inside the fence
67− if (event->key() == Qt::Key_Tab) {
68− event->accept();
69− } else {
70− QQuickItem::keyReleaseEvent(event);
71− }
72−}
plugins/Utils/tabfocusfence.hdeleted−38
@@ -1,38 +0,0 @@
1−/*
2− * Copyright 2017 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15−*/
16−
17−#ifndef TABFOCUSFENCE_H
18−#define TABFOCUSFENCE_H
19−
20−#include <QQuickItem>
21−
22−// An item that restricts focus Tab travelling
23−// to its children
24−class TabFocusFenceItem : public QQuickItem
25−{
26−Q_OBJECT
27−
28−public:
29− TabFocusFenceItem(QQuickItem *parent = nullptr);
30−
31− Q_INVOKABLE bool focusNext();
32− Q_INVOKABLE bool focusPrev();
33−
34− void keyPressEvent(QKeyEvent *event) override;
35− void keyReleaseEvent(QKeyEvent *event) override;
36−};
37−
38−#endif
plugins/Utils/windowstatestorage.cpp+125−294
@@ -1,6 +1,5 @@
1/*
1/*
2 * Copyright 2015-2016 Canonical Ltd.
2 * Copyright 2015-2016 Canonical Ltd.
3− * Copyright 2021 UBports Foundation
4 *
3 *
5 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -17,344 +16,178 @@
17
16
18#include "windowstatestorage.h"
17#include "windowstatestorage.h"
19
18
19+#include <QtConcurrent>
20#include <QDebug>
20#include <QDebug>
21−#include <QDir>
21+#include <QFutureSynchronizer>
22−#include <QMetaObject>
23−#include <QObject>
24#include <QSqlQuery>
22#include <QSqlQuery>
25#include <QSqlError>
23#include <QSqlError>
26#include <QSqlResult>
24#include <QSqlResult>
27−#include <QStandardPaths>
28#include <QRect>
25#include <QRect>
29#include <unity/shell/application/ApplicationInfoInterface.h>
26#include <unity/shell/application/ApplicationInfoInterface.h>
30
27
28+QMutex WindowStateStorage::s_mutex;
31
29
32−class AsyncQuery: public QObject
30+inline QString sanitiseString(QString string) {
33−{
31+ return string.remove(QLatin1Char('\"'))
34− Q_OBJECT
32+ .remove(QLatin1Char('\''))
33+ .remove(QLatin1Char('\\'));
34+}
35
35
36−public:
36+WindowStateStorage::WindowStateStorage(QObject *parent):
37− AsyncQuery(const QString &dbName):
37+ QObject(parent)
38− m_dbName(dbName)
38+{
39− {
39+ const QString dbPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QStringLiteral("/unity8/");
40+ m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
41+ QDir dir;
42+ dir.mkpath(dbPath);
43+ m_db.setDatabaseName(dbPath + "windowstatestorage.sqlite");
44+ initdb();
40− }
45+}
41
46
42− ~AsyncQuery()
47+WindowStateStorage::~WindowStateStorage()
43− {
48+{
44− QSqlDatabase::removeDatabase(m_connectionName);
49+ QFutureSynchronizer<void> futureSync;
50+ for (int i = 0; i < m_asyncQueries.count(); ++i) {
51+ futureSync.addFuture(m_asyncQueries[i]);
45 }
52 }
53+ futureSync.waitForFinished();
54+ m_db.close();
55+}
46
56
47− Q_INVOKABLE const QString getDbName()
57+void WindowStateStorage::saveState(const QString &windowId, WindowStateStorage::WindowState state)
48− {
58+{
49− if (!m_ok) {
59+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values ('%1', '%2');")
50− return "ERROR";
60+ .arg(sanitiseString(windowId))
51− }
61+ .arg((int)state);
52− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
53− return connection.databaseName();
54− }
55
62
56− Q_INVOKABLE bool initdb()
63+ saveValue(queryString);
57− {
58− if (m_ok) {
59− return true;
60− }
61− QSqlDatabase connection = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName);
62− connection.setDatabaseName(m_dbName);
63− connection.setConnectOptions(QStringLiteral("QSQLITE_BUSY_TIMEOUT=1000"));
64− if (!connection.open()) {
65− qWarning() << "AsyncQuery::initdb: Error opening state database. Window positions will not be saved or restored." << m_dbName << connection.lastError().driverText() << connection.lastError().databaseText();
66− return false;
67− }
68− QSqlQuery query(connection);
69−
70− if (!connection.tables().contains(QStringLiteral("geometry"))) {
71− QString geometryQuery = QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);");
72− if (!query.exec(geometryQuery)) {
73− logSqlError(query);
74− return false;
75− }
76− }
77−
78− if (!connection.tables().contains(QStringLiteral("state"))) {
79− QString stateQuery = QStringLiteral("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);");
80− if (!query.exec(stateQuery)) {
81− logSqlError(query);
82− return false;
83− }
84− }
85−
86− if (!connection.tables().contains(QStringLiteral("stage"))) {
87− QString stageQuery = QStringLiteral("CREATE TABLE stage(appId TEXT UNIQUE, stage INTEGER);");
88− if (!query.exec(stageQuery)) {
89− logSqlError(query);
90− return false;
91− }
92− }
93− m_ok = true;
94− return true;
95− }
64+}
96
65
97− Q_INVOKABLE int getState(const QString &windowId) const
66+WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
98− {
67+{
99− if (!m_ok) {
68+ const QString queryString = QStringLiteral("SELECT state FROM state WHERE windowId = '%1';")
100− return -1;
69+ .arg(sanitiseString(windowId));
101− }
102− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
103− QSqlQuery query(connection);
104− query.prepare(m_getStateQuery);
105− query.bindValue(":windowId", windowId);
106− query.exec();
107− if (!query.isActive() || !query.isSelect()) {
108− logSqlError(query);
109− return -1;
110− }
111− if (!query.first()) {
112− return -1;
113− }
114− bool converted = false;
115− QVariant resultStr = query.value(0);
116− int result = resultStr.toInt(&converted);
117− if (converted) {
118− return result;
119− } else {
120− qWarning() << "getState result expected integer, got " << resultStr;
121− return -1;
122− }
123− }
124
70
125− Q_INVOKABLE QRect getGeometry(const QString &windowId) const
126− {
127− if (!m_ok) {
128− return QRect();
129− }
130− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
131− QSqlQuery query(connection);
71+ QSqlQuery query = getValue(queryString);
132− query.prepare(m_getGeometryQuery);
133− query.bindValue(":windowId", windowId);
134− query.exec();
135− if (!query.isActive() || !query.isSelect()) {
136− logSqlError(query);
137− return QRect();
138− }
139−
140− if (!query.first()) {
141− return QRect();
142− }
143−
144− bool xConverted, yConverted, widthConverted, heightConverted = false;
145− int x, y, width, height;
146− QVariant xResultStr = query.value(QStringLiteral("x"));
147− QVariant yResultStr = query.value(QStringLiteral("y"));
148− QVariant widthResultStr = query.value(QStringLiteral("width"));
149− QVariant heightResultStr = query.value(QStringLiteral("height"));
150− x = xResultStr.toInt(&xConverted);
151− y = yResultStr.toInt(&yConverted);
152− width = widthResultStr.toInt(&widthConverted);
153− height = heightResultStr.toInt(&heightConverted);
154−
155− if (xConverted && yConverted && widthConverted && heightConverted) {
156− return QRect(x, y, width, height);
157− } else {
158− qWarning() << "getGeometry result expected integers, got x:"
159− << xResultStr << "y:" << yResultStr << "width" << widthResultStr
160− << "height:" << heightResultStr;
161− return QRect();
162− }
163
72
73+ if (!query.first()) {
74+ return defaultValue;
164 }
75 }
76+ return (WindowState)query.value(QStringLiteral("state")).toInt();
77+}
165
78
166− Q_INVOKABLE int getStage(const QString &appId) const
79+void WindowStateStorage::saveGeometry(const QString &windowId, const QRect &rect)
167− {
80+{
168− if (!m_ok) {
81+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values ('%1', '%2', '%3', '%4', '%5');")
169− return -1;
82+ .arg(sanitiseString(windowId))
170− }
83+ .arg(rect.x())
171− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
84+ .arg(rect.y())
172− QSqlQuery query(connection);
85+ .arg(rect.width())
173− query.prepare(m_getStageQuery);
86+ .arg(rect.height());
174− query.bindValue(":appId", appId);
87+
175− query.exec();
88+ saveValue(queryString);
176− if (!query.isActive() || !query.isSelect()) {
177− logSqlError(query);
178− return -1;
179− }
180− if (!query.first()) {
181− return -1;
182− }
183− bool converted = false;
184− QVariant resultStr = query.value(0);
185− int result = resultStr.toInt(&converted);
186− if (converted) {
187− return result;
188− } else {
189− qWarning() << "getStage result expected integer, got " << resultStr;
190− return -1;
191− }
192− }
89+}
193
90
194−public Q_SLOTS:
91+void WindowStateStorage::saveStage(const QString &appId, int stage)
195−
92+{
196− void saveState(const QString &windowId, WindowStateStorage::WindowState state)
93+ const QString queryString = QStringLiteral("INSERT OR REPLACE INTO stage (appId, stage) values ('%1', '%2');")
197− {
94+ .arg(sanitiseString(appId))
198− if (!m_ok) {
95+ .arg(stage);
199− return;
200− }
201− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
202− QSqlQuery query(connection);
203− query.prepare(m_saveStateQuery);
204− query.bindValue(":windowId", windowId);
205− query.bindValue(":state", (int)state);
206− if (!query.exec()) {
207− logSqlError(query);
208− }
209− }
210
96
211− void saveGeometry(const QString &windowId, const QRect &rect)
97+ saveValue(queryString);
212− {
213− if (!m_ok) {
214− return;
215− }
216− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
217− QSqlQuery query(connection);
218− query.prepare(m_saveGeometryQuery);
219− query.bindValue(":windowId", windowId);
220− query.bindValue(":x", rect.x());
221− query.bindValue(":y", rect.y());
222− query.bindValue(":width", rect.width());
223− query.bindValue(":height", rect.height());
224− if (!query.exec()) {
225− logSqlError(query);
226− }
227− }
98+}
228
99
229− void saveStage(const QString &appId, int stage)
100+int WindowStateStorage::getStage(const QString &appId, int defaultValue) const
230− {
101+{
231− if (!m_ok) {
102+ const QString queryString = QStringLiteral("SELECT stage FROM stage WHERE appId = '%1';")
232− return;
103+ .arg(sanitiseString(appId));
233− }
234− QSqlDatabase connection = QSqlDatabase::database(m_connectionName);
235− QSqlQuery query(connection);
236− query.prepare(m_saveStageQuery);
237− query.bindValue(":appId", appId);
238− query.bindValue(":stage", stage);
239− if (!query.exec()) {
240− logSqlError(query);
241− }
242− }
243
104
244−private:
105+ QSqlQuery query = getValue(queryString);
245− static const QString m_connectionName;
246− static const QString m_getStateQuery;
247− static const QString m_saveStateQuery;
248− static const QString m_getGeometryQuery;
249− static const QString m_saveGeometryQuery;
250− static const QString m_getStageQuery;
251− static const QString m_saveStageQuery;
252−
253− static void logSqlError(const QSqlQuery query)
254− {
255− qWarning() << "Error executing query" << query.lastQuery()
256− << "Driver error:" << query.lastError().driverText()
257− << "Database error:" << query.lastError().databaseText();
258− }
259
106
260− QString m_dbName;
107+ if (!query.first()) {
261− bool m_ok = false;
108+ return defaultValue;
262−};
263−
264−const QString AsyncQuery::m_connectionName = QStringLiteral("WindowStateStorage");
265−const QString AsyncQuery::m_getStateQuery = QStringLiteral("SELECT state FROM state WHERE windowId = :windowId");
266−const QString AsyncQuery::m_saveStateQuery = QStringLiteral("INSERT OR REPLACE INTO state (windowId, state) values (:windowId, :state)");
267−const QString AsyncQuery::m_getGeometryQuery = QStringLiteral("SELECT * FROM geometry WHERE windowId = :windowId");
268−const QString AsyncQuery::m_saveGeometryQuery = QStringLiteral("INSERT OR REPLACE INTO geometry (windowId, x, y, width, height) values (:windowId, :x, :y, :width, :height)");
269−const QString AsyncQuery::m_getStageQuery = QStringLiteral("SELECT stage FROM stage WHERE appId = :appId");
270−const QString AsyncQuery::m_saveStageQuery = QStringLiteral("INSERT OR REPLACE INTO stage (appId, stage) values (:appId, :stage)");
271−
272−WindowStateStorage::WindowStateStorage(const QString &dbName, QObject *parent):
273− QObject(parent),
274− m_thread()
275−{
276− qRegisterMetaType<WindowStateStorage::WindowState>("WindowStateStorage::WindowState");
277− QString dbFile;
278− if (dbName.isEmpty()) {
279− const QString dbPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QStringLiteral("/unity8/");
280− QDir dir;
281− dir.mkpath(dbPath);
282− dbFile = QString(dbPath) + QStringLiteral("windowstatestorage.sqlite");
283− } else {
284− dbFile = dbName;
285 }
109 }
286− m_asyncQuery = new AsyncQuery(dbFile);
110+ return query.value("stage").toInt();
287− m_asyncQuery->moveToThread(&m_thread);
288− connect(&m_thread, &QThread::finished, m_asyncQuery, &QObject::deleteLater);
289− m_thread.start();
290− // Note that we're relying on initdb being called before any other methods
291− // on AsyncQuery. Given the current behavior of QueuedConnection (slots
292− // invoked in the order they are received), this is fine.
293− QMetaObject::invokeMethod(m_asyncQuery, "initdb",
294− Qt::QueuedConnection);
295− connect(this, &WindowStateStorage::saveState, m_asyncQuery, &AsyncQuery::saveState);
296− connect(this, &WindowStateStorage::saveGeometry, m_asyncQuery, &AsyncQuery::saveGeometry);
297− connect(this, &WindowStateStorage::saveStage, m_asyncQuery, &AsyncQuery::saveStage);
298}
111}
299
112
300−WindowStateStorage::~WindowStateStorage()
113+void WindowStateStorage::executeAsyncQuery(const QString &queryString)
301{
114{
302− m_thread.quit();
115+ QMutexLocker l(&s_mutex);
303− m_thread.wait();
116+ QSqlQuery query;
117+
118+ bool ok = query.exec(queryString);
119+ if (!ok) {
120+ qWarning() << "Error executing query" << queryString
121+ << "Driver error:" << query.lastError().driverText()
122+ << "Database error:" << query.lastError().databaseText();
123+ }
304}
124}
305
125
306−WindowStateStorage::WindowState WindowStateStorage::getState(const QString &windowId, WindowStateStorage::WindowState defaultValue) const
126+QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
307{
127{
308− int state;
128+ QString queryString = QStringLiteral("SELECT * FROM geometry WHERE windowId = '%1';")
129+ .arg(sanitiseString(windowId));
309
130
310− QMetaObject::invokeMethod(m_asyncQuery, "getState", Qt::BlockingQueuedConnection,
131+ QSqlQuery query = getValue(queryString);
311− Q_RETURN_ARG(int, state),
312− Q_ARG(const QString&, windowId)
313− );
314
132
315− if (state == -1) {
133+ if (!query.first()) {
316 return defaultValue;
134 return defaultValue;
317 }
135 }
318−
136+ return QRect(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(),
319− return (WindowState)state;
137+ query.value(QStringLiteral("width")).toInt(), query.value(QStringLiteral("height")).toInt());
320}
138}
321
139
322−int WindowStateStorage::getStage(const QString &appId, int defaultValue) const
140+void WindowStateStorage::initdb()
323{
141{
324− int stage;
142+ m_db.open();
143+ if (!m_db.open()) {
144+ qWarning() << "Error opening state database:" << m_db.lastError().driverText() << m_db.lastError().databaseText();
145+ return;
146+ }
325
147
326− QMetaObject::invokeMethod(m_asyncQuery, "getStage", Qt::BlockingQueuedConnection,
148+ if (!m_db.tables().contains(QStringLiteral("geometry"))) {
327− Q_RETURN_ARG(int, stage),
149+ QSqlQuery query;
328− Q_ARG(const QString&, appId)
150+ query.exec(QStringLiteral("CREATE TABLE geometry(windowId TEXT UNIQUE, x INTEGER, y INTEGER, width INTEGER, height INTEGER);"));
329− );
151+ }
330
152
331− if (stage == -1) {
153+ if (!m_db.tables().contains(QStringLiteral("state"))) {
332− return defaultValue;
154+ QSqlQuery query;
155+ query.exec(QStringLiteral("CREATE TABLE state(windowId TEXT UNIQUE, state INTEGER);"));
333 }
156 }
334
157
335− return stage;
158+ if (!m_db.tables().contains(QStringLiteral("stage"))) {
159+ QSqlQuery query;
160+ query.exec(QStringLiteral("CREATE TABLE stage(appId TEXT UNIQUE, stage INTEGER);"));
161+ }
336}
162}
337
163
338−QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defaultValue) const
164+void WindowStateStorage::saveValue(const QString &queryString)
339{
165{
340− QRect geometry;
166+ QMutexLocker mutexLocker(&s_mutex);
341− QMetaObject::invokeMethod(m_asyncQuery, "getGeometry", Qt::BlockingQueuedConnection,
167+
342− Q_RETURN_ARG(QRect, geometry),
168+ QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
343− Q_ARG(const QString&, windowId)
169+ m_asyncQueries.append(future);
344− );
170+
345− if (geometry.isNull() || !geometry.isValid()) {
171+ QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
346− return defaultValue;
172+ futureWatcher->setFuture(future);
347− }
173+ connect(futureWatcher, &QFutureWatcher<void>::finished,
348− return geometry;
174+ this,
175+ [=](){ m_asyncQueries.removeAll(futureWatcher->future());
176+ futureWatcher->deleteLater(); });
349}
177}
350
178
351−const QString WindowStateStorage::getDbName()
179+QSqlQuery WindowStateStorage::getValue(const QString &queryString) const
352{
180{
353− QString dbName;
181+ QMutexLocker l(&s_mutex);
354− QMetaObject::invokeMethod(m_asyncQuery, "getDbName", Qt::BlockingQueuedConnection,
182+ QSqlQuery query;
355− Q_RETURN_ARG(QString, dbName)
183+
356− );
184+ bool ok = query.exec(queryString);
185+ if (!ok) {
186+ qWarning() << "Error retrieving database query:" << queryString
187+ << "Driver error:" << query.lastError().driverText()
188+ << "Database error:" << query.lastError().databaseText();
189+ }
357− return QString(dbName);
190+ return query;
358}
191}
359
192
360Mir::State WindowStateStorage::toMirState(WindowState state) const
193Mir::State WindowStateStorage::toMirState(WindowState state) const
@@ -379,5 +212,3 @@ Mir::State WindowStateStorage::toMirState(WindowState state) const
379 return Mir::RestoredState;
212 return Mir::RestoredState;
380 }
213 }
381}
214}
382−
383−#include "windowstatestorage.moc"
plugins/Utils/windowstatestorage.h+15−14
@@ -1,6 +1,5 @@
1/*
1/*
2 * Copyright 2015-2016 Canonical Ltd.
2 * Copyright 2015-2016 Canonical Ltd.
3− * Copyright 2021 UBports Foundation
4 *
3 *
5 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -17,16 +16,12 @@
17
16
18#include <QObject>
17#include <QObject>
19#include <QSqlDatabase>
18#include <QSqlDatabase>
20−#include <QSqlQuery>
21#include <QMutex>
19#include <QMutex>
22#include <QFuture>
20#include <QFuture>
23−#include <QThread>
24
21
25// unity-api
22// unity-api
26#include <unity/shell/application/Mir.h>
23#include <unity/shell/application/Mir.h>
27
24
28−class AsyncQuery;
29−
30class WindowStateStorage: public QObject
25class WindowStateStorage: public QObject
31{
26{
32 Q_OBJECT
27 Q_OBJECT
@@ -50,25 +45,31 @@ public:
50 Q_DECLARE_FLAGS(WindowStates, WindowState)
45 Q_DECLARE_FLAGS(WindowStates, WindowState)
51 Q_FLAG(WindowStates)
46 Q_FLAG(WindowStates)
52
47
53− WindowStateStorage(const QString &dbName = QString(), QObject *parent = nullptr);
48+ WindowStateStorage(QObject *parent = nullptr);
54 virtual ~WindowStateStorage();
49 virtual ~WindowStateStorage();
55
50
51+ Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
56 Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const;
52 Q_INVOKABLE WindowState getState(const QString &windowId, WindowState defaultValue) const;
57
53
54+ Q_INVOKABLE void saveGeometry(const QString &windowId, const QRect &rect);
58 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const;
55 Q_INVOKABLE QRect getGeometry(const QString &windowId, const QRect &defaultValue) const;
59
56
57+ Q_INVOKABLE void saveStage(const QString &appId, int stage);
60 Q_INVOKABLE int getStage(const QString &appId, int defaultValue) const;
58 Q_INVOKABLE int getStage(const QString &appId, int defaultValue) const;
61
59
62 Q_INVOKABLE Mir::State toMirState(WindowState state) const;
60 Q_INVOKABLE Mir::State toMirState(WindowState state) const;
63
61
64− const QString getDbName();
62+private:
63+ void initdb();
65
64
66−Q_SIGNALS:
67− void saveStage(const QString &appId, int stage);
65+ void saveValue(const QString &queryString);
68− void saveGeometry(const QString &windowId, const QRect &rect);
66+ QSqlQuery getValue(const QString &queryString) const;
69− void saveState(const QString &windowId, WindowStateStorage::WindowState state);
70
67
71−private:
68+ static void executeAsyncQuery(const QString &queryString);
72− QThread m_thread;
69+ static QMutex s_mutex;
73− AsyncQuery *m_asyncQuery;
70+
71+ // NB: This is accessed from threads. Make sure to mutex it.
72+ QSqlDatabase m_db;
73+
74+ QList<QFuture<void>> m_asyncQueries;
74};
75};
plugins/WindowManager/AvailableDesktopArea.cppdeleted−50
@@ -1,50 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it under
5− * the terms of the GNU Lesser General Public License version 3, as published by
6− * the Free Software Foundation.
7− *
8− * This program is distributed in the hope that it will be useful, but WITHOUT
9− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11− * Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "AvailableDesktopArea.h"
18−
19−#include <QGuiApplication>
20−#include <QQuickWindow>
21−#include <qpa/qplatformnativeinterface.h>
22−
23−AvailableDesktopArea::AvailableDesktopArea(QQuickItem *parent)
24− : QQuickItem(parent)
25−{
26− connect(this, &QQuickItem::xChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
27− connect(this, &QQuickItem::yChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
28− connect(this, &QQuickItem::widthChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
29− connect(this, &QQuickItem::heightChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
30−}
31−
32−void AvailableDesktopArea::updatePlatformWindowProperty()
33−{
34− if (!window()) {
35− return;
36− }
37−
38− QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
39−
40− QRect rect(x(), y(), width(), height());
41−
42− nativeInterface->setWindowProperty(window()->handle(), "availableDesktopArea", QVariant(rect));
43−}
44−
45−void AvailableDesktopArea::itemChange(ItemChange change, const ItemChangeData &)
46−{
47− if (change == ItemSceneChange) {
48− updatePlatformWindowProperty();
49− }
50−}
plugins/WindowManager/CMakeLists.txt+1−11
@@ -1,10 +1,7 @@
1set(WINDOWMANAGER_SRC
1set(WINDOWMANAGER_SRC
2− AvailableDesktopArea.cpp
3 TopLevelWindowModel.cpp
2 TopLevelWindowModel.cpp
4 Window.cpp
3 Window.cpp
5 WindowManagerPlugin.cpp
4 WindowManagerPlugin.cpp
6− WindowMargins.cpp
7− InputMethodManager.cpp
8 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
5 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
6 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
10 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -12,15 +9,8 @@ set(WINDOWMANAGER_SRC
12 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/SurfaceManagerInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/SurfaceManagerInterface.h
13 )
10 )
14
11
15−add_definitions(-DWINDOWMANAGERQML_LIBRARY)
16−
17−include_directories(
18− SYSTEM
19− ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
20−)
21−
22add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
12add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
23
13
24−target_link_libraries(windowmanager-qml Qt5::Qml Qt5::Quick Qt5::Gui)
14+qt5_use_modules(windowmanager-qml Qml Quick Gui)
25
15
26add_unity8_plugin(WindowManager 0.1 WindowManager TARGETS windowmanager-qml)
16add_unity8_plugin(WindowManager 0.1 WindowManager TARGETS windowmanager-qml)
plugins/WindowManager/InputMethodManager.cppdeleted−56
@@ -1,56 +0,0 @@
1−/*
2− * Copyright (C) 2019 UBports Foundation.
3− * Author(s) Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software: you can redistribute it and/or modify it under
6− * the terms of the GNU Lesser General Public License version 3, as published by
7− * the Free Software Foundation.
8− *
9− * This program is distributed in the hope that it will be useful, but WITHOUT
10− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
11− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12− * Lesser General Public License for more details.
13− *
14− * You should have received a copy of the GNU Lesser General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#include "InputMethodManager.h"
19−#include <QDebug>
20−
21−#include <unity/shell/application/MirSurfaceInterface.h>
22−
23−// local
24−#include "Window.h"
25−
26−Q_LOGGING_CATEGORY(INPUTMETHODMANAGER, "InputMethodManager", QtInfoMsg)
27−#define DEBUG_MSG qCDebug(INPUTMETHODMANAGER).nospace().noquote() << __func__
28−
29−namespace unityapi = unity::shell::application;
30−
31−InputMethodManager *InputMethodManager::instance()
32−{
33− static InputMethodManager* inputMethod(new InputMethodManager());
34− return inputMethod;
35−}
36−
37−InputMethodManager::InputMethodManager()
38−{
39−}
40−
41−void InputMethodManager::setWindow(Window* window)
42−{
43− if (window == m_inputMethodWindow) {
44− return;
45− }
46−
47− DEBUG_MSG << "(" << window << ")";
48−
49− m_inputMethodWindow = window;
50− Q_EMIT surfaceChanged(surface());
51−}
52−
53−unityapi::MirSurfaceInterface* InputMethodManager::surface() const
54−{
55− return m_inputMethodWindow ? m_inputMethodWindow->surface() : nullptr;
56−}
plugins/WindowManager/InputMethodManager.hdeleted−55
@@ -1,55 +0,0 @@
1−/*
2− * Copyright (C) 2019 UBports Foundation.
3− * Author(s) Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software: you can redistribute it and/or modify it under
6− * the terms of the GNU Lesser General Public License version 3, as published by
7− * the Free Software Foundation.
8− *
9− * This program is distributed in the hope that it will be useful, but WITHOUT
10− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
11− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12− * Lesser General Public License for more details.
13− *
14− * You should have received a copy of the GNU Lesser General Public License
15− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#pragma once
19−
20−#include <QLoggingCategory>
21−#include <QObject>
22−
23−#include "WindowManagerGlobal.h"
24−
25−Q_DECLARE_LOGGING_CATEGORY(INPUTMETHODMANAGER)
26−
27−class Window;
28−
29−namespace unity {
30− namespace shell {
31− namespace application {
32− class MirSurfaceInterface;
33− }
34− }
35−}
36−
37−class WINDOWMANAGERQML_EXPORT InputMethodManager : public QObject
38−{
39− Q_OBJECT
40− Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
41−
42−public:
43− InputMethodManager();
44− static InputMethodManager* instance();
45−
46− void setWindow(Window* window);
47−
48−Q_SIGNALS:
49− void surfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
50−
51−private:
52− unity::shell::application::MirSurfaceInterface* surface() const;
53−
54− Window* m_inputMethodWindow{nullptr};
55−};
plugins/WindowManager/TopLevelWindowModel.cpp+83−197
@@ -1,6 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3− * Copyright 2019 UBports Foundation
4 *
3 *
5 * This program is free software: you can redistribute it and/or modify it under
4 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3, as published by
5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -30,7 +29,6 @@
30
29
31// local
30// local
32#include "Window.h"
31#include "Window.h"
33−#include "InputMethodManager.h"
34
32
35Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
33Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
36
34
@@ -40,12 +38,7 @@ Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
40namespace unityapi = unity::shell::application;
38namespace unityapi = unity::shell::application;
41
39
42TopLevelWindowModel::TopLevelWindowModel()
40TopLevelWindowModel::TopLevelWindowModel()
43− : m_nullWindow(createNullWindow()),
44− m_surfaceManagerBusy(false)
45{
41{
46− connect(m_nullWindow, &Window::focusedChanged, this, [this] {
47− Q_EMIT rootFocusChanged();
48− });
49}
42}
50
43
51void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
44void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
@@ -137,7 +130,7 @@ void TopLevelWindowModel::removeApplication(unityapi::ApplicationInfoInterface *
137 int i = 0;
130 int i = 0;
138 while (i < m_windowModel.count()) {
131 while (i < m_windowModel.count()) {
139 if (m_windowModel.at(i).application == application) {
132 if (m_windowModel.at(i).application == application) {
140− deleteAt(i);
133+ removeAt(i);
141 } else {
134 } else {
142 ++i;
135 ++i;
143 }
136 }
@@ -155,13 +148,12 @@ void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface,
155{
148{
156 Q_ASSERT(surface != nullptr);
149 Q_ASSERT(surface != nullptr);
157
150
158− connectSurface(surface);
159−
160 bool filledPlaceholder = false;
151 bool filledPlaceholder = false;
161 for (int i = 0; i < m_windowModel.count() && !filledPlaceholder; ++i) {
152 for (int i = 0; i < m_windowModel.count() && !filledPlaceholder; ++i) {
162 ModelEntry &entry = m_windowModel[i];
153 ModelEntry &entry = m_windowModel[i];
163 if (entry.application == application && entry.window->surface() == nullptr) {
154 if (entry.application == application && entry.window->surface() == nullptr) {
164 entry.window->setSurface(surface);
155 entry.window->setSurface(surface);
156+ connectSurface(surface);
165 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
157 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
166 << ", filling out placeholder. after: " << toString();
158 << ", filling out placeholder. after: " << toString();
167 filledPlaceholder = true;
159 filledPlaceholder = true;
@@ -175,33 +167,6 @@ void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface,
175}
167}
176
168
177void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
169void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
178−{
179−
180− Window *window = createWindow(surface);
181−
182− connect(window, &Window::stateChanged, this, [=](Mir::State newState) {
183− if (newState == Mir::HiddenState) {
184− // Comply, removing it from our model. Just as if it didn't exist anymore.
185− removeAt(indexForId(window->id()));
186− } else {
187− if (indexForId(window->id()) == -1) {
188− // was probably hidden before. put it back on the list
189− auto *application = m_applicationManager->findApplicationWithSurface(window->surface());
190− Q_ASSERT(application);
191− prependWindow(window, application);
192− }
193− }
194− });
195−
196− prependWindow(window, application);
197−
198− // Activate the newly-prepended window.
199− window->activate();
200−
201− INFO_MSG << " after " << toString();
202−}
203−
204−void TopLevelWindowModel::prependWindow(Window *window, unityapi::ApplicationInfoInterface *application)
205{
170{
206 if (m_modelState == IdleState) {
171 if (m_modelState == IdleState) {
207 m_modelState = InsertingState;
172 m_modelState = InsertingState;
@@ -211,7 +176,17 @@ void TopLevelWindowModel::prependWindow(Window *window, unityapi::ApplicationInf
211 // No point in signaling anything if we're resetting the whole model
176 // No point in signaling anything if we're resetting the whole model
212 }
177 }
213
178
179+ int id = generateId();
180+ Window *window = new Window(id, this);
181+ if (surface) {
182+ window->setSurface(surface);
183+ }
214 m_windowModel.prepend(ModelEntry(window, application));
184 m_windowModel.prepend(ModelEntry(window, application));
185+ if (surface) {
186+ connectSurface(surface);
187+ }
188+
189+ connectWindow(window);
215
190
216 if (m_modelState == InsertingState) {
191 if (m_modelState == InsertingState) {
217 endInsertRows();
192 endInsertRows();
@@ -219,6 +194,12 @@ void TopLevelWindowModel::prependWindow(Window *window, unityapi::ApplicationInf
219 Q_EMIT listChanged();
194 Q_EMIT listChanged();
220 m_modelState = IdleState;
195 m_modelState = IdleState;
221 }
196 }
197+
198+ if (!surface) {
199+ activateEmptyWindow(window);
200+ }
201+
202+ INFO_MSG << " after " << toString();
222}
203}
223
204
224void TopLevelWindowModel::connectWindow(Window *window)
205void TopLevelWindowModel::connectWindow(Window *window)
@@ -267,13 +248,6 @@ void TopLevelWindowModel::connectWindow(Window *window)
267 connect(window, &Window::emptyWindowActivated, this, [this, window]() {
248 connect(window, &Window::emptyWindowActivated, this, [this, window]() {
268 activateEmptyWindow(window);
249 activateEmptyWindow(window);
269 });
250 });
270−
271− connect(window, &Window::liveChanged, this, [this, window](bool isAlive) {
272− if (!isAlive && window->state() == Mir::HiddenState) {
273− // Hidden windows are not in the model. So just delete it right away.
274− delete window;
275− }
276− });
277}
251}
278
252
279void TopLevelWindowModel::activateEmptyWindow(Window *window)
253void TopLevelWindowModel::activateEmptyWindow(Window *window)
@@ -317,11 +291,10 @@ void TopLevelWindowModel::onSurfaceDied(unityapi::MirSurfaceInterface *surface)
317
291
318 auto application = m_windowModel[i].application;
292 auto application = m_windowModel[i].application;
319
293
320− DEBUG_MSG << " application->name()=" << application->name()
294+ // can't be starting if it already has a surface
321− << " application->state()=" << application->state();
295+ Q_ASSERT(application->state() != unityapi::ApplicationInfoInterface::Starting);
322
296
323− if (application->state() == unityapi::ApplicationInfoInterface::Running
297+ if (application->state() == unityapi::ApplicationInfoInterface::Running) {
324− || application->state() == unityapi::ApplicationInfoInterface::Starting) {
325 m_windowModel[i].removeOnceSurfaceDestroyed = true;
298 m_windowModel[i].removeOnceSurfaceDestroyed = true;
326 } else {
299 } else {
327 // assume it got killed by the out-of-memory daemon.
300 // assume it got killed by the out-of-memory daemon.
@@ -340,7 +313,7 @@ void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surf
340 }
313 }
341
314
342 if (m_windowModel[i].removeOnceSurfaceDestroyed) {
315 if (m_windowModel[i].removeOnceSurfaceDestroyed) {
343− deleteAt(i);
316+ removeAt(i);
344 } else {
317 } else {
345 auto window = m_windowModel[i].window;
318 auto window = m_windowModel[i].window;
346 window->setSurface(nullptr);
319 window->setSurface(nullptr);
@@ -349,78 +322,34 @@ void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surf
349 }
322 }
350}
323}
351
324
352−Window *TopLevelWindowModel::createWindow(unityapi::MirSurfaceInterface *surface)
353−{
354− int id = m_nextId.fetchAndAddAcquire(1);
355− return createWindowWithId(surface, id);
356−}
357−
358−Window *TopLevelWindowModel::createNullWindow()
359−{
360− return createWindowWithId(nullptr, 0);
361−}
362−
363−Window *TopLevelWindowModel::createWindowWithId(unityapi::MirSurfaceInterface *surface, int id)
364−{
365− Window *qmlWindow = new Window(id, this);
366− connectWindow(qmlWindow);
367− if (surface) {
368− qmlWindow->setSurface(surface);
369− }
370− return qmlWindow;
371−}
372−
373void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
325void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
374{
326{
375 DEBUG_MSG << "(" << surface << ")";
327 DEBUG_MSG << "(" << surface << ")";
376−
328+ if (surface->type() == Mir::InputMethodType) {
377− if (surface->parentSurface()) {
329+ int id = generateId();
378− // Wrap it in a Window so that we keep focusedWindow() up to date.
330+ Window *qmlWindow = new Window(id, this);
379− Window *window = createWindow(surface);
331+ connectWindow(qmlWindow);
380− connect(surface, &QObject::destroyed, window, [=](){
381− window->setSurface(nullptr);
332+ qmlWindow->setSurface(surface);
382− window->deleteLater();
333+ setInputMethodWindow(qmlWindow);
383− });
384 } else {
334 } else {
385− if (surface->type() == Mir::InputMethodType) {
335+ auto application = m_applicationManager->findApplicationWithSurface(surface);
386− connectSurface(surface);
336+ if (application) {
387− setInputMethodWindow(createWindow(surface));
337+ prependSurface(surface, application);
388 } else {
338 } else {
389− auto *application = m_applicationManager->findApplicationWithSurface(surface);
390− if (application) {
391− if (surface->state() == Mir::HiddenState) {
392− // Ignore it until it's finally shown
393− connect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, [=](Mir::State newState) {
394− Q_ASSERT(newState != Mir::HiddenState);
395− disconnect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, 0);
396− prependSurface(surface, application);
397− });
398− } else {
399− prependSurface(surface, application);
400− }
401− } else {
402− // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
339+ // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
403− // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
340+ // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
404− // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
341+ // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
342+ int id = generateId();
405− Window *promptWindow = createWindow(surface);
343+ Window *promptWindow = new Window(id, this);
344+ connectWindow(promptWindow);
345+ promptWindow->setSurface(surface);
406− connect(surface, &QObject::destroyed, promptWindow, [=](){
346+ connect(surface, &QObject::destroyed, promptWindow, [=](){
407− promptWindow->setSurface(nullptr);
347+ promptWindow->setSurface(nullptr);
408− promptWindow->deleteLater();
348+ promptWindow->deleteLater();
409− });
349+ });
410− }
411 }
350 }
412 }
351 }
413−}
352+ // TODO: handle surfaces that are neither top-level windows nor input method. eg: child dialogs, popups, menus
414−
415−void TopLevelWindowModel::deleteAt(int index)
416−{
417− auto window = m_windowModel[index].window;
418−
419− removeAt(index);
420−
421− window->setSurface(nullptr);
422−
423− delete window;
424}
353}
425
354
426void TopLevelWindowModel::removeAt(int index)
355void TopLevelWindowModel::removeAt(int index)
@@ -435,9 +364,8 @@ void TopLevelWindowModel::removeAt(int index)
435
364
436 auto window = m_windowModel[index].window;
365 auto window = m_windowModel[index].window;
437
366
438− if (!window->surface()) {
367+ window->setSurface(nullptr);
439− window->setFocused(false);
368+ window->setFocused(false);
440− }
441
369
442 m_windowModel.removeAt(index);
370 m_windowModel.removeAt(index);
443
371
@@ -448,21 +376,13 @@ void TopLevelWindowModel::removeAt(int index)
448 m_modelState = IdleState;
376 m_modelState = IdleState;
449 }
377 }
450
378
379+ disconnect(window, 0, this, 0);
451 if (m_focusedWindow == window) {
380 if (m_focusedWindow == window) {
452 setFocusedWindow(nullptr);
381 setFocusedWindow(nullptr);
453 }
382 }
383+ delete window;
454
384
455− if (m_previousWindow == window) {
456− m_previousWindow = nullptr;
457− }
458−
459− if (m_closingAllApps) {
460− if (m_windowModel.isEmpty()) {
461− Q_EMIT closedAllWindows();
462− }
463− }
464−
465− INFO_MSG << " after " << toString() << " apps left " << m_windowModel.count();
385+ INFO_MSG << " after " << toString();
466}
386}
467
387
468void TopLevelWindowModel::setInputMethodWindow(Window *window)
388void TopLevelWindowModel::setInputMethodWindow(Window *window)
@@ -473,7 +393,6 @@ void TopLevelWindowModel::setInputMethodWindow(Window *window)
473 }
393 }
474 m_inputMethodWindow = window;
394 m_inputMethodWindow = window;
475 Q_EMIT inputMethodSurfaceChanged(m_inputMethodWindow->surface());
395 Q_EMIT inputMethodSurfaceChanged(m_inputMethodWindow->surface());
476− InputMethodManager::instance()->setWindow(window);
477}
396}
478
397
479void TopLevelWindowModel::removeInputMethodWindow()
398void TopLevelWindowModel::removeInputMethodWindow()
@@ -482,7 +401,6 @@ void TopLevelWindowModel::removeInputMethodWindow()
482 delete m_inputMethodWindow;
401 delete m_inputMethodWindow;
483 m_inputMethodWindow = nullptr;
402 m_inputMethodWindow = nullptr;
484 Q_EMIT inputMethodSurfaceChanged(nullptr);
403 Q_EMIT inputMethodSurfaceChanged(nullptr);
485− InputMethodManager::instance()->setWindow(nullptr);
486 }
404 }
487}
405}
488
406
@@ -528,6 +446,37 @@ int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surfac
528 return -1;
446 return -1;
529}
447}
530
448
449+int TopLevelWindowModel::generateId()
450+{
451+ int id = m_nextId;
452+ m_nextId = nextFreeId(nextId(id), id);
453+ return id;
454+}
455+
456+int TopLevelWindowModel::nextId(int id) const
457+{
458+ if (id == m_maxId) {
459+ return id = 1;
460+ } else {
461+ return id + 1;
462+ }
463+}
464+
465+int TopLevelWindowModel::nextFreeId(int candidateId, const int latestId)
466+{
467+ int firstCandidateId = candidateId;
468+
469+ while (indexForId(candidateId) != -1 || candidateId == latestId) {
470+ candidateId = nextId(candidateId);
471+
472+ if (candidateId == firstCandidateId) {
473+ qFatal("TopLevelWindowModel: run out of window ids.");
474+ }
475+ }
476+
477+ return candidateId;
478+}
479+
531QString TopLevelWindowModel::toString()
480QString TopLevelWindowModel::toString()
532{
481{
533 QString str;
482 QString str;
@@ -641,19 +590,16 @@ void TopLevelWindowModel::setFocusedWindow(Window *window)
641 if (window != m_focusedWindow) {
590 if (window != m_focusedWindow) {
642 INFO_MSG << "(" << window << ")";
591 INFO_MSG << "(" << window << ")";
643
592
644− m_previousWindow = m_focusedWindow;
593+ Window* previousWindow = m_focusedWindow;
645
594
646 m_focusedWindow = window;
595 m_focusedWindow = window;
647 Q_EMIT focusedWindowChanged(m_focusedWindow);
596 Q_EMIT focusedWindowChanged(m_focusedWindow);
648
597
649− if (m_previousWindow && m_previousWindow->focused() && !m_previousWindow->surface()) {
598+ if (previousWindow && previousWindow->focused() && !previousWindow->surface()) {
650 // do it ourselves. miral doesn't know about this window
599 // do it ourselves. miral doesn't know about this window
651− m_previousWindow->setFocused(false);
600+ previousWindow->setFocused(false);
652 }
601 }
653 }
602 }
654−
655− // Reset
656− m_pendingActivation = false;
657}
603}
658
604
659unityapi::MirSurfaceInterface* TopLevelWindowModel::inputMethodSurface() const
605unityapi::MirSurfaceInterface* TopLevelWindowModel::inputMethodSurface() const
@@ -697,7 +643,6 @@ void TopLevelWindowModel::move(int from, int to)
697}
643}
698void TopLevelWindowModel::onModificationsStarted()
644void TopLevelWindowModel::onModificationsStarted()
699{
645{
700− m_surfaceManagerBusy = true;
701}
646}
702
647
703void TopLevelWindowModel::onModificationsEnded()
648void TopLevelWindowModel::onModificationsEnded()
@@ -708,7 +653,6 @@ void TopLevelWindowModel::onModificationsEnded()
708 // reset
653 // reset
709 m_focusedWindowChanged = false;
654 m_focusedWindowChanged = false;
710 m_newlyFocusedWindow = nullptr;
655 m_newlyFocusedWindow = nullptr;
711− m_surfaceManagerBusy = false;
712}
656}
713
657
714void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
658void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
@@ -719,64 +663,6 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
719 Window *window = m_windowModel[i].window;
663 Window *window = m_windowModel[i].window;
720 if (window->id() != forbiddenId) {
664 if (window->id() != forbiddenId) {
721 window->activate();
665 window->activate();
722− break;
723 }
666 }
724 }
667 }
725}
668}
726−
727−void TopLevelWindowModel::closeAllWindows()
728−{
729− m_closingAllApps = true;
730− for (auto win : m_windowModel) {
731− win.window->close();
732− }
733−
734− // This is done after the for loop in the unlikely event that
735− // an app starts in between this
736− if (m_windowModel.isEmpty()) {
737− Q_EMIT closedAllWindows();
738− }
739−}
740−
741−bool TopLevelWindowModel::rootFocus()
742−{
743− return !m_nullWindow->focused();
744−}
745−
746−void TopLevelWindowModel::setRootFocus(bool focus)
747−{
748− INFO_MSG << "(" << focus << "), surfaceManagerBusy is " << m_surfaceManagerBusy;
749−
750− if (m_surfaceManagerBusy) {
751− // Something else is probably being focused already, let's not add to
752− // the noise.
753− return;
754− }
755−
756− if (focus) {
757− // Give focus back to previous focused window, only if null window is focused.
758− // If null window is not focused, a different app had taken the focus and we
759− // should repect that, or if a pendingActivation is going on.
760− if (m_previousWindow && !m_previousWindow->focused() && !m_pendingActivation &&
761− m_nullWindow == m_focusedWindow && m_previousWindow != m_nullWindow) {
762− m_previousWindow->activate();
763− } else if (!m_pendingActivation) {
764− // The previous window does not exist any more, focus top window.
765− activateTopMostWindowWithoutId(-1);
766− }
767− } else {
768− if (!m_nullWindow->focused()) {
769− m_nullWindow->activate();
770− }
771− }
772−}
773−
774−// Pending Activation will block refocus of previous focused window
775−// this is needed since surface activation with miral is async,
776−// and activation of placeholder is sync. This causes a race condition
777−// between placeholder and prev window. This results in prev window
778−// gets focused, as it will always be later than the placeholder.
779−void TopLevelWindowModel::pendingActivation()
780−{
781− m_pendingActivation = true;
782−}
plugins/WindowManager/TopLevelWindowModel.h+10−58
@@ -1,6 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3− * Copyright 2019 UBports Foundation
4 *
3 *
5 * This program is free software: you can redistribute it and/or modify it under
4 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3, as published by
5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -19,11 +18,8 @@
19#define TOPLEVELWINDOWMODEL_H
18#define TOPLEVELWINDOWMODEL_H
20
19
21#include <QAbstractListModel>
20#include <QAbstractListModel>
22−#include <QAtomicInteger>
23#include <QLoggingCategory>
21#include <QLoggingCategory>
24
22
25−#include "WindowManagerGlobal.h"
26−
27Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
23Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
28
24
29class Window;
25class Window;
@@ -51,7 +47,7 @@ namespace unity {
51 * As applications can have multiple surfaces and you can also have entries without surfaces at all,
47 * As applications can have multiple surfaces and you can also have entries without surfaces at all,
52 * the only way to unambiguously refer to an entry in this model is through its id.
48 * the only way to unambiguously refer to an entry in this model is through its id.
53 */
49 */
54−class WINDOWMANAGERQML_EXPORT TopLevelWindowModel : public QAbstractListModel
50+class TopLevelWindowModel : public QAbstractListModel
55{
51{
56 Q_OBJECT
52 Q_OBJECT
57
53
@@ -88,28 +84,7 @@ class WINDOWMANAGERQML_EXPORT TopLevelWindowModel : public QAbstractListModel
88 The id to be used on the next entry created
84 The id to be used on the next entry created
89 Useful for tests
85 Useful for tests
90 */
86 */
91− Q_PROPERTY(int nextId READ nextId)
87+ Q_PROPERTY(int nextId READ nextId NOTIFY nextIdChanged)
92−
93−
94− /**
95− * @brief Sets whether a user Window or "nothing" should be focused
96− *
97− * This implementation of TLWM must have something focused. However, the
98− * user may wish to have nothing in some cases - for example, when they
99− * minimize all their windows on the desktop or unfocus the app they're
100− * using by clicking the background or indicators.
101− *
102− * Unsetting rootFocus effectively focuses "nothing" by setting up a Window
103− * that has no displayable Surfaces and bringing it into focus.
104− *
105− * Setting rootFocus attempts to focus the Window which was focused last -
106− * unless another app is attempting to gain focus (as determined by
107− * pendingActivation) and that's why we got rootFocus.
108− *
109− * If the previously-focused Window was closed before rootFocus was set,
110− * the next available window will be focused.
111− */
112− Q_PROPERTY(bool rootFocus READ rootFocus WRITE setRootFocus NOTIFY rootFocusChanged)
113
88
114public:
89public:
115 /**
90 /**
@@ -145,7 +120,7 @@ public:
145 unity::shell::application::SurfaceManagerInterface *surfaceManager() const { return m_surfaceManager; }
120 unity::shell::application::SurfaceManagerInterface *surfaceManager() const { return m_surfaceManager; }
146 void setSurfaceManager(unity::shell::application::SurfaceManagerInterface*);
121 void setSurfaceManager(unity::shell::application::SurfaceManagerInterface*);
147
122
148− int nextId() const { return m_nextId.load(); }
123+ int nextId() const { return m_nextId; }
149
124
150public:
125public:
151 /**
126 /**
@@ -187,19 +162,6 @@ public:
187 */
162 */
188 Q_INVOKABLE void raiseId(int id);
163 Q_INVOKABLE void raiseId(int id);
189
164
190− /**
191− * @brief Closes all windows, emits closedAllWindows when done
192− */
193− Q_INVOKABLE void closeAllWindows();
194−
195− /**
196− * @brief Sets pending activation flag
197− */
198− Q_INVOKABLE void pendingActivation();
199−
200− void setRootFocus(bool focus);
201− bool rootFocus();
202−
203Q_SIGNALS:
165Q_SIGNALS:
204 void countChanged();
166 void countChanged();
205 void inputMethodSurfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
167 void inputMethodSurfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
@@ -214,9 +176,7 @@ Q_SIGNALS:
214 */
176 */
215 void listChanged();
177 void listChanged();
216
178
217− void closedAllWindows();
179+ void nextIdChanged();
218−
219− void rootFocusChanged();
220
180
221private Q_SLOTS:
181private Q_SLOTS:
222 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
182 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
@@ -237,7 +197,6 @@ private:
237 void setFocusedWindow(Window *window);
197 void setFocusedWindow(Window *window);
238 void removeInputMethodWindow();
198 void removeInputMethodWindow();
239 int findIndexOf(const unity::shell::application::MirSurfaceInterface *surface) const;
199 int findIndexOf(const unity::shell::application::MirSurfaceInterface *surface) const;
240− void deleteAt(int index);
241 void removeAt(int index);
200 void removeAt(int index);
242
201
243 void addApplication(unity::shell::application::ApplicationInfoInterface *application);
202 void addApplication(unity::shell::application::ApplicationInfoInterface *application);
@@ -248,7 +207,6 @@ private:
248 unity::shell::application::ApplicationInfoInterface *application);
207 unity::shell::application::ApplicationInfoInterface *application);
249 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
208 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
250 unity::shell::application::ApplicationInfoInterface *application);
209 unity::shell::application::ApplicationInfoInterface *application);
251− void prependWindow(Window *window, unity::shell::application::ApplicationInfoInterface *application);
252
210
253 void connectWindow(Window *window);
211 void connectWindow(Window *window);
254 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
212 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
@@ -262,10 +220,6 @@ private:
262
220
263 void activateTopMostWindowWithoutId(int forbiddenId);
221 void activateTopMostWindowWithoutId(int forbiddenId);
264
222
265− Window *createWindow(unity::shell::application::MirSurfaceInterface *surface);
266− Window *createWindowWithId(unity::shell::application::MirSurfaceInterface *surface, int id);
267− Window *createNullWindow();
268−
269 struct ModelEntry {
223 struct ModelEntry {
270 ModelEntry() {}
224 ModelEntry() {}
271 ModelEntry(Window *window,
225 ModelEntry(Window *window,
@@ -279,15 +233,15 @@ private:
279 QVector<ModelEntry> m_windowModel;
233 QVector<ModelEntry> m_windowModel;
280 Window* m_inputMethodWindow{nullptr};
234 Window* m_inputMethodWindow{nullptr};
281 Window* m_focusedWindow{nullptr};
235 Window* m_focusedWindow{nullptr};
282− Window* m_nullWindow;
283− Window* m_previousWindow{nullptr};
284− bool m_pendingActivation;
285
236
286− QAtomicInteger<int> m_nextId{1};
237+ int m_nextId{1};
238+ // Just something big enough that we don't risk running out of unused id numbers.
239+ // Not sure if QML int type supports something close to std::numeric_limits<int>::max() and
240+ // there's no reason to try out its limits.
241+ static const int m_maxId{1000000};
287
242
288 unity::shell::application::ApplicationManagerInterface* m_applicationManager{nullptr};
243 unity::shell::application::ApplicationManagerInterface* m_applicationManager{nullptr};
289 unity::shell::application::SurfaceManagerInterface *m_surfaceManager{nullptr};
244 unity::shell::application::SurfaceManagerInterface *m_surfaceManager{nullptr};
290− bool m_surfaceManagerBusy;
291
245
292 enum ModelState {
246 enum ModelState {
293 IdleState,
247 IdleState,
@@ -301,8 +255,6 @@ private:
301 // Valid between modificationsStarted and modificationsEnded
255 // Valid between modificationsStarted and modificationsEnded
302 bool m_focusedWindowChanged{false};
256 bool m_focusedWindowChanged{false};
303 Window *m_newlyFocusedWindow{nullptr};
257 Window *m_newlyFocusedWindow{nullptr};
304−
305− bool m_closingAllApps{false};
306};
258};
307
259
308#endif // TOPLEVELWINDOWMODEL_H
260#endif // TOPLEVELWINDOWMODEL_H
plugins/WindowManager/Window.cpp+1−41
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@ namespace unityapi = unity::shell::application;
27Q_LOGGING_CATEGORY(UNITY_WINDOW, "unity.window", QtWarningMsg)
27Q_LOGGING_CATEGORY(UNITY_WINDOW, "unity.window", QtWarningMsg)
28
28
29#define DEBUG_MSG qCDebug(UNITY_WINDOW).nospace() << qPrintable(toString()) << "::" << __func__
29#define DEBUG_MSG qCDebug(UNITY_WINDOW).nospace() << qPrintable(toString()) << "::" << __func__
30−#define WARNING_MSG qCWarning(UNITY_WINDOW).nospace() << qPrintable(toString()) << "::" << __func__
31
30
32Window::Window(int id, QObject *parent)
31Window::Window(int id, QObject *parent)
33 : QObject(parent)
32 : QObject(parent)
@@ -68,23 +67,6 @@ void Window::setRequestedPosition(const QPoint &value)
68 }
67 }
69}
68}
70
69
71−bool Window::allowClientResize() const
72−{
73− return m_allowClientResize;
74−}
75−
76−void Window::setAllowClientResize(bool value)
77−{
78− if (value != m_allowClientResize) {
79− DEBUG_MSG << "("<<value<<")";
80− m_allowClientResize = value;
81− if (m_surface) {
82− m_surface->setAllowClientResize(value);
83− }
84− Q_EMIT allowClientResizeChanged(m_allowClientResize);
85− }
86−}
87−
88Mir::State Window::state() const
70Mir::State Window::state() const
89{
71{
90 return m_state;
72 return m_state;
@@ -172,35 +154,13 @@ void Window::setSurface(unityapi::MirSurfaceInterface *surface)
172 updateFocused();
154 updateFocused();
173 });
155 });
174
156
175− connect(surface, &unityapi::MirSurfaceInterface::allowClientResizeChanged, this, [this]() {
176− if (m_surface->allowClientResize() != m_allowClientResize) {
177− m_allowClientResize = m_surface->allowClientResize();
178− Q_EMIT allowClientResizeChanged(m_allowClientResize);
179− }
180− });
181−
182− connect(surface, &unityapi::MirSurfaceInterface::liveChanged, this, &Window::liveChanged);
183−
184− connect(surface, &QObject::destroyed, this, [this]() {
185− setSurface(nullptr);
186− });
187−
188− // Surface should never be focused at this point!
189− if (m_surface->focused()) {
190− WARNING_MSG << "Inital surface is focused!";
191− }
192−
193 // bring it up to speed
157 // bring it up to speed
194− if (m_focused) {
195− m_surface->activate();
196− }
197 if (m_positionRequested) {
158 if (m_positionRequested) {
198 m_surface->setRequestedPosition(m_requestedPosition);
159 m_surface->setRequestedPosition(m_requestedPosition);
199 }
160 }
200 if (m_stateRequested && m_surface->state() == Mir::RestoredState) {
161 if (m_stateRequested && m_surface->state() == Mir::RestoredState) {
201 m_surface->requestState(m_state);
162 m_surface->requestState(m_state);
202 }
163 }
203− m_surface->setAllowClientResize(m_allowClientResize);
204
164
205 // and sync with surface
165 // and sync with surface
206 updatePosition();
166 updatePosition();
plugins/WindowManager/Window.h+3−18
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -24,8 +24,6 @@
24// Unity API
24// Unity API
25#include <unity/shell/application/Mir.h>
25#include <unity/shell/application/Mir.h>
26
26
27−#include "WindowManagerGlobal.h"
28−
29namespace unity {
27namespace unity {
30 namespace shell {
28 namespace shell {
31 namespace application {
29 namespace application {
@@ -34,6 +32,7 @@ namespace unity {
34 }
32 }
35}
33}
36
34
35+
37Q_DECLARE_LOGGING_CATEGORY(UNITY_WINDOW)
36Q_DECLARE_LOGGING_CATEGORY(UNITY_WINDOW)
38
37
39/**
38/**
@@ -44,7 +43,7 @@ Q_DECLARE_LOGGING_CATEGORY(UNITY_WINDOW)
44 was killed to free up memory, as it should still remain in the window list since the user
43 was killed to free up memory, as it should still remain in the window list since the user
45 did not explicitly close it).
44 did not explicitly close it).
46 */
45 */
47−class WINDOWMANAGERQML_EXPORT Window : public QObject
46+class Window : public QObject
48{
47{
49 Q_OBJECT
48 Q_OBJECT
50
49
@@ -91,13 +90,6 @@ class WINDOWMANAGERQML_EXPORT Window : public QObject
91 */
90 */
92 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
91 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
93
92
94− /**
95− * @brief Whether to comply to resize requests coming from the client side
96− *
97− * It's true by default
98− */
99− Q_PROPERTY(bool allowClientResize READ allowClientResize WRITE setAllowClientResize NOTIFY allowClientResizeChanged)
100−
101public:
93public:
102 Window(int id, QObject *parent = nullptr);
94 Window(int id, QObject *parent = nullptr);
103 virtual ~Window();
95 virtual ~Window();
@@ -113,9 +105,6 @@ public:
113 void setSurface(unity::shell::application::MirSurfaceInterface *surface);
105 void setSurface(unity::shell::application::MirSurfaceInterface *surface);
114 void setFocused(bool value);
106 void setFocused(bool value);
115
107
116− bool allowClientResize() const;
117− void setAllowClientResize(bool);
118−
119 QString toString() const;
108 QString toString() const;
120
109
121public Q_SLOTS:
110public Q_SLOTS:
@@ -145,8 +134,6 @@ Q_SIGNALS:
145 void focusedChanged(bool value);
134 void focusedChanged(bool value);
146 void confinesMousePointerChanged(bool value);
135 void confinesMousePointerChanged(bool value);
147 void surfaceChanged(unity::shell::application::MirSurfaceInterface *surface);
136 void surfaceChanged(unity::shell::application::MirSurfaceInterface *surface);
148− void allowClientResizeChanged(bool value);
149− void liveChanged(bool value);
150
137
151 /**
138 /**
152 * @brief Emitted when focus for this window is requested by an external party
139 * @brief Emitted when focus for this window is requested by an external party
@@ -166,8 +153,6 @@ private:
166 Mir::State m_state{Mir::RestoredState};
153 Mir::State m_state{Mir::RestoredState};
167 bool m_stateRequested{false};
154 bool m_stateRequested{false};
168 unity::shell::application::MirSurfaceInterface *m_surface{nullptr};
155 unity::shell::application::MirSurfaceInterface *m_surface{nullptr};
169−
170− bool m_allowClientResize{true};
171};
156};
172
157
173QDebug operator<<(QDebug dbg, const Window *window);
158QDebug operator<<(QDebug dbg, const Window *window);
plugins/WindowManager/WindowManagerPlugin.cpp+1−14
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016-2017 Canonical, Ltd.
2+ * Copyright (C) 2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -16,27 +16,14 @@
16
16
17#include "WindowManagerPlugin.h"
17#include "WindowManagerPlugin.h"
18
18
19−#include "AvailableDesktopArea.h"
20#include "TopLevelWindowModel.h"
19#include "TopLevelWindowModel.h"
21#include "Window.h"
20#include "Window.h"
22−#include "WindowMargins.h"
23−#include "InputMethodManager.h"
24
21
25#include <QtQml>
22#include <QtQml>
26
23
27−QObject *inputMethodManager(QQmlEngine *engine, QJSEngine *scriptEngine)
28−{
29− Q_UNUSED(engine)
30− Q_UNUSED(scriptEngine)
31− return InputMethodManager::instance();
32−}
33−
34void WindowManagerPlugin::registerTypes(const char *uri)
24void WindowManagerPlugin::registerTypes(const char *uri)
35{
25{
36− qmlRegisterType<AvailableDesktopArea>(uri, 1, 0, "AvailableDesktopArea");
37 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
26 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
38− qmlRegisterType<WindowMargins>(uri, 1, 0, "WindowMargins");
39− qmlRegisterSingletonType<InputMethodManager>(uri, 1, 0, "InputMethodManager", inputMethodManager);
40
27
41 qRegisterMetaType<Window*>("Window*");
28 qRegisterMetaType<Window*>("Window*");
42
29
plugins/WindowManager/WindowMargins.cppdeleted−74
@@ -1,74 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it under
5− * the terms of the GNU Lesser General Public License version 3, as published by
6− * the Free Software Foundation.
7− *
8− * This program is distributed in the hope that it will be useful, but WITHOUT
9− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11− * Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "WindowMargins.h"
18−
19−#include <QGuiApplication>
20−#include <QQuickWindow>
21−#include <qpa/qplatformnativeinterface.h>
22−
23−void WindowMargins::setNormal(QRectF value)
24−{
25− if (m_normal == value) {
26− return;
27− }
28−
29− m_normal = value;
30−
31− if (window()) {
32− QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
33− nativeInterface->setWindowProperty(window()->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
34− }
35−
36− Q_EMIT normalChanged();
37−}
38−
39−QRectF WindowMargins::normal() const
40−{
41− return m_normal;
42−}
43−
44−void WindowMargins::setDialog(QRectF value)
45−{
46− if (m_dialog == value) {
47− return;
48− }
49−
50− m_dialog = value;
51−
52− if (window()) {
53− QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
54− nativeInterface->setWindowProperty(window()->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
55− }
56−
57− Q_EMIT dialogChanged();
58−}
59−
60−QRectF WindowMargins::dialog() const
61−{
62− return m_dialog;
63−}
64−
65−void WindowMargins::itemChange(ItemChange change, const ItemChangeData &data)
66−{
67− if (change == ItemSceneChange && data.window != nullptr) {
68− QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
69− if (!m_normal.isNull()) {
70− nativeInterface->setWindowProperty(data.window->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
71− nativeInterface->setWindowProperty(data.window->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
72− }
73− }
74−}
plugins/WindowManager/WindowMargins.hdeleted−59
@@ -1,59 +0,0 @@
1−/*
2− * Copyright (C) 2017 Canonical, Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it under
5− * the terms of the GNU Lesser General Public License version 3, as published by
6− * the Free Software Foundation.
7− *
8− * This program is distributed in the hope that it will be useful, but WITHOUT
9− * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10− * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11− * Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef WINDOWMARGINS_H
18−#define WINDOWMARGINS_H
19−
20−#include <QQuickItem>
21−#include <QRectF>
22−
23−/*
24− * Specifies window margins for different Mir window types
25− *
26− * Used to inform MirAL so that it can take window management decisions that match
27− * the visuals drawn by Unity.
28− */
29−class WindowMargins : public QQuickItem
30−{
31− Q_OBJECT
32−
33− // Margins for windows of normal type
34− Q_PROPERTY(QRectF normal READ normal WRITE setNormal NOTIFY normalChanged)
35−
36− // Margins for windows of dialog type
37− Q_PROPERTY(QRectF dialog READ dialog WRITE setDialog NOTIFY dialogChanged)
38−
39− // TODO: Add margins for other window types as needed
40−
41−public:
42− QRectF normal() const;
43− void setNormal(QRectF value);
44−
45− QRectF dialog() const;
46− void setDialog(QRectF value);
47−
48−protected:
49− void itemChange(ItemChange change, const ItemChangeData &value) override;
50−
51−Q_SIGNALS:
52− void normalChanged();
53− void dialogChanged();
54−private:
55− QRectF m_normal;
56− QRectF m_dialog;
57−};
58−
59−#endif // WINDOWMARGINS_H
plugins/Wizard/CMakeLists.txt+2−5
@@ -10,13 +10,10 @@ add_library(Wizard-qml MODULE
10 timezonemodel.cpp
10 timezonemodel.cpp
11 Status.cpp
11 Status.cpp
12 keyboardLayoutsModel.cpp
12 keyboardLayoutsModel.cpp
13− Changelog.cpp
14)
13)
15
14
16−target_link_libraries(Wizard-qml
15+qt5_use_modules(Wizard-qml DBus Qml)
17− Qt5::DBus Qt5::Qml
18− ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS}
16+target_link_libraries(Wizard-qml ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
19−)
20add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
17add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
21
18
22set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
19set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
plugins/Wizard/Changelog.cppdeleted−58
@@ -1,58 +0,0 @@
1−/*
2− * Copyright (C) 2018 The UBports project
3− * Written by: Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software: you can redistribute it and/or modify it
6− * under the terms of the GNU General Public License version 3, as published
7− * by the Free Software Foundation.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License along
15− * with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#include "Changelog.h"
19−
20−#include <QDir>
21−#include <QFile>
22−#include <QTextStream>
23−
24−Changelog::Changelog()
25− : QObject()
26−{
27− readChangelog();
28− if(QFile::exists(changelogPath()))
29− m_fsWatcher.addPath(changelogPath());
30− connect(&m_fsWatcher, &QFileSystemWatcher::fileChanged, this, &Changelog::watcherFileChanged);
31−}
32−
33−QString Changelog::changelogPath()
34−{
35− return "/usr/share/ubports/changelogs/current";
36−}
37−
38−QString Changelog::text() const
39−{
40− return m_text;
41−}
42−
43−void Changelog::readChangelog()
44−{
45− if(!QFile::exists(changelogPath()))
46− return;
47− QFile f(changelogPath());
48− if (!f.open(QFile::ReadOnly | QFile::Text)) return;
49− QTextStream in(&f);
50− m_text = in.readAll();
51− Q_EMIT textChanged();
52−}
53−
54−void Changelog::watcherFileChanged()
55−{
56− readChangelog();
57− m_fsWatcher.removePath(changelogPath());
58−}
plugins/Wizard/Changelog.hdeleted−52
@@ -1,52 +0,0 @@
1−/*
2− * Copyright (C) 2018 The UBports project
3− * Written by: Marius Gripsgard <marius@ubports.com>
4− *
5− * This program is free software: you can redistribute it and/or modify it
6− * under the terms of the GNU General Public License version 3, as published
7− * by the Free Software Foundation.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the GNU General Public License for more details.
13− *
14− * You should have received a copy of the GNU General Public License along
15− * with this program. If not, see <http://www.gnu.org/licenses/>.
16− */
17−
18−#ifndef WIZARD_CHANGELOG_H
19−#define WIZARD_CHANGELOG_H
20−
21−#include <QFileSystemWatcher>
22−#include <QObject>
23−#include <QString>
24−
25−class Changelog : public QObject
26−{
27− Q_OBJECT
28− Q_PROPERTY(QString text READ text NOTIFY textChanged)
29−
30−public:
31− Changelog();
32− ~Changelog() = default;
33−
34− QString text() const;
35−
36−Q_SIGNALS:
37− void textChanged();
38−
39−private Q_SLOTS:
40− void watcherFileChanged();
41−
42−private:
43− Q_DISABLE_COPY(Changelog)
44−
45− static QString changelogPath();
46− void readChangelog();
47−
48− QFileSystemWatcher m_fsWatcher;
49− QString m_text;
50−};
51−
52−#endif
plugins/Wizard/PageList.cpp+5−6
@@ -46,7 +46,9 @@ PageList::PageList(QObject *parent)
46 QSet<QString> disabledPages;
46 QSet<QString> disabledPages;
47 QStringList dataDirs;
47 QStringList dataDirs;
48
48
49− if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) {
49+ if (getenv("WIZARD_TESTING") != nullptr) {
50+ dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
51+ } else if (!isRunningInstalled()) {
50 dataDirs << qmlDirectory();
52 dataDirs << qmlDirectory();
51 } else {
53 } else {
52 dataDirs = shellDataDirs();
54 dataDirs = shellDataDirs();
@@ -71,11 +73,8 @@ PageList::PageList(QObject *parent)
71 // If there was a system update installed, skip until the last page to just greet the user
73 // If there was a system update installed, skip until the last page to just greet the user
72 QSettings settings;
74 QSettings settings;
73 if (settings.value(QStringLiteral("Wizard/SkipUntilFinishedPage")).toBool()) {
75 if (settings.value(QStringLiteral("Wizard/SkipUntilFinishedPage")).toBool()) {
74− const QString lastPage = m_pages.lastKey();
76+ while (m_pages.count() > 1) {
75− Q_FOREACH(const QString &page, m_pages.keys()) {
77+ m_pages.erase(m_pages.begin());
76− if (Q_UNLIKELY(page != lastPage)) {
77− m_pages.remove(page);
78− }
79 }
78 }
80
79
81 // ... and reset it again for the next run
80 // ... and reset it again for the next run
plugins/Wizard/System.cpp+7−69
@@ -1,5 +1,4 @@
1/*
1/*
2− * Copyright (C) 2018 The UBports project
3 * Copyright (C) 2014-2016 Canonical Ltd.
2 * Copyright (C) 2014-2016 Canonical Ltd.
4 *
3 *
5 * This program is free software: you can redistribute it and/or modify it
4 * This program is free software: you can redistribute it and/or modify it
@@ -47,93 +46,29 @@ QString System::wizardEnabledPath()
47 return QDir::home().filePath(QStringLiteral(".config/ubuntu-system-settings/wizard-has-run"));
46 return QDir::home().filePath(QStringLiteral(".config/ubuntu-system-settings/wizard-has-run"));
48}
47}
49
48
50−QString System::currentFrameworkPath()
51−{
52− QFileInfo f("/usr/share/click/frameworks/current");
53− return f.canonicalFilePath();
54−}
55−
56−/*
57−wizardEnabled and isUpdate logic
58−
59−if wizard-has-run does NOT exist == is new install
60−if wizard-has-run exists but does NOT match current framework == is update
61−if wizard-has-run exists but does match current framework == show no wizard
62−*/
63−
64−bool System::wizardPathExists() {
65− return QFile::exists(wizardEnabledPath());
66−}
67−
68bool System::wizardEnabled() const
49bool System::wizardEnabled() const
69{
50{
70− if (!wizardPathExists()) {
71− return true;
72− }
73− return isUpdate();
74−}
75−
76−QString System::readCurrentFramework()
77−{
78− QFile f(currentFrameworkPath());
79− if (!f.open(QFile::ReadOnly | QFile::Text)) return "";
80− QTextStream in(&f);
81− return in.readAll();
82−}
83−
84−QString System::readWizardEnabled()
85−{
86− QFile f(wizardEnabledPath());
51+ return !QFile::exists(wizardEnabledPath());
87− if (!f.open(QFile::ReadOnly | QFile::Text)) return "";
88− QTextStream in(&f);
89− return in.readAll();
90−}
91−
92−QString System::version() const
93−{
94− return readCurrentFramework();
95−}
96−
97−bool System::isUpdate() const
98−{
99− if (!wizardPathExists()) {
100− return false;
101− }
102−
103− return readCurrentFramework() != readWizardEnabled();
104}
52}
105
53
106void System::setWizardEnabled(bool enabled)
54void System::setWizardEnabled(bool enabled)
107{
55{
108− if (wizardEnabled() == enabled && !isUpdate())
56+ if (wizardEnabled() == enabled)
109 return;
57 return;
110
58
111 if (enabled) {
59 if (enabled) {
112 QFile::remove(wizardEnabledPath());
60 QFile::remove(wizardEnabledPath());
113 } else {
61 } else {
114 QDir(wizardEnabledPath()).mkpath(QStringLiteral(".."));
62 QDir(wizardEnabledPath()).mkpath(QStringLiteral(".."));
115− if (QFile::exists(wizardEnabledPath())) {
116− QFile::remove(wizardEnabledPath());
117− }
118− // For special cases check if wizardEnabledPath is a folder
119− if (QDir(wizardEnabledPath()).exists()) {
120− QDir(wizardEnabledPath()).removeRecursively();
121− }
122− if (!QFile::copy(currentFrameworkPath(), wizardEnabledPath())) {
63+ QFile(wizardEnabledPath()).open(QIODevice::WriteOnly);
123− // Make en empty file if framework does not exist
124− QFile f(wizardEnabledPath());
125− f.open(QFile::WriteOnly);
126− }
127 m_fsWatcher.addPath(wizardEnabledPath());
64 m_fsWatcher.addPath(wizardEnabledPath());
128 Q_EMIT wizardEnabledChanged();
65 Q_EMIT wizardEnabledChanged();
129− Q_EMIT isUpdateChanged();
130 }
66 }
131}
67}
132
68
133void System::watcherFileChanged()
69void System::watcherFileChanged()
134{
70{
135 Q_EMIT wizardEnabledChanged();
71 Q_EMIT wizardEnabledChanged();
136− Q_EMIT isUpdateChanged();
137 m_fsWatcher.removePath(wizardEnabledPath());
72 m_fsWatcher.removePath(wizardEnabledPath());
138}
73}
139
74
@@ -168,10 +103,13 @@ void System::updateSessionLocale(const QString &locale)
168
103
169 // Restart bits of the session to pick up new language.
104 // Restart bits of the session to pick up new language.
170 QProcess::startDetached(QStringLiteral("sh -c \"initctl emit indicator-services-end; \
105 QProcess::startDetached(QStringLiteral("sh -c \"initctl emit indicator-services-end; \
106+ initctl stop scope-registry; \
107+ initctl stop smart-scopes-proxy; \
171 initctl emit --no-wait indicator-services-start; \
108 initctl emit --no-wait indicator-services-start; \
172 initctl restart --no-wait ubuntu-location-service-trust-stored; \
109 initctl restart --no-wait ubuntu-location-service-trust-stored; \
173 initctl restart --no-wait maliit-server; \
110 initctl restart --no-wait maliit-server; \
174− initctl restart --no-wait indicator-messages"));
111+ initctl restart --no-wait indicator-messages; \
112+ initctl restart --no-wait unity8-dash\""));
175}
113}
176
114
177void System::skipUntilFinishedPage()
115void System::skipUntilFinishedPage()
plugins/Wizard/System.h−17
@@ -1,5 +1,4 @@
1/*
1/*
2− * Copyright (C) 2018 The UBports project
3 * Copyright (C) 2014-2016 Canonical Ltd.
2 * Copyright (C) 2014-2016 Canonical Ltd.
4 *
3 *
5 * This program is free software: you can redistribute it and/or modify it
4 * This program is free software: you can redistribute it and/or modify it
@@ -19,7 +18,6 @@
19#define WIZARD_SYSTEM_H
18#define WIZARD_SYSTEM_H
20
19
21#include <QFileSystemWatcher>
20#include <QFileSystemWatcher>
22−#include <QVersionNumber>
23#include <QObject>
21#include <QObject>
24#include <QString>
22#include <QString>
25
23
@@ -27,21 +25,12 @@ class System : public QObject
27{
25{
28 Q_OBJECT
26 Q_OBJECT
29 Q_PROPERTY(bool wizardEnabled READ wizardEnabled WRITE setWizardEnabled NOTIFY wizardEnabledChanged)
27 Q_PROPERTY(bool wizardEnabled READ wizardEnabled WRITE setWizardEnabled NOTIFY wizardEnabledChanged)
30− Q_PROPERTY(QString version READ version NOTIFY versionChanged)
31− Q_PROPERTY(bool isUpdate READ isUpdate NOTIFY isUpdateChanged)
32
28
33public:
29public:
34 System();
30 System();
35 ~System() = default;
31 ~System() = default;
36
32
37− /**
38− * Checks whether the wizard is enabled for first-run or otherwise.
39− */
40 bool wizardEnabled() const;
33 bool wizardEnabled() const;
41−
42− QString version() const;
43− bool isUpdate() const;
44−
45 void setWizardEnabled(bool enabled);
34 void setWizardEnabled(bool enabled);
46
35
47public Q_SLOTS:
36public Q_SLOTS:
@@ -53,8 +42,6 @@ public Q_SLOTS:
53
42
54Q_SIGNALS:
43Q_SIGNALS:
55 void wizardEnabledChanged();
44 void wizardEnabledChanged();
56− void versionChanged();
57− void isUpdateChanged();
58
45
59private Q_SLOTS:
46private Q_SLOTS:
60 void watcherFileChanged();
47 void watcherFileChanged();
@@ -63,11 +50,7 @@ private:
63 Q_DISABLE_COPY(System)
50 Q_DISABLE_COPY(System)
64
51
65 static QString wizardEnabledPath();
52 static QString wizardEnabledPath();
66− static QString currentFrameworkPath();
67 static void setSessionVariable(const QString &variable, const QString &value);
53 static void setSessionVariable(const QString &variable, const QString &value);
68− static QString readCurrentFramework();
69− static QString readWizardEnabled();
70− static bool wizardPathExists();
71
54
72 QFileSystemWatcher m_fsWatcher;
55 QFileSystemWatcher m_fsWatcher;
73};
56};
plugins/Wizard/Utils/CMakeLists.txt+1−1
@@ -20,7 +20,7 @@ add_library(WizardUtils-qml SHARED
20# files directly in targets.
20# files directly in targets.
21set_target_properties(WizardUtils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
21set_target_properties(WizardUtils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
22
22
23−target_link_libraries(WizardUtils-qml Qt5::DBus Qt5::Qml Qt5::Quick)
23+qt5_use_modules(WizardUtils-qml DBus Qml Quick)
24
24
25set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/Wizard/Utils)
25set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/Wizard/Utils)
26install(FILES qmldir DESTINATION ${PLUG_DIR})
26install(FILES qmldir DESTINATION ${PLUG_DIR})
plugins/Wizard/plugin.cpp−2
@@ -20,7 +20,6 @@
20#include "timezonemodel.h"
20#include "timezonemodel.h"
21#include "LocalePlugin.h"
21#include "LocalePlugin.h"
22#include "Status.h"
22#include "Status.h"
23−#include "Changelog.h"
24#include "keyboardLayoutsModel.h"
23#include "keyboardLayoutsModel.h"
25
24
26#include <QtQml/qqml.h>
25#include <QtQml/qqml.h>
@@ -31,7 +30,6 @@ void WizardPlugin::registerTypes(const char *uri)
31 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
30 qmlRegisterType<PageList>(uri, 0, 1, "PageList");
32 qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
31 qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
33 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
32 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
34− qmlRegisterSingletonType<Changelog>(uri, 0, 1, "Changelog", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Changelog; });
35 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
33 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
36 qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
34 qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
37 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
35 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
plugins/Wizard/test.shnew file+18
@@ -0,0 +1,18 @@
1+#!/bin/sh
2+
3+TOPDIR=$(readlink -e "$(dirname ${0})/..")
4+
5+LOCAL_PRIVATE_DIR=$(ls -d ${TOPDIR}/debian/tmp/usr/lib/*/ubuntu-system-settings/private)
6+if [ -n ${LOCAL_PRIVATE_DIR} ]; then
7+ echo "Testing against locally built version"
8+ export UBUNTU_SYSTEM_SETTINGS_WIZARD_ROOT="${TOPDIR}/debian/tmp/usr/share"
9+ export UBUNTU_SYSTEM_SETTINGS_WIZARD_MODULES="${LOCAL_PRIVATE_DIR}"
10+ export QML2_IMPORT_PATH=${LOCAL_PRIVATE_DIR}:${QML2_IMPORT_PATH}
11+ export PATH=${TOPDIR}/debian/tmp/usr/bin:${PATH}
12+else
13+ echo "Testing against system version"
14+fi
15+
16+export QML2_IMPORT_PATH=${TOPDIR}/tests/mocks:${QML2_IMPORT_PATH}
17+
18+exec system-settings-wizard
plugins/Wizard/timezonemodel.h+1−1
@@ -27,7 +27,6 @@ class TimeZoneLocationModel: public QAbstractListModel
27 Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged)
27 Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged)
28 Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
28 Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
29 Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged)
29 Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged)
30− Q_ENUMS(Roles)
31
30
32public:
31public:
33 explicit TimeZoneLocationModel(QObject *parent = nullptr);
32 explicit TimeZoneLocationModel(QObject *parent = nullptr);
@@ -42,6 +41,7 @@ public:
42 LatitudeRole,
41 LatitudeRole,
43 LongitudeRole
42 LongitudeRole
44 };
43 };
44+ Q_ENUM(Roles)
45
45
46 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
46 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
47 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
47 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
po/aa.po+324−231
@@ -6,58 +6,28 @@
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9−"Report-Msgid-Bugs-To: \n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2021-01-29 11:42-0600\n"
10+"POT-Creation-Date: 2017-01-10 14:48+0000\n"
11−"PO-Revision-Date: 2021-03-08 10:42+0000\n"
11+"PO-Revision-Date: 2016-02-12 10:18+0000\n"
12−"Last-Translator: TigranKhachatryan0 <tigrank2008@gmail.com>\n"
12+"Last-Translator: Charif AYFARAH <ayfarah@ymail.com>\n"
13−"Language-Team: Afar <https://translate.ubports.com/projects/ubports/lomiri/"
13+"Language-Team: Afar <aa@li.org>\n"
14−"aa/>\n"
15−"Language: aa\n"
16"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Generator: Weblate 3.11.3\n"
21−"X-Launchpad-Export-Date: 2016-11-23 06:34+0000\n"
18+"X-Launchpad-Export-Date: 2017-01-16 05:47+0000\n"
19+"X-Generator: Launchpad (build 18302)\n"
22
20
23−#: plugins/LightDM/Greeter.cpp:199
21+#: plugins/LightDM/Greeter.cpp:123
24msgid "Password: "
22msgid "Password: "
25−msgstr ""
23+msgstr "Cuumita "
26−
27−#: plugins/LightDM/Greeter.cpp:214
28−msgid "Username"
29−msgstr ""
30−
31−#: plugins/LightDM/Greeter.cpp:258
32−msgid "Failed to authenticate"
33−msgstr ""
34−
35−#: plugins/LightDM/Greeter.cpp:260
36−msgid "Invalid password, please try again"
37−msgstr ""
38−
39−#: plugins/LightDM/Greeter.cpp:270
40−msgid "Log In"
41−msgstr ""
42−
43−#: plugins/LightDM/Greeter.cpp:270
44−msgid "Retry"
45−msgstr "Qagis"
46
24
47−#: plugins/LightDM/UsersModel.cpp:157
48−msgid "Login"
49−msgstr ""
50−
51−#: plugins/LightDM/UsersModel.cpp:165
52−msgid "Guest Session"
53−msgstr ""
54−
55−#: plugins/Unity/Launcher/launcheritem.cpp:48
25+#: plugins/Unity/Launcher/launcheritem.cpp:50
56#: plugins/Unity/Launcher/launcheritem.cpp:122
26#: plugins/Unity/Launcher/launcheritem.cpp:122
57msgid "Pin shortcut"
27msgid "Pin shortcut"
58msgstr ""
28msgstr ""
59
29
60−#: plugins/Unity/Launcher/launcheritem.cpp:54
30+#: plugins/Unity/Launcher/launcheritem.cpp:55
61msgid "Quit"
31msgid "Quit"
62msgstr "Kat"
32msgstr "Kat"
63
33
@@ -65,79 +35,76 @@ msgstr "Kat"
65msgid "Unpin shortcut"
35msgid "Unpin shortcut"
66msgstr ""
36msgstr ""
67
37
68−#: qml/Components/Dialogs.qml:176
38+#: qml/Components/Dialogs.qml:149
69msgctxt "Title: Lock/Log out dialog"
39msgctxt "Title: Lock/Log out dialog"
70msgid "Log out"
40msgid "Log out"
71msgstr "Eweq"
41msgstr "Eweq"
72
42
73−#: qml/Components/Dialogs.qml:177
43+#: qml/Components/Dialogs.qml:150
74msgid "Are you sure you want to log out?"
44msgid "Are you sure you want to log out?"
75msgstr ""
45msgstr ""
76
46
77−#: qml/Components/Dialogs.qml:180
47+#: qml/Components/Dialogs.qml:152
78msgctxt "Button: Lock the system"
48msgctxt "Button: Lock the system"
79msgid "Lock"
49msgid "Lock"
80msgstr "Koflis"
50msgstr "Koflis"
81
51
82−#: qml/Components/Dialogs.qml:191
52+#: qml/Components/Dialogs.qml:160
83msgctxt "Button: Log out from the system"
53msgctxt "Button: Log out from the system"
84msgid "Log Out"
54msgid "Log Out"
85msgstr "Eweq"
55msgstr "Eweq"
86
56
87−#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
57+#: qml/Components/Dialogs.qml:167 qml/Components/Dialogs.qml:225
58+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:232
88−#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
59+#: qml/Wizard/Pages/passcode-confirm.qml:32
89#: qml/Wizard/Pages/passcode-set.qml:32
60#: qml/Wizard/Pages/passcode-set.qml:32
90msgid "Cancel"
61msgid "Cancel"
91msgstr "Bayis"
62msgstr "Bayis"
92
63
93−#: qml/Components/Dialogs.qml:211
64+#: qml/Components/Dialogs.qml:179
94msgctxt "Title: Reboot dialog"
65msgctxt "Title: Reboot dialog"
95msgid "Reboot"
66msgid "Reboot"
96msgstr "Wadir-ugus"
67msgstr "Wadir-ugus"
97
68
98−#: qml/Components/Dialogs.qml:212
69+#: qml/Components/Dialogs.qml:180
99msgid "Are you sure you want to reboot?"
70msgid "Are you sure you want to reboot?"
100msgstr "Wadir-ugussuh digga maay litoo?"
71msgstr "Wadir-ugussuh digga maay litoo?"
101
72
102−#: qml/Components/Dialogs.qml:215
73+#: qml/Components/Dialogs.qml:182
103msgid "No"
74msgid "No"
104msgstr "Maleey"
75msgstr "Maleey"
105
76
106−#: qml/Components/Dialogs.qml:223
77+#: qml/Components/Dialogs.qml:189
107msgid "Yes"
78msgid "Yes"
108msgstr "Yeey"
79msgstr "Yeey"
109
80
110−#: qml/Components/Dialogs.qml:243
81+#: qml/Components/Dialogs.qml:204
111msgctxt "Title: Power off/Restart dialog"
82msgctxt "Title: Power off/Restart dialog"
112msgid "Power"
83msgid "Power"
113msgstr "Cayla"
84msgstr "Cayla"
114
85
115−#: qml/Components/Dialogs.qml:244
86+#: qml/Components/Dialogs.qml:205
116msgid ""
87msgid ""
117"Are you sure you would like\n"
88"Are you sure you would like\n"
118"to power off?"
89"to power off?"
119msgstr "Timmi haytuh digga maay litoo?"
90msgstr "Timmi haytuh digga maay litoo?"
120
91
121−#: qml/Components/Dialogs.qml:248
92+#: qml/Components/Dialogs.qml:208
122msgctxt "Button: Power off the system"
93msgctxt "Button: Power off the system"
123msgid "Power off"
94msgid "Power off"
124msgstr "Timmi hayis"
95msgstr "Timmi hayis"
125
96
126−#: qml/Components/Dialogs.qml:263
97+#: qml/Components/Dialogs.qml:217
127msgctxt "Button: Restart the system"
98msgctxt "Button: Restart the system"
128msgid "Restart"
99msgid "Restart"
129msgstr "Wadir-qimbis"
100msgstr "Wadir-qimbis"
130
101
131−#: qml/Components/Dialogs.qml:276
132−msgid "Screenshot"
133−msgstr ""
134−
135#: qml/Components/KeyboardShortcutsOverlay.qml:41
102#: qml/Components/KeyboardShortcutsOverlay.qml:41
136msgid "Keyboard Shortcuts"
103msgid "Keyboard Shortcuts"
137msgstr ""
104msgstr ""
138
105
139#: qml/Components/KeyboardShortcutsOverlay.qml:55
106#: qml/Components/KeyboardShortcutsOverlay.qml:55
140−msgid "Lomiri"
107+msgid "Unity 8"
141msgstr ""
108msgstr ""
142
109
143#: qml/Components/KeyboardShortcutsOverlay.qml:62
110#: qml/Components/KeyboardShortcutsOverlay.qml:62
@@ -153,7 +120,7 @@ msgid "Alt + PrtScr"
153msgstr ""
120msgstr ""
154
121
155#: qml/Components/KeyboardShortcutsOverlay.qml:80
122#: qml/Components/KeyboardShortcutsOverlay.qml:80
156−msgid "Takes a screenshot of the current window."
123+msgid "Takes a screenshot of a window."
157msgstr ""
124msgstr ""
158
125
159#: qml/Components/KeyboardShortcutsOverlay.qml:88
126#: qml/Components/KeyboardShortcutsOverlay.qml:88
@@ -172,131 +139,135 @@ msgstr ""
172msgid "Switches to previous keyboard layout."
139msgid "Switches to previous keyboard layout."
173msgstr ""
140msgstr ""
174
141
175−#: qml/Components/KeyboardShortcutsOverlay.qml:114
142+#: qml/Components/KeyboardShortcutsOverlay.qml:118
176−msgid "Ctrl + Alt + T"
143+msgid "Launcher"
177msgstr ""
144msgstr ""
178
145
179−#: qml/Components/KeyboardShortcutsOverlay.qml:119
146+#: qml/Components/KeyboardShortcutsOverlay.qml:125
180−msgid "Starts the Terminal application."
147+msgid "Super (Hold)"
181msgstr ""
148msgstr ""
182
149
183−#: qml/Components/KeyboardShortcutsOverlay.qml:131
150+#: qml/Components/KeyboardShortcutsOverlay.qml:130
184−msgid "Launcher"
151+msgid "Opens the launcher, displays shortcuts."
185msgstr ""
152msgstr ""
186
153
187#: qml/Components/KeyboardShortcutsOverlay.qml:138
154#: qml/Components/KeyboardShortcutsOverlay.qml:138
188−msgid "Super (Hold)"
155+msgid "Alt + F1"
189msgstr ""
156msgstr ""
190
157
191#: qml/Components/KeyboardShortcutsOverlay.qml:143
158#: qml/Components/KeyboardShortcutsOverlay.qml:143
192−msgid "Opens the launcher, displays shortcuts."
159+msgid "Opens launcher keyboard navigation mode."
193msgstr ""
160msgstr ""
194
161
195#: qml/Components/KeyboardShortcutsOverlay.qml:151
162#: qml/Components/KeyboardShortcutsOverlay.qml:151
196−msgid "Alt + F1"
163+msgid "Super + Tab"
197msgstr ""
164msgstr ""
198
165
199#: qml/Components/KeyboardShortcutsOverlay.qml:156
166#: qml/Components/KeyboardShortcutsOverlay.qml:156
200−msgid "Opens launcher keyboard navigation mode."
167+msgid "Switches applications via the launcher."
201msgstr ""
168msgstr ""
202
169
203#: qml/Components/KeyboardShortcutsOverlay.qml:164
170#: qml/Components/KeyboardShortcutsOverlay.qml:164
204−msgid "Super + Tab"
171+msgid "Super + 0 to 9"
205msgstr ""
172msgstr ""
206
173
207#: qml/Components/KeyboardShortcutsOverlay.qml:169
174#: qml/Components/KeyboardShortcutsOverlay.qml:169
208−msgid "Switches applications via the launcher."
175+msgid "Same as clicking on a launcher icon."
209msgstr ""
176msgstr ""
210
177
211#: qml/Components/KeyboardShortcutsOverlay.qml:177
178#: qml/Components/KeyboardShortcutsOverlay.qml:177
212−msgid "Super + 1 to 0"
179+msgid "Super + A"
213msgstr ""
180msgstr ""
214
181
215#: qml/Components/KeyboardShortcutsOverlay.qml:182
182#: qml/Components/KeyboardShortcutsOverlay.qml:182
216−msgid "Same as clicking on a launcher icon."
183+msgid "Opens the Application Drawer."
217msgstr ""
184msgstr ""
218
185
219−#: qml/Components/KeyboardShortcutsOverlay.qml:190
186+#: qml/Components/KeyboardShortcutsOverlay.qml:194
220−msgid "Super + A"
187+msgid "Scopes"
221msgstr ""
188msgstr ""
222
189
223−#: qml/Components/KeyboardShortcutsOverlay.qml:195
190+#: qml/Components/KeyboardShortcutsOverlay.qml:201
224−msgid "Opens the Application Drawer."
191+msgid "Super (Tap)"
225msgstr ""
192msgstr ""
226
193
227−#: qml/Components/KeyboardShortcutsOverlay.qml:235
194+#: qml/Components/KeyboardShortcutsOverlay.qml:206
195+msgid "Opens the Scopes home."
196+msgstr ""
197+
198+#: qml/Components/KeyboardShortcutsOverlay.qml:222
228msgid "Switching"
199msgid "Switching"
229msgstr ""
200msgstr ""
230
201
231−#: qml/Components/KeyboardShortcutsOverlay.qml:242
202+#: qml/Components/KeyboardShortcutsOverlay.qml:229
232msgid "Alt + Tab"
203msgid "Alt + Tab"
233msgstr ""
204msgstr ""
234
205
235−#: qml/Components/KeyboardShortcutsOverlay.qml:247
206+#: qml/Components/KeyboardShortcutsOverlay.qml:234
236msgid "Switches between applications."
207msgid "Switches between applications."
237msgstr ""
208msgstr ""
238
209
239−#: qml/Components/KeyboardShortcutsOverlay.qml:255
210+#: qml/Components/KeyboardShortcutsOverlay.qml:242
240msgid "Super + W"
211msgid "Super + W"
241msgstr ""
212msgstr ""
242
213
243−#: qml/Components/KeyboardShortcutsOverlay.qml:260
214+#: qml/Components/KeyboardShortcutsOverlay.qml:247
244msgid "Opens the desktop spread."
215msgid "Opens the desktop spread."
245msgstr ""
216msgstr ""
246
217
247−#: qml/Components/KeyboardShortcutsOverlay.qml:268
218+#: qml/Components/KeyboardShortcutsOverlay.qml:255
248msgid "Cursor Left or Right"
219msgid "Cursor Left or Right"
249msgstr ""
220msgstr ""
250
221
251−#: qml/Components/KeyboardShortcutsOverlay.qml:273
222+#: qml/Components/KeyboardShortcutsOverlay.qml:260
252msgid "Moves the focus."
223msgid "Moves the focus."
253msgstr ""
224msgstr ""
254
225
255−#: qml/Components/KeyboardShortcutsOverlay.qml:285
226+#: qml/Components/KeyboardShortcutsOverlay.qml:272
256msgid "Windows"
227msgid "Windows"
257msgstr ""
228msgstr ""
258
229
259−#: qml/Components/KeyboardShortcutsOverlay.qml:292
230+#: qml/Components/KeyboardShortcutsOverlay.qml:279
260msgid "Ctrl + Super + D"
231msgid "Ctrl + Super + D"
261msgstr ""
232msgstr ""
262
233
263−#: qml/Components/KeyboardShortcutsOverlay.qml:297
234+#: qml/Components/KeyboardShortcutsOverlay.qml:284
264msgid "Minimizes all windows."
235msgid "Minimizes all windows."
265msgstr ""
236msgstr ""
266
237
267−#: qml/Components/KeyboardShortcutsOverlay.qml:305
238+#: qml/Components/KeyboardShortcutsOverlay.qml:292
268msgid "Ctrl + Super + Up"
239msgid "Ctrl + Super + Up"
269msgstr ""
240msgstr ""
270
241
271−#: qml/Components/KeyboardShortcutsOverlay.qml:310
242+#: qml/Components/KeyboardShortcutsOverlay.qml:297
272msgid "Maximizes the current window."
243msgid "Maximizes the current window."
273msgstr ""
244msgstr ""
274
245
275−#: qml/Components/KeyboardShortcutsOverlay.qml:318
246+#: qml/Components/KeyboardShortcutsOverlay.qml:305
276msgid "Ctrl + Super + Down"
247msgid "Ctrl + Super + Down"
277msgstr ""
248msgstr ""
278
249
279−#: qml/Components/KeyboardShortcutsOverlay.qml:323
250+#: qml/Components/KeyboardShortcutsOverlay.qml:310
280msgid "Minimizes or restores the current window."
251msgid "Minimizes or restores the current window."
281msgstr ""
252msgstr ""
282
253
283−#: qml/Components/KeyboardShortcutsOverlay.qml:331
254+#: qml/Components/KeyboardShortcutsOverlay.qml:318
284msgid "Ctrl + Super + Left or Right"
255msgid "Ctrl + Super + Left or Right"
285msgstr ""
256msgstr ""
286
257
287−#: qml/Components/KeyboardShortcutsOverlay.qml:336
258+#: qml/Components/KeyboardShortcutsOverlay.qml:323
288msgid "Semi-maximizes the current window."
259msgid "Semi-maximizes the current window."
289msgstr ""
260msgstr ""
290
261
291−#: qml/Components/KeyboardShortcutsOverlay.qml:344
262+#: qml/Components/KeyboardShortcutsOverlay.qml:331
292msgid "Alt + F4"
263msgid "Alt + F4"
293msgstr ""
264msgstr ""
294
265
295−#: qml/Components/KeyboardShortcutsOverlay.qml:349
266+#: qml/Components/KeyboardShortcutsOverlay.qml:336
296msgid "Closes the current window."
267msgid "Closes the current window."
297msgstr ""
268msgstr ""
298
269
299−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:235
270+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:252
300msgid "Return to Call"
271msgid "Return to Call"
301msgstr "Seecol gacis"
272msgstr "Seecol gacis"
302
273
@@ -304,7 +275,7 @@ msgstr "Seecol gacis"
304msgid "Emergency Call"
275msgid "Emergency Call"
305msgstr ""
276msgstr ""
306
277
307−#: qml/Components/Lockscreen.qml:245
278+#: qml/Components/Lockscreen.qml:244
308msgid "OK"
279msgid "OK"
309msgstr "Hayya"
280msgstr "Hayya"
310
281
@@ -318,29 +289,29 @@ msgstr ""
318msgid "%1:%2"
289msgid "%1:%2"
319msgstr ""
290msgstr ""
320
291
321−#: qml/Components/ModeSwitchWarningDialog.qml:33
292+#: qml/Components/ModeSwitchWarningDialog.qml:32
322msgid "Apps may have unsaved data:"
293msgid "Apps may have unsaved data:"
323msgstr ""
294msgstr ""
324
295
325−#: qml/Components/ModeSwitchWarningDialog.qml:60
296+#: qml/Components/ModeSwitchWarningDialog.qml:57
326msgctxt ""
297msgctxt ""
327"Re-dock means connect the device again to an external screen/mouse/keyboard"
298"Re-dock means connect the device again to an external screen/mouse/keyboard"
328msgid "Re-dock, save your work and close these apps to continue."
299msgid "Re-dock, save your work and close these apps to continue."
329msgstr ""
300msgstr ""
330
301
331−#: qml/Components/ModeSwitchWarningDialog.qml:67
302+#: qml/Components/ModeSwitchWarningDialog.qml:63
332msgid "Or force close now (unsaved data will be lost)."
303msgid "Or force close now (unsaved data will be lost)."
333msgstr ""
304msgstr ""
334
305
335−#: qml/Components/ModeSwitchWarningDialog.qml:80
306+#: qml/Components/ModeSwitchWarningDialog.qml:75
336msgid "OK, I will reconnect"
307msgid "OK, I will reconnect"
337msgstr ""
308msgstr ""
338
309
339−#: qml/Components/ModeSwitchWarningDialog.qml:81
310+#: qml/Components/ModeSwitchWarningDialog.qml:76
340msgid "Reconnect now!"
311msgid "Reconnect now!"
341msgstr ""
312msgstr ""
342
313
343−#: qml/Components/ModeSwitchWarningDialog.qml:94
314+#: qml/Components/ModeSwitchWarningDialog.qml:88
344msgid "Close all"
315msgid "Close all"
345msgstr "Inkih alif"
316msgstr "Inkih alif"
346
317
@@ -370,6 +341,103 @@ msgstr ""
370msgid "Find more settings in the system settings."
341msgid "Find more settings in the system settings."
371msgstr ""
342msgstr ""
372
343
344+#: qml/Dash/DashPageHeader.qml:361
345+msgctxt "Button: Open the Ubuntu Store"
346+msgid "Store"
347+msgstr ""
348+
349+#: qml/Dash/DashPageHeader.qml:368
350+msgctxt "Button: Start a search in the current dash scope"
351+msgid "Search"
352+msgstr "Goranto"
353+
354+#: qml/Dash/DashPageHeader.qml:378
355+msgctxt "Button: Show the current dash scope settings"
356+msgid "Settings"
357+msgstr "Massosu"
358+
359+#: qml/Dash/DashPageHeader.qml:385
360+msgid "Remove from Favorites"
361+msgstr ""
362+
363+#: qml/Dash/DashPageHeader.qml:385
364+msgid "Add to Favorites"
365+msgstr ""
366+
367+#: qml/Dash/FiltersPopover.qml:61
368+msgid "Refine your results"
369+msgstr ""
370+
371+#: qml/Dash/FiltersPopover.qml:70
372+msgid "Reset"
373+msgstr ""
374+
375+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
376+msgid "Show less"
377+msgstr ""
378+
379+#: qml/Dash/GenericScopeView.qml:547
380+msgid "Show all"
381+msgstr ""
382+
383+#: qml/Dash/GenericScopeView.qml:578
384+msgctxt "Label: Hint for dash search line edit"
385+msgid "Search"
386+msgstr "Goranto"
387+
388+#: qml/Dash/PageHeaderExtraPanel.qml:67
389+msgid "Recent Searches"
390+msgstr ""
391+
392+#: qml/Dash/PageHeaderExtraPanel.qml:78
393+msgid "Clear All"
394+msgstr ""
395+
396+#: qml/Dash/Previews/PreviewActionCombo.qml:36
397+msgid "More..."
398+msgstr ""
399+
400+#: qml/Dash/Previews/PreviewActionCombo.qml:36
401+msgid "Less..."
402+msgstr ""
403+
404+#: qml/Dash/Previews/PreviewCommentInput.qml:83
405+#: qml/Dash/Previews/PreviewRatingInput.qml:202
406+msgid "Send"
407+msgstr "Rub"
408+
409+#: qml/Dash/Previews/PreviewRatingInput.qml:109
410+msgid "Rate this"
411+msgstr ""
412+
413+#: qml/Dash/Previews/PreviewRatingInput.qml:184
414+msgid "Add a review"
415+msgstr ""
416+
417+#: qml/Dash/PullToRefreshScopeStyle.qml:56
418+msgid "Pull to refresh…"
419+msgstr ""
420+
421+#: qml/Dash/PullToRefreshScopeStyle.qml:61
422+msgid "Release to refresh…"
423+msgstr ""
424+
425+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
426+msgid "Enable location data"
427+msgstr ""
428+
429+#: qml/Dash/ScopesList.qml:146
430+msgid "Manage"
431+msgstr ""
432+
433+#: qml/Dash/ScopesList.qml:187
434+msgid "Home"
435+msgstr "Dabqi"
436+
437+#: qml/Dash/ScopesList.qml:188
438+msgid "Also installed"
439+msgstr ""
440+
373#: qml/Greeter/CoverPage.qml:127
441#: qml/Greeter/CoverPage.qml:127
374msgid "Unlock"
442msgid "Unlock"
375msgstr ""
443msgstr ""
@@ -393,51 +461,45 @@ msgid_plural "Please wait %1 minutes and then try again…"
393msgstr[0] "Maganak %1 minit qambaalaay, kaadu gabbat"
461msgstr[0] "Maganak %1 minit qambaalaay, kaadu gabbat"
394msgstr[1] "Maganak %1 minit qambaalaay, kaadu gabbat"
462msgstr[1] "Maganak %1 minit qambaalaay, kaadu gabbat"
395
463
396−#: qml/Greeter/Greeter.qml:550
464+#: qml/Greeter/Greeter.qml:592
397msgid "Try again"
465msgid "Try again"
398msgstr ""
466msgstr ""
399
467
400−#: qml/Greeter/Greeter.qml:551
468+#: qml/Greeter/LoginList.qml:70
401−#, fuzzy
469+msgid "Passphrase"
402−#| msgid "Enter passphrase"
403−msgid "Enter passphrase to unlock"
404−msgstr "Tatur-maxco culus"
405−
406−#: qml/Greeter/Greeter.qml:552
407−#, fuzzy
408−#| msgid "Enter passcode"
409−msgid "Enter passcode to unlock"
410−msgstr "Tatur-mudenta culus"
470+msgstr ""
411
471
412−#: qml/Greeter/NarrowView.qml:235
472+#: qml/Greeter/LoginList.qml:71
413−msgid "Emergency"
473+msgid "Passcode"
414msgstr ""
474msgstr ""
415
475
416−#: qml/Greeter/PromptList.qml:126
476+#: qml/Greeter/LoginList.qml:98
477+msgid "Retry"
478+msgstr "Qagis"
479+
480+#: qml/Greeter/LoginList.qml:99
417−msgid "Passphrase"
481+msgid "Log In"
418msgstr ""
482msgstr ""
419
483
420−#: qml/Greeter/PromptList.qml:126
484+#: qml/Greeter/NarrowView.qml:252
421−msgid "Passcode"
485+msgid "Emergency"
422msgstr ""
486msgstr ""
423
487
424−#: qml/Greeter/SessionsList.qml:124
488+#: qml/Greeter/SessionsList.qml:122
425msgid "Select desktop environment"
489msgid "Select desktop environment"
426msgstr ""
490msgstr ""
427
491
428−#: qml/Launcher/Drawer.qml:250
492+#: qml/Launcher/Drawer.qml:80
429−#, fuzzy
430−#| msgctxt "Button: Start a search in the current dash scope"
431−#| msgid "Search"
432msgid "Search…"
493msgid "Search…"
433−msgstr "Goranto"
494+msgstr ""
434
495
435−#: qml/Launcher/PullToRefreshScopeStyle.qml:56
496+#: qml/Launcher/Drawer.qml:101
497+msgctxt "Apps sorted alphabetically"
436−msgid "Pull to refresh…"
498+msgid "A-Z"
437msgstr ""
499msgstr ""
438
500
439−#: qml/Launcher/PullToRefreshScopeStyle.qml:61
501+#: qml/Launcher/MoreAppsHeader.qml:32
440−msgid "Release to refresh…"
502+msgid "More apps in the store"
441msgstr ""
503msgstr ""
442
504
443#: qml/Notifications/NotificationMenuItemFactory.qml:124
505#: qml/Notifications/NotificationMenuItemFactory.qml:124
@@ -527,34 +589,23 @@ msgctxt "Button: Call back on phone"
527msgid "Call back"
589msgid "Call back"
528msgstr ""
590msgstr ""
529
591
530−#: qml/Panel/PanelMenuPage.qml:92
531−#, fuzzy
532−#| msgctxt "Button: Go back one page in the Wizard"
533−#| msgid "Back"
534−msgid "Back"
535−msgstr "Derre"
536−
537#: qml/Stage/SideStage.qml:76
592#: qml/Stage/SideStage.qml:76
538msgid "Drag using 3 fingers any application from one window to the other"
593msgid "Drag using 3 fingers any application from one window to the other"
539msgstr ""
594msgstr ""
540
595
541−#: qml/Stage/Stage.qml:671
542−msgid "No running apps"
543−msgstr ""
544−
545#: qml/Tutorial/TutorialLeftLong.qml:49
596#: qml/Tutorial/TutorialLeftLong.qml:49
546−msgid "Long swipe from the left edge to open the Application Drawer"
597+msgid "Long swipe from the left edge to open the Today scope"
547msgstr ""
598msgstr ""
548
599
549#: qml/Tutorial/TutorialLeft.qml:47
600#: qml/Tutorial/TutorialLeft.qml:47
550msgid "Short swipe from the left edge to open the launcher"
601msgid "Short swipe from the left edge to open the launcher"
551msgstr ""
602msgstr ""
552
603
553−#: qml/Tutorial/TutorialRight.qml:54
604+#: qml/Tutorial/TutorialRight.qml:55
554msgid "Push your mouse against the right edge to view your open apps"
605msgid "Push your mouse against the right edge to view your open apps"
555msgstr ""
606msgstr ""
556
607
557−#: qml/Tutorial/TutorialRight.qml:55
608+#: qml/Tutorial/TutorialRight.qml:56
558msgid "Swipe from the right edge to view your open apps"
609msgid "Swipe from the right edge to view your open apps"
559msgstr ""
610msgstr ""
560
611
@@ -562,41 +613,25 @@ msgstr ""
562msgid "Swipe from the top edge to access notifications and quick settings"
613msgid "Swipe from the top edge to access notifications and quick settings"
563msgstr ""
614msgstr ""
564
615
565−#: qml/Wizard/Page.qml:59
616+#: qml/Wizard/Page.qml:54
566msgctxt "Button: Go back one page in the Wizard"
617msgctxt "Button: Go back one page in the Wizard"
567msgid "Back"
618msgid "Back"
568msgstr "Derre"
619msgstr "Derre"
569
620
570−#: qml/Wizard/Pages/10-welcome.qml:29
621+#: qml/Wizard/Pages/10-welcome.qml:28
571msgid "Language"
622msgid "Language"
572msgstr ""
623msgstr ""
573
624
574−#: qml/Wizard/Pages/10-welcome.qml:176
625+#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
575−#: qml/Wizard/Pages/10-welcome-update.qml:126
626+#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
576−#: qml/Wizard/Pages/11-changelog.qml:74 qml/Wizard/Pages/20-keyboard.qml:152
577−#: qml/Wizard/Pages/30-wifi.qml:214 qml/Wizard/Pages/50-timezone.qml:272
627+#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
578−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/70-passwd-type.qml:146
628+#: qml/Wizard/Pages/70-passwd-type.qml:145
629+#: qml/Wizard/Pages/75-report-check.qml:84
579−#: qml/Wizard/Pages/passcode-desktop.qml:154
630+#: qml/Wizard/Pages/passcode-desktop.qml:142
580−#: qml/Wizard/Pages/password-set.qml:153
631+#: qml/Wizard/Pages/password-set.qml:142
581msgid "Next"
632msgid "Next"
582msgstr ""
633msgstr ""
583
634
584−#: qml/Wizard/Pages/10-welcome-update.qml:91
585−msgid "Welcome to "
586−msgstr ""
587−
588−#: qml/Wizard/Pages/10-welcome-update.qml:106
589−msgid "We will make sure your device is ready to use "
590−msgstr ""
591−
592−#: qml/Wizard/Pages/11-changelog.qml:28
593−msgid "What's new"
594−msgstr ""
595−
596−#: qml/Wizard/Pages/11-changelog.qml:74
597−msgid "Loading..."
598−msgstr ""
599−
600#: qml/Wizard/Pages/20-keyboard.qml:31
635#: qml/Wizard/Pages/20-keyboard.qml:31
601msgid "Select Keyboard"
636msgid "Select Keyboard"
602msgstr ""
637msgstr ""
@@ -609,8 +644,8 @@ msgstr ""
609msgid "Keyboard layout"
644msgid "Keyboard layout"
610msgstr ""
645msgstr ""
611
646
612−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
647+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
613−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
648+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
614#: qml/Wizard/Pages/sim.qml:101
649#: qml/Wizard/Pages/sim.qml:101
615msgid "Skip"
650msgid "Skip"
616msgstr "Kaqit"
651msgstr "Kaqit"
@@ -619,23 +654,55 @@ msgstr "Kaqit"
619msgid "Connect to Wi‑Fi"
654msgid "Connect to Wi‑Fi"
620msgstr ""
655msgstr ""
621
656
622−#: qml/Wizard/Pages/30-wifi.qml:139
657+#: qml/Wizard/Pages/30-wifi.qml:132
623msgid "Connected"
658msgid "Connected"
624msgstr ""
659msgstr ""
625
660
626−#: qml/Wizard/Pages/30-wifi.qml:172
661+#: qml/Wizard/Pages/30-wifi.qml:165
627msgid "Available Wi-Fi networks"
662msgid "Available Wi-Fi networks"
628msgstr ""
663msgstr ""
629
664
630−#: qml/Wizard/Pages/30-wifi.qml:173
665+#: qml/Wizard/Pages/30-wifi.qml:166
631msgid "No available Wi-Fi networks"
666msgid "No available Wi-Fi networks"
632msgstr ""
667msgstr ""
633
668
669+#: qml/Wizard/Pages/40-location.qml:27
670+msgid "Location Services"
671+msgstr ""
672+
673+#: qml/Wizard/Pages/40-location.qml:83
674+msgid ""
675+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
676+"(recommended)"
677+msgstr ""
678+
679+#: qml/Wizard/Pages/40-location.qml:105
680+#, qt-format
681+msgid "By selecting this option you agree to the Nokia HERE %1."
682+msgstr ""
683+
684+#: qml/Wizard/Pages/40-location.qml:106
685+msgctxt "part of: Nokia HERE terms and conditions"
686+msgid "terms and conditions"
687+msgstr ""
688+
689+#: qml/Wizard/Pages/40-location.qml:160
690+msgid "GPS only"
691+msgstr ""
692+
693+#: qml/Wizard/Pages/40-location.qml:214
694+msgid "Don't use my location"
695+msgstr ""
696+
697+#: qml/Wizard/Pages/40-location.qml:260
698+msgid "You can change it later in System Settings."
699+msgstr ""
700+
634#: qml/Wizard/Pages/50-timezone.qml:30
701#: qml/Wizard/Pages/50-timezone.qml:30
635msgid "Time Zone"
702msgid "Time Zone"
636msgstr ""
703msgstr ""
637
704
638−#: qml/Wizard/Pages/50-timezone.qml:183
705+#: qml/Wizard/Pages/50-timezone.qml:182
639msgid "Enter your city"
706msgid "Enter your city"
640msgstr ""
707msgstr ""
641
708
@@ -643,7 +710,7 @@ msgstr ""
643msgid "Personalize Your Device"
710msgid "Personalize Your Device"
644msgstr ""
711msgstr ""
645
712
646−#: qml/Wizard/Pages/60-account.qml:54
713+#: qml/Wizard/Pages/60-account.qml:48
647msgid "Preferred Name"
714msgid "Preferred Name"
648msgstr ""
715msgstr ""
649
716
@@ -651,72 +718,110 @@ msgstr ""
651msgid "Lock Screen"
718msgid "Lock Screen"
652msgstr ""
719msgstr ""
653
720
654−#: qml/Wizard/Pages/70-passwd-type.qml:103
721+#: qml/Wizard/Pages/70-passwd-type.qml:102
655msgctxt "Label: Type of security method"
722msgctxt "Label: Type of security method"
656msgid "Create new password"
723msgid "Create new password"
657msgstr ""
724msgstr ""
658
725
659−#: qml/Wizard/Pages/70-passwd-type.qml:105
726+#: qml/Wizard/Pages/70-passwd-type.qml:104
660msgctxt "Label: Type of security method"
727msgctxt "Label: Type of security method"
661msgid "Create passcode (numbers only)"
728msgid "Create passcode (numbers only)"
662msgstr ""
729msgstr ""
663
730
664−#: qml/Wizard/Pages/70-passwd-type.qml:107
731+#: qml/Wizard/Pages/70-passwd-type.qml:106
665msgctxt "Label: Type of security method"
732msgctxt "Label: Type of security method"
666msgid "No lock code"
733msgid "No lock code"
667msgstr ""
734msgstr ""
668
735
736+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
737+msgid "Privacy Policy"
738+msgstr ""
739+
740+#: qml/Wizard/Pages/75-report-check.qml:26
741+msgid "Help Us Improve"
742+msgstr ""
743+
744+#: qml/Wizard/Pages/75-report-check.qml:59
745+msgid "Improve system performance by sending us crashes and error reports."
746+msgstr ""
747+
748+#: qml/Wizard/Pages/75-report-check.qml:60
749+msgid "Privacy policy"
750+msgstr ""
751+
669−#: qml/Wizard/Pages/79-system-update.qml:28
752+#: qml/Wizard/Pages/77-system-update.qml:28
670msgid "Update Device"
753msgid "Update Device"
671msgstr ""
754msgstr ""
672
755
673−#: qml/Wizard/Pages/79-system-update.qml:55
756+#: qml/Wizard/Pages/77-system-update.qml:55
674msgid ""
757msgid ""
675"There is a system update available and ready to install. Afterwards, the "
758"There is a system update available and ready to install. Afterwards, the "
676"device will automatically restart."
759"device will automatically restart."
677msgstr ""
760msgstr ""
678
761
679−#: qml/Wizard/Pages/79-system-update.qml:76
762+#: qml/Wizard/Pages/77-system-update.qml:76
680msgctxt "string identifying name of the update"
763msgctxt "string identifying name of the update"
681−msgid "Ubuntu Touch system"
764+msgid "Ubuntu system"
682msgstr ""
765msgstr ""
683
766
684−#: qml/Wizard/Pages/79-system-update.qml:83
767+#: qml/Wizard/Pages/77-system-update.qml:83
685#, qt-format
768#, qt-format
686msgctxt "version of the system update"
769msgctxt "version of the system update"
687msgid "Version %1"
770msgid "Version %1"
688msgstr ""
771msgstr ""
689
772
690−#: qml/Wizard/Pages/79-system-update.qml:95
773+#: qml/Wizard/Pages/77-system-update.qml:102
691msgid "This could take a few minutes..."
774msgid "This could take a few minutes..."
692msgstr ""
775msgstr ""
693
776
694−#: qml/Wizard/Pages/79-system-update.qml:109
777+#: qml/Wizard/Pages/77-system-update.qml:116
695msgid "Install and restart now"
778msgid "Install and restart now"
696msgstr ""
779msgstr ""
697
780
698−#: qml/Wizard/Pages/80-finished.qml:91
781+#: qml/Wizard/Pages/80-finished.qml:89
699−msgid "Welcome Back"
700−msgstr ""
701−
702−#: qml/Wizard/Pages/80-finished.qml:91
703msgid "Welcome to Ubuntu"
782msgid "Welcome to Ubuntu"
704msgstr ""
783msgstr ""
705
784
706−#: qml/Wizard/Pages/80-finished.qml:106
785+#: qml/Wizard/Pages/80-finished.qml:104
707msgid "You are ready to use your device now"
786msgid "You are ready to use your device now"
708msgstr ""
787msgstr ""
709
788
710−#: qml/Wizard/Pages/80-finished.qml:126
789+#: qml/Wizard/Pages/80-finished.qml:124
711−msgid "Continue"
712−msgstr "Tatur"
713−
714−#: qml/Wizard/Pages/80-finished.qml:126
715msgid "Get Started"
790msgid "Get Started"
716msgstr ""
791msgstr ""
717
792
793+#: qml/Wizard/Pages/here-terms.qml:25
794+msgid "Terms & Conditions"
795+msgstr ""
796+
797+#: qml/Wizard/Pages/here-terms.qml:69
798+msgid "Your device uses positioning technologies provided by HERE."
799+msgstr ""
800+
801+#: qml/Wizard/Pages/here-terms.qml:81
802+msgid ""
803+"To provide you with positioning services and to improve their quality, HERE "
804+"collects information about nearby cell towers and Wi-Fi hotspots around your "
805+"current location whenever your position is being found."
806+msgstr ""
807+
808+#: qml/Wizard/Pages/here-terms.qml:93
809+msgid ""
810+"The information collected is used to analyze the service and to improve the "
811+"use of service, but not to identify you personally."
812+msgstr ""
813+
814+#: qml/Wizard/Pages/here-terms.qml:106
815+#, qt-format
816+msgid "By continuing, you agree to the HERE platform %1 and %2."
817+msgstr ""
818+
819+#: qml/Wizard/Pages/here-terms.qml:107
820+msgid "Service Terms"
821+msgstr ""
822+
718#: qml/Wizard/Pages/passcode-confirm.qml:43
823#: qml/Wizard/Pages/passcode-confirm.qml:43
719−#: qml/Wizard/Pages/passcode-desktop.qml:104
824+#: qml/Wizard/Pages/passcode-desktop.qml:97
720msgid "Confirm passcode"
825msgid "Confirm passcode"
721msgstr ""
826msgstr ""
722
827
@@ -733,24 +838,24 @@ msgstr ""
733msgid "Lock Screen Passcode"
838msgid "Lock Screen Passcode"
734msgstr ""
839msgstr ""
735
840
736−#: qml/Wizard/Pages/passcode-desktop.qml:68
841+#: qml/Wizard/Pages/passcode-desktop.qml:61
737msgid "Enter 4 numbers to setup your passcode"
842msgid "Enter 4 numbers to setup your passcode"
738msgstr ""
843msgstr ""
739
844
740−#: qml/Wizard/Pages/passcode-desktop.qml:84
845+#: qml/Wizard/Pages/passcode-desktop.qml:77
741#: qml/Wizard/Pages/passcode-set.qml:54
846#: qml/Wizard/Pages/passcode-set.qml:54
742msgid "Choose passcode"
847msgid "Choose passcode"
743msgstr ""
848msgstr ""
744
849
745−#: qml/Wizard/Pages/passcode-desktop.qml:139
850+#: qml/Wizard/Pages/passcode-desktop.qml:127
746msgid "Passcode too short"
851msgid "Passcode too short"
747msgstr ""
852msgstr ""
748
853
749−#: qml/Wizard/Pages/passcode-desktop.qml:141
854+#: qml/Wizard/Pages/passcode-desktop.qml:129
750msgid "Passcodes match"
855msgid "Passcodes match"
751msgstr ""
856msgstr ""
752
857
753−#: qml/Wizard/Pages/passcode-desktop.qml:143
858+#: qml/Wizard/Pages/passcode-desktop.qml:131
754msgid "Passcodes do not match"
859msgid "Passcodes do not match"
755msgstr ""
860msgstr ""
756
861
@@ -762,15 +867,15 @@ msgstr ""
762msgid "Lock Screen Password"
867msgid "Lock Screen Password"
763msgstr ""
868msgstr ""
764
869
765−#: qml/Wizard/Pages/password-set.qml:68
870+#: qml/Wizard/Pages/password-set.qml:62
766msgid "Enter at least 8 characters"
871msgid "Enter at least 8 characters"
767msgstr ""
872msgstr ""
768
873
769−#: qml/Wizard/Pages/password-set.qml:80
874+#: qml/Wizard/Pages/password-set.qml:74
770msgid "Choose password"
875msgid "Choose password"
771msgstr ""
876msgstr ""
772
877
773−#: qml/Wizard/Pages/password-set.qml:110
878+#: qml/Wizard/Pages/password-set.qml:104
774msgid "Confirm password"
879msgid "Confirm password"
775msgstr ""
880msgstr ""
776
881
@@ -826,28 +931,6 @@ msgstr ""
826msgid "Very weak password"
931msgid "Very weak password"
827msgstr ""
932msgstr ""
828
933
829−#~ msgctxt "Button: Show the current dash scope settings"
830−#~ msgid "Settings"
831−#~ msgstr "Massosu"
832−
833−#~ msgctxt "Label: Hint for dash search line edit"
834−#~ msgid "Search"
835−#~ msgstr "Goranto"
836−
837−#~ msgid "Send"
838−#~ msgstr "Rub"
839−
840−#~ msgid "Home"
841−#~ msgstr "Dabqi"
842−
843−#, fuzzy
844−#~ msgid "Download"
845−#~ msgstr "Qulluumah"
846−
847−#, fuzzy
848−#~ msgid "Downloaded"
849−#~ msgstr "Qulluumah"
850−
851#~ msgctxt "Title: Reboot/Shut down dialog"
934#~ msgctxt "Title: Reboot/Shut down dialog"
852#~ msgid "Shut down"
935#~ msgid "Shut down"
853#~ msgstr "Bargus"
936#~ msgstr "Bargus"
@@ -863,9 +946,16 @@ msgstr ""
863#~ msgid "Reboot"
946#~ msgid "Reboot"
864#~ msgstr "Wadir-ugus"
947#~ msgstr "Wadir-ugus"
865
948
949+#, qt-format
866#~ msgid "Enter %1"
950#~ msgid "Enter %1"
867#~ msgstr "%1 culus"
951#~ msgstr "%1 culus"
868
952
953+#~ msgid "Enter passphrase"
954+#~ msgstr "Tatur-maxco culus"
955+
956+#~ msgid "Enter passcode"
957+#~ msgstr "Tatur-mudenta culus"
958+
869#~ msgctxt "Label: Type of security method"
959#~ msgctxt "Label: Type of security method"
870#~ msgid "Swipe"
960#~ msgid "Swipe"
871#~ msgstr "Uysuttuc"
961#~ msgstr "Uysuttuc"
@@ -878,3 +968,6 @@ msgstr ""
878
968
879#~ msgid "Let’s get started."
969#~ msgid "Let’s get started."
880#~ msgstr "Hayya qimbisnay."
970#~ msgstr "Hayya qimbisnay."
971+
972+#~ msgid "Continue"
973+#~ msgstr "Tatur"
po/am.po+365−441
@@ -6,58 +6,28 @@
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9−"Report-Msgid-Bugs-To: \n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2021-01-29 11:42-0600\n"
10+"POT-Creation-Date: 2017-01-10 14:48+0000\n"
11−"PO-Revision-Date: 2021-08-29 20:18+0000\n"
11+"PO-Revision-Date: 2016-08-13 14:45+0000\n"
12−"Last-Translator: Samson <sambelet@yahoo.com>\n"
12+"Last-Translator: samson <Unknown>\n"
13−"Language-Team: Amharic <https://translate.ubports.com/projects/ubports/"
13+"Language-Team: Amharic <am@li.org>\n"
14−"lomiri/am/>\n"
15−"Language: am\n"
16"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
20−"X-Generator: Weblate 3.11.3\n"
21−"X-Launchpad-Export-Date: 2016-11-23 06:34+0000\n"
18+"X-Launchpad-Export-Date: 2017-01-16 05:47+0000\n"
19+"X-Generator: Launchpad (build 18302)\n"
22
20
23−#: plugins/LightDM/Greeter.cpp:199
21+#: plugins/LightDM/Greeter.cpp:123
24msgid "Password: "
22msgid "Password: "
25msgstr "የ መግቢያ ቃል: "
23msgstr "የ መግቢያ ቃል: "
26
24
27−#: plugins/LightDM/Greeter.cpp:214
28−msgid "Username"
29−msgstr "የ ተጠቃሚ ስም"
30−
31−#: plugins/LightDM/Greeter.cpp:258
32−msgid "Failed to authenticate"
33−msgstr "ማረጋገጥ አልተቻለም"
34−
35−#: plugins/LightDM/Greeter.cpp:260
36−msgid "Invalid password, please try again"
37−msgstr "ዋጋ የሌለው የ መግቢያ ቃል: እባክዎን እንደገና ይሞክሩ"
38−
39−#: plugins/LightDM/Greeter.cpp:270
40−msgid "Log In"
41−msgstr "መግቢያ"
42−
43−#: plugins/LightDM/Greeter.cpp:270
44−msgid "Retry"
45−msgstr "እንደገና ይሞክሩ"
46−
47−#: plugins/LightDM/UsersModel.cpp:157
48−msgid "Login"
49−msgstr "መግቢያ"
50−
51−#: plugins/LightDM/UsersModel.cpp:165
52−msgid "Guest Session"
53−msgstr "የ እንግዳ ክፍለ ጊዜ"
54−
55−#: plugins/Unity/Launcher/launcheritem.cpp:48
25+#: plugins/Unity/Launcher/launcheritem.cpp:50
56#: plugins/Unity/Launcher/launcheritem.cpp:122
26#: plugins/Unity/Launcher/launcheritem.cpp:122
57msgid "Pin shortcut"
27msgid "Pin shortcut"
58msgstr "አቋራጭ ማጣበቂያ"
28msgstr "አቋራጭ ማጣበቂያ"
59
29
60−#: plugins/Unity/Launcher/launcheritem.cpp:54
30+#: plugins/Unity/Launcher/launcheritem.cpp:55
61msgid "Quit"
31msgid "Quit"
62msgstr "ማጥፊያ"
32msgstr "ማጥፊያ"
63
33
@@ -65,54 +35,55 @@ msgstr "ማጥፊያ"
65msgid "Unpin shortcut"
35msgid "Unpin shortcut"
66msgstr "አቋራጭ መለያያ"
36msgstr "አቋራጭ መለያያ"
67
37
68−#: qml/Components/Dialogs.qml:176
38+#: qml/Components/Dialogs.qml:149
69msgctxt "Title: Lock/Log out dialog"
39msgctxt "Title: Lock/Log out dialog"
70msgid "Log out"
40msgid "Log out"
71msgstr "መውጫ"
41msgstr "መውጫ"
72
42
73−#: qml/Components/Dialogs.qml:177
43+#: qml/Components/Dialogs.qml:150
74msgid "Are you sure you want to log out?"
44msgid "Are you sure you want to log out?"
75msgstr "በእርግጥ መውጣት ይፈልጋሉ?"
45msgstr "በእርግጥ መውጣት ይፈልጋሉ?"
76
46
77−#: qml/Components/Dialogs.qml:180
47+#: qml/Components/Dialogs.qml:152
78msgctxt "Button: Lock the system"
48msgctxt "Button: Lock the system"
79msgid "Lock"
49msgid "Lock"
80msgstr "መቆለፊያ"
50msgstr "መቆለፊያ"
81
51
82−#: qml/Components/Dialogs.qml:191
52+#: qml/Components/Dialogs.qml:160
83msgctxt "Button: Log out from the system"
53msgctxt "Button: Log out from the system"
84msgid "Log Out"
54msgid "Log Out"
85msgstr "መውጫ"
55msgstr "መውጫ"
86
56
87−#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
57+#: qml/Components/Dialogs.qml:167 qml/Components/Dialogs.qml:225
58+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:232
88−#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
59+#: qml/Wizard/Pages/passcode-confirm.qml:32
89#: qml/Wizard/Pages/passcode-set.qml:32
60#: qml/Wizard/Pages/passcode-set.qml:32
90msgid "Cancel"
61msgid "Cancel"
91msgstr "መሰረዣ"
62msgstr "መሰረዣ"
92
63
93−#: qml/Components/Dialogs.qml:211
64+#: qml/Components/Dialogs.qml:179
94msgctxt "Title: Reboot dialog"
65msgctxt "Title: Reboot dialog"
95msgid "Reboot"
66msgid "Reboot"
96msgstr "እንደገና ማስነሻ"
67msgstr "እንደገና ማስነሻ"
97
68
98−#: qml/Components/Dialogs.qml:212
69+#: qml/Components/Dialogs.qml:180
99msgid "Are you sure you want to reboot?"
70msgid "Are you sure you want to reboot?"
100msgstr "በእርግጥ እንደገና ማስነሳት ይፈልጋሉ?"
71msgstr "በእርግጥ እንደገና ማስነሳት ይፈልጋሉ?"
101
72
102−#: qml/Components/Dialogs.qml:215
73+#: qml/Components/Dialogs.qml:182
103msgid "No"
74msgid "No"
104msgstr "አይ"
75msgstr "አይ"
105
76
106−#: qml/Components/Dialogs.qml:223
77+#: qml/Components/Dialogs.qml:189
107msgid "Yes"
78msgid "Yes"
108msgstr "አዎ"
79msgstr "አዎ"
109
80
110−#: qml/Components/Dialogs.qml:243
81+#: qml/Components/Dialogs.qml:204
111msgctxt "Title: Power off/Restart dialog"
82msgctxt "Title: Power off/Restart dialog"
112msgid "Power"
83msgid "Power"
113msgstr "ሐይል"
84msgstr "ሐይል"
114
85
115−#: qml/Components/Dialogs.qml:244
86+#: qml/Components/Dialogs.qml:205
116msgid ""
87msgid ""
117"Are you sure you would like\n"
88"Are you sure you would like\n"
118"to power off?"
89"to power off?"
@@ -120,27 +91,23 @@ msgstr ""
120"በእርግጥ ሐይሉን ማጥፋት\n"
91"በእርግጥ ሐይሉን ማጥፋት\n"
121"ይፈልጋሉ?"
92"ይፈልጋሉ?"
122
93
123−#: qml/Components/Dialogs.qml:248
94+#: qml/Components/Dialogs.qml:208
124msgctxt "Button: Power off the system"
95msgctxt "Button: Power off the system"
125msgid "Power off"
96msgid "Power off"
126msgstr "ሐይል ማጥፊያ"
97msgstr "ሐይል ማጥፊያ"
127
98
128−#: qml/Components/Dialogs.qml:263
99+#: qml/Components/Dialogs.qml:217
129msgctxt "Button: Restart the system"
100msgctxt "Button: Restart the system"
130msgid "Restart"
101msgid "Restart"
131msgstr "እንደገና ማስጀመሪያ"
102msgstr "እንደገና ማስጀመሪያ"
132
103
133−#: qml/Components/Dialogs.qml:276
134−msgid "Screenshot"
135−msgstr "መመልከቻ ፎቶ ማንሻ"
136−
137#: qml/Components/KeyboardShortcutsOverlay.qml:41
104#: qml/Components/KeyboardShortcutsOverlay.qml:41
138msgid "Keyboard Shortcuts"
105msgid "Keyboard Shortcuts"
139msgstr "የ ፊደል ገበታ አቋራጮች"
106msgstr "የ ፊደል ገበታ አቋራጮች"
140
107
141#: qml/Components/KeyboardShortcutsOverlay.qml:55
108#: qml/Components/KeyboardShortcutsOverlay.qml:55
142−msgid "Lomiri"
109+msgid "Unity 8"
143−msgstr "Lomiri"
110+msgstr "Unity 8"
144
111
145#: qml/Components/KeyboardShortcutsOverlay.qml:62
112#: qml/Components/KeyboardShortcutsOverlay.qml:62
146msgid "PrtScr"
113msgid "PrtScr"
@@ -155,8 +122,8 @@ msgid "Alt + PrtScr"
155msgstr "Alt + PrtScr"
122msgstr "Alt + PrtScr"
156
123
157#: qml/Components/KeyboardShortcutsOverlay.qml:80
124#: qml/Components/KeyboardShortcutsOverlay.qml:80
158−msgid "Takes a screenshot of the current window."
125+msgid "Takes a screenshot of a window."
159−msgstr "የ አሁኑን መስኮት መመልከቻ ፎቶ ማንሻ"
126+msgstr "የ መስኮት መመልከቻ ፎቶ ማንሻ"
160
127
161#: qml/Components/KeyboardShortcutsOverlay.qml:88
128#: qml/Components/KeyboardShortcutsOverlay.qml:88
162msgid "Super + Space"
129msgid "Super + Space"
@@ -174,131 +141,135 @@ msgstr "Super + Shift + Space"
174msgid "Switches to previous keyboard layout."
141msgid "Switches to previous keyboard layout."
175msgstr "ወዳለፈው የ ፊደል ገበታ እቅድ መቀየሪያ"
142msgstr "ወዳለፈው የ ፊደል ገበታ እቅድ መቀየሪያ"
176
143
177−#: qml/Components/KeyboardShortcutsOverlay.qml:114
144+#: qml/Components/KeyboardShortcutsOverlay.qml:118
178−msgid "Ctrl + Alt + T"
179−msgstr "Ctrl + Alt + T"
180−
181−#: qml/Components/KeyboardShortcutsOverlay.qml:119
182−msgid "Starts the Terminal application."
183−msgstr "የ ተርሚናል መተግበሪያ ማስጀመሪያ"
184−
185−#: qml/Components/KeyboardShortcutsOverlay.qml:131
186msgid "Launcher"
145msgid "Launcher"
187msgstr "ማስነሻ"
146msgstr "ማስነሻ"
188
147
189−#: qml/Components/KeyboardShortcutsOverlay.qml:138
148+#: qml/Components/KeyboardShortcutsOverlay.qml:125
190msgid "Super (Hold)"
149msgid "Super (Hold)"
191msgstr "Super (ይጫኑ)"
150msgstr "Super (ይጫኑ)"
192
151
193−#: qml/Components/KeyboardShortcutsOverlay.qml:143
152+#: qml/Components/KeyboardShortcutsOverlay.qml:130
194msgid "Opens the launcher, displays shortcuts."
153msgid "Opens the launcher, displays shortcuts."
195msgstr "ማስነሻውን መክፈቻ እና አቋራጮች ማሳያ"
154msgstr "ማስነሻውን መክፈቻ እና አቋራጮች ማሳያ"
196
155
197−#: qml/Components/KeyboardShortcutsOverlay.qml:151
156+#: qml/Components/KeyboardShortcutsOverlay.qml:138
198msgid "Alt + F1"
157msgid "Alt + F1"
199msgstr "Alt + F1"
158msgstr "Alt + F1"
200
159
201−#: qml/Components/KeyboardShortcutsOverlay.qml:156
160+#: qml/Components/KeyboardShortcutsOverlay.qml:143
202msgid "Opens launcher keyboard navigation mode."
161msgid "Opens launcher keyboard navigation mode."
203msgstr "መክፈቻ በ ፊደል ገበታ መቃኛ ዘዴ ማስነሻ"
162msgstr "መክፈቻ በ ፊደል ገበታ መቃኛ ዘዴ ማስነሻ"
204
163
205−#: qml/Components/KeyboardShortcutsOverlay.qml:164
164+#: qml/Components/KeyboardShortcutsOverlay.qml:151
206msgid "Super + Tab"
165msgid "Super + Tab"
207msgstr "Super + Tab"
166msgstr "Super + Tab"
208
167
209−#: qml/Components/KeyboardShortcutsOverlay.qml:169
168+#: qml/Components/KeyboardShortcutsOverlay.qml:156
210msgid "Switches applications via the launcher."
169msgid "Switches applications via the launcher."
211msgstr "መተግበሪያዎችን በ ማስጀመሪያ መቀየሪያ"
170msgstr "መተግበሪያዎችን በ ማስጀመሪያ መቀየሪያ"
212
171
213−#: qml/Components/KeyboardShortcutsOverlay.qml:177
172+#: qml/Components/KeyboardShortcutsOverlay.qml:164
214−msgid "Super + 1 to 0"
173+msgid "Super + 0 to 9"
215msgstr "Super + 0 እስከ 9"
174msgstr "Super + 0 እስከ 9"
216
175
217−#: qml/Components/KeyboardShortcutsOverlay.qml:182
176+#: qml/Components/KeyboardShortcutsOverlay.qml:169
218msgid "Same as clicking on a launcher icon."
177msgid "Same as clicking on a launcher icon."
219msgstr "ተመሳሳይ በ ማስጀመሪያ ምልክት ላይ እንደ መጫን"
178msgstr "ተመሳሳይ በ ማስጀመሪያ ምልክት ላይ እንደ መጫን"
220
179
221−#: qml/Components/KeyboardShortcutsOverlay.qml:190
180+#: qml/Components/KeyboardShortcutsOverlay.qml:177
222msgid "Super + A"
181msgid "Super + A"
223−msgstr "Super + A"
182+msgstr ""
224
183
225−#: qml/Components/KeyboardShortcutsOverlay.qml:195
184+#: qml/Components/KeyboardShortcutsOverlay.qml:182
226msgid "Opens the Application Drawer."
185msgid "Opens the Application Drawer."
227−msgstr "የ መሳያ መተግበሪያ ማስጀመሪያ"
186+msgstr ""
187+
188+#: qml/Components/KeyboardShortcutsOverlay.qml:194
189+msgid "Scopes"
190+msgstr "ክልል"
191+
192+#: qml/Components/KeyboardShortcutsOverlay.qml:201
193+msgid "Super (Tap)"
194+msgstr "Super (Tap)"
195+
196+#: qml/Components/KeyboardShortcutsOverlay.qml:206
197+msgid "Opens the Scopes home."
198+msgstr "የ ክልል ቤት መክፈቻ"
228
199
229−#: qml/Components/KeyboardShortcutsOverlay.qml:235
200+#: qml/Components/KeyboardShortcutsOverlay.qml:222
230msgid "Switching"
201msgid "Switching"
231msgstr "በ መቀየር ላይ"
202msgstr "በ መቀየር ላይ"
232
203
233−#: qml/Components/KeyboardShortcutsOverlay.qml:242
204+#: qml/Components/KeyboardShortcutsOverlay.qml:229
234msgid "Alt + Tab"
205msgid "Alt + Tab"
235msgstr "Alt + Tab"
206msgstr "Alt + Tab"
236
207
237−#: qml/Components/KeyboardShortcutsOverlay.qml:247
208+#: qml/Components/KeyboardShortcutsOverlay.qml:234
238msgid "Switches between applications."
209msgid "Switches between applications."
239msgstr "በ መተግበሪያዎች መካከል መቀያየሪያ"
210msgstr "በ መተግበሪያዎች መካከል መቀያየሪያ"
240
211
241−#: qml/Components/KeyboardShortcutsOverlay.qml:255
212+#: qml/Components/KeyboardShortcutsOverlay.qml:242
242msgid "Super + W"
213msgid "Super + W"
243msgstr "Super + W"
214msgstr "Super + W"
244
215
245−#: qml/Components/KeyboardShortcutsOverlay.qml:260
216+#: qml/Components/KeyboardShortcutsOverlay.qml:247
246msgid "Opens the desktop spread."
217msgid "Opens the desktop spread."
247msgstr "የ ዴስክቶፕ ማስፊያ መክፈቻ"
218msgstr "የ ዴስክቶፕ ማስፊያ መክፈቻ"
248
219
249−#: qml/Components/KeyboardShortcutsOverlay.qml:268
220+#: qml/Components/KeyboardShortcutsOverlay.qml:255
250msgid "Cursor Left or Right"
221msgid "Cursor Left or Right"
251msgstr "መጠቆሚያ የ ግራ ወይንም የ ቀኝ"
222msgstr "መጠቆሚያ የ ግራ ወይንም የ ቀኝ"
252
223
253−#: qml/Components/KeyboardShortcutsOverlay.qml:273
224+#: qml/Components/KeyboardShortcutsOverlay.qml:260
254msgid "Moves the focus."
225msgid "Moves the focus."
255msgstr "ትኩረት ማንቀሳቀሻ"
226msgstr "ትኩረት ማንቀሳቀሻ"
256
227
257−#: qml/Components/KeyboardShortcutsOverlay.qml:285
228+#: qml/Components/KeyboardShortcutsOverlay.qml:272
258msgid "Windows"
229msgid "Windows"
259msgstr "መስኮቶች"
230msgstr "መስኮቶች"
260
231
261−#: qml/Components/KeyboardShortcutsOverlay.qml:292
232+#: qml/Components/KeyboardShortcutsOverlay.qml:279
262msgid "Ctrl + Super + D"
233msgid "Ctrl + Super + D"
263msgstr "Ctrl + Super + D"
234msgstr "Ctrl + Super + D"
264
235
265−#: qml/Components/KeyboardShortcutsOverlay.qml:297
236+#: qml/Components/KeyboardShortcutsOverlay.qml:284
266msgid "Minimizes all windows."
237msgid "Minimizes all windows."
267msgstr "ሁሉንም መስኮቶች ማሳነሻ"
238msgstr "ሁሉንም መስኮቶች ማሳነሻ"
268
239
269−#: qml/Components/KeyboardShortcutsOverlay.qml:305
240+#: qml/Components/KeyboardShortcutsOverlay.qml:292
270msgid "Ctrl + Super + Up"
241msgid "Ctrl + Super + Up"
271msgstr "Ctrl + Super + Up"
242msgstr "Ctrl + Super + Up"
272
243
273−#: qml/Components/KeyboardShortcutsOverlay.qml:310
244+#: qml/Components/KeyboardShortcutsOverlay.qml:297
274msgid "Maximizes the current window."
245msgid "Maximizes the current window."
275msgstr "የ አሁኑን መስኮት ማሳደጊያ"
246msgstr "የ አሁኑን መስኮት ማሳደጊያ"
276
247
277−#: qml/Components/KeyboardShortcutsOverlay.qml:318
248+#: qml/Components/KeyboardShortcutsOverlay.qml:305
278msgid "Ctrl + Super + Down"
249msgid "Ctrl + Super + Down"
279msgstr "Ctrl + Super + Down"
250msgstr "Ctrl + Super + Down"
280
251
281−#: qml/Components/KeyboardShortcutsOverlay.qml:323
252+#: qml/Components/KeyboardShortcutsOverlay.qml:310
282msgid "Minimizes or restores the current window."
253msgid "Minimizes or restores the current window."
283msgstr "የ አሁኑን መስኮትማሳነሻ ወይንም እንደ ነበር መመለሻ"
254msgstr "የ አሁኑን መስኮትማሳነሻ ወይንም እንደ ነበር መመለሻ"
284
255
285−#: qml/Components/KeyboardShortcutsOverlay.qml:331
256+#: qml/Components/KeyboardShortcutsOverlay.qml:318
286msgid "Ctrl + Super + Left or Right"
257msgid "Ctrl + Super + Left or Right"
287msgstr "Ctrl + Super + Left or Right"
258msgstr "Ctrl + Super + Left or Right"
288
259
289−#: qml/Components/KeyboardShortcutsOverlay.qml:336
260+#: qml/Components/KeyboardShortcutsOverlay.qml:323
290msgid "Semi-maximizes the current window."
261msgid "Semi-maximizes the current window."
291msgstr "የ አሁኑን መስኮት በ ንዑስ-ማሳደጊያ"
262msgstr "የ አሁኑን መስኮት በ ንዑስ-ማሳደጊያ"
292
263
293−#: qml/Components/KeyboardShortcutsOverlay.qml:344
264+#: qml/Components/KeyboardShortcutsOverlay.qml:331
294msgid "Alt + F4"
265msgid "Alt + F4"
295msgstr "Alt + F4"
266msgstr "Alt + F4"
296
267
297−#: qml/Components/KeyboardShortcutsOverlay.qml:349
268+#: qml/Components/KeyboardShortcutsOverlay.qml:336
298msgid "Closes the current window."
269msgid "Closes the current window."
299msgstr "የ አሁኑን መስኮት መዝጊያ"
270msgstr "የ አሁኑን መስኮት መዝጊያ"
300
271
301−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:235
272+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:252
302msgid "Return to Call"
273msgid "Return to Call"
303msgstr "ወደ ጥሪ መመለሻ"
274msgstr "ወደ ጥሪ መመለሻ"
304
275
@@ -306,7 +277,7 @@ msgstr "ወደ ጥሪ መመለሻ"
306msgid "Emergency Call"
277msgid "Emergency Call"
307msgstr "የ ድንገተኛ ጥሪ"
278msgstr "የ ድንገተኛ ጥሪ"
308
279
309−#: qml/Components/Lockscreen.qml:245
280+#: qml/Components/Lockscreen.qml:244
310msgid "OK"
281msgid "OK"
311msgstr "እሺ"
282msgstr "እሺ"
312
283
@@ -320,29 +291,29 @@ msgstr "%1:%2:%3"
320msgid "%1:%2"
291msgid "%1:%2"
321msgstr "%1:%2"
292msgstr "%1:%2"
322
293
323−#: qml/Components/ModeSwitchWarningDialog.qml:33
294+#: qml/Components/ModeSwitchWarningDialog.qml:32
324msgid "Apps may have unsaved data:"
295msgid "Apps may have unsaved data:"
325msgstr "መተግበሪያው ያልተቀመጠ ዳታ ይዟል:"
296msgstr "መተግበሪያው ያልተቀመጠ ዳታ ይዟል:"
326
297
327−#: qml/Components/ModeSwitchWarningDialog.qml:60
298+#: qml/Components/ModeSwitchWarningDialog.qml:57
328msgctxt ""
299msgctxt ""
329"Re-dock means connect the device again to an external screen/mouse/keyboard"
300"Re-dock means connect the device again to an external screen/mouse/keyboard"
330msgid "Re-dock, save your work and close these apps to continue."
301msgid "Re-dock, save your work and close these apps to continue."
331msgstr "እንደገና-ማሳረፊያ: ስራዎትን ያስቀምጡ እና ይዝጉ መተግበሪያው እንዲቀጥል"
302msgstr "እንደገና-ማሳረፊያ: ስራዎትን ያስቀምጡ እና ይዝጉ መተግበሪያው እንዲቀጥል"
332
303
333−#: qml/Components/ModeSwitchWarningDialog.qml:67
304+#: qml/Components/ModeSwitchWarningDialog.qml:63
334msgid "Or force close now (unsaved data will be lost)."
305msgid "Or force close now (unsaved data will be lost)."
335msgstr "ወይንም አሁን አስገድዶ ማጥፊያ (ያልተቀመጠ ዳታ ይጠፋል)"
306msgstr "ወይንም አሁን አስገድዶ ማጥፊያ (ያልተቀመጠ ዳታ ይጠፋል)"
336
307
337−#: qml/Components/ModeSwitchWarningDialog.qml:80
308+#: qml/Components/ModeSwitchWarningDialog.qml:75
338msgid "OK, I will reconnect"
309msgid "OK, I will reconnect"
339msgstr "እሺ: እኔ አሁን እንደገና እገናኛለሁ"
310msgstr "እሺ: እኔ አሁን እንደገና እገናኛለሁ"
340
311
341−#: qml/Components/ModeSwitchWarningDialog.qml:81
312+#: qml/Components/ModeSwitchWarningDialog.qml:76
342msgid "Reconnect now!"
313msgid "Reconnect now!"
343msgstr "አሁን እንደገና መገናኛ!"
314msgstr "አሁን እንደገና መገናኛ!"
344
315
345−#: qml/Components/ModeSwitchWarningDialog.qml:94
316+#: qml/Components/ModeSwitchWarningDialog.qml:88
346msgid "Close all"
317msgid "Close all"
347msgstr "ሁሉንም መዝጊያ"
318msgstr "ሁሉንም መዝጊያ"
348
319
@@ -358,19 +329,116 @@ msgstr "የ እርስዎ አካል አሁን ከ ውጪ ማሳያ ጋር ተገ
358
329
359#: qml/Components/VirtualTouchPad.qml:327
330#: qml/Components/VirtualTouchPad.qml:327
360msgid "Tap left button to click."
331msgid "Tap left button to click."
361−msgstr "የ ግራ ቁልፍ መታ ያድርጉ ለ መጫን"
332+msgstr ""
362
333
363#: qml/Components/VirtualTouchPad.qml:339
334#: qml/Components/VirtualTouchPad.qml:339
364msgid "Tap right button to right click."
335msgid "Tap right button to right click."
365−msgstr "የ ቀኝ ቁልፍ መታ ያድርጉ በ ቀኝ ለ መጫን"
336+msgstr ""
366
337
367#: qml/Components/VirtualTouchPad.qml:351
338#: qml/Components/VirtualTouchPad.qml:351
368msgid "Swipe with two fingers to scroll."
339msgid "Swipe with two fingers to scroll."
369−msgstr "ለ መሸብለል በ ሁለት ጣቶች ይጥረጉ"
340+msgstr ""
370
341
371#: qml/Components/VirtualTouchPad.qml:396
342#: qml/Components/VirtualTouchPad.qml:396
372msgid "Find more settings in the system settings."
343msgid "Find more settings in the system settings."
373−msgstr "ተጨማሪ ማሰናጃ በ ስርአት ማሰናጃ ውስጥ መፈለጊያ"
344+msgstr ""
345+
346+#: qml/Dash/DashPageHeader.qml:361
347+msgctxt "Button: Open the Ubuntu Store"
348+msgid "Store"
349+msgstr "ማስቀመጫ"
350+
351+#: qml/Dash/DashPageHeader.qml:368
352+msgctxt "Button: Start a search in the current dash scope"
353+msgid "Search"
354+msgstr "መፈለጊያ"
355+
356+#: qml/Dash/DashPageHeader.qml:378
357+msgctxt "Button: Show the current dash scope settings"
358+msgid "Settings"
359+msgstr "ማሰናጃዎች"
360+
361+#: qml/Dash/DashPageHeader.qml:385
362+msgid "Remove from Favorites"
363+msgstr "ከምወዳቸው ማስወገጃ"
364+
365+#: qml/Dash/DashPageHeader.qml:385
366+msgid "Add to Favorites"
367+msgstr "ወደምወዳቸው መጨመሪያ"
368+
369+#: qml/Dash/FiltersPopover.qml:61
370+msgid "Refine your results"
371+msgstr "የ እርስዎን ውጤቶች እንደገና ማጣሪያ"
372+
373+#: qml/Dash/FiltersPopover.qml:70
374+msgid "Reset"
375+msgstr "እንደ ነበረ መመለሻ"
376+
377+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
378+msgid "Show less"
379+msgstr "ትንሽ ማሳያ"
380+
381+#: qml/Dash/GenericScopeView.qml:547
382+msgid "Show all"
383+msgstr "ሁሉንም ማሳያ"
384+
385+#: qml/Dash/GenericScopeView.qml:578
386+msgctxt "Label: Hint for dash search line edit"
387+msgid "Search"
388+msgstr "መፈለጊያ"
389+
390+#: qml/Dash/PageHeaderExtraPanel.qml:67
391+msgid "Recent Searches"
392+msgstr "የ ቅርብ ጊዜ ፍለጋዎች"
393+
394+#: qml/Dash/PageHeaderExtraPanel.qml:78
395+msgid "Clear All"
396+msgstr "ሁሉንም ማጽጃ"
397+
398+#: qml/Dash/Previews/PreviewActionCombo.qml:36
399+msgid "More..."
400+msgstr "ተጨማሪ..."
401+
402+#: qml/Dash/Previews/PreviewActionCombo.qml:36
403+msgid "Less..."
404+msgstr "አነስተኛ..."
405+
406+#: qml/Dash/Previews/PreviewCommentInput.qml:83
407+#: qml/Dash/Previews/PreviewRatingInput.qml:202
408+msgid "Send"
409+msgstr "መላኪያ"
410+
411+#: qml/Dash/Previews/PreviewRatingInput.qml:109
412+msgid "Rate this"
413+msgstr "ለዚህ ደረጃ ይስጡ"
414+
415+#: qml/Dash/Previews/PreviewRatingInput.qml:184
416+msgid "Add a review"
417+msgstr "ግምገማ መጨመሪያ"
418+
419+#: qml/Dash/PullToRefreshScopeStyle.qml:56
420+msgid "Pull to refresh…"
421+msgstr "ይሳቡ ለማነቃቃት…"
422+
423+#: qml/Dash/PullToRefreshScopeStyle.qml:61
424+msgid "Release to refresh…"
425+msgstr "ይልቀቁ ለማነቃቃት…"
426+
427+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
428+msgid "Enable location data"
429+msgstr "የአካባቢ ዳታ ማስቻያ"
430+
431+#: qml/Dash/ScopesList.qml:146
432+msgid "Manage"
433+msgstr "አስተዳዳሪ"
434+
435+#: qml/Dash/ScopesList.qml:187
436+msgid "Home"
437+msgstr "ቤት"
438+
439+#: qml/Dash/ScopesList.qml:188
440+msgid "Also installed"
441+msgstr "እንዲሁም የተገጠሙ"
374
442
375#: qml/Greeter/CoverPage.qml:127
443#: qml/Greeter/CoverPage.qml:127
376msgid "Unlock"
444msgid "Unlock"
@@ -395,45 +463,46 @@ msgid_plural "Please wait %1 minutes and then try again…"
395msgstr[0] "እባክዎን ይቆዩ %1 ደቂቃ እና ከዛ እንደ ገና ይምክሩ…"
463msgstr[0] "እባክዎን ይቆዩ %1 ደቂቃ እና ከዛ እንደ ገና ይምክሩ…"
396msgstr[1] "እባክዎን ይቆዩ %1 ደቂቃዎች እና ከዛ እንደ ገና ይምክሩ…"
464msgstr[1] "እባክዎን ይቆዩ %1 ደቂቃዎች እና ከዛ እንደ ገና ይምክሩ…"
397
465
398−#: qml/Greeter/Greeter.qml:550
466+#: qml/Greeter/Greeter.qml:592
399msgid "Try again"
467msgid "Try again"
400msgstr "እንደገና ይሞክሩ"
468msgstr "እንደገና ይሞክሩ"
401
469
402−#: qml/Greeter/Greeter.qml:551
470+#: qml/Greeter/LoginList.qml:70
403−msgid "Enter passphrase to unlock"
404−msgstr "የ ማለፊያ ሀረግ ያስገቡ"
405−
406−#: qml/Greeter/Greeter.qml:552
407−msgid "Enter passcode to unlock"
408−msgstr "የ ማለፊያ ኮድ ያስገቡ ለ መክፈት"
409−
410−#: qml/Greeter/NarrowView.qml:235
411−msgid "Emergency"
412−msgstr "ድንገተኛ"
413−
414−#: qml/Greeter/PromptList.qml:126
415msgid "Passphrase"
471msgid "Passphrase"
416msgstr "የማለፊያ ሐረግ"
472msgstr "የማለፊያ ሐረግ"
417
473
418−#: qml/Greeter/PromptList.qml:126
474+#: qml/Greeter/LoginList.qml:71
419msgid "Passcode"
475msgid "Passcode"
420msgstr "ማለፊያ ኮድ"
476msgstr "ማለፊያ ኮድ"
421
477
478+#: qml/Greeter/LoginList.qml:98
479+msgid "Retry"
480+msgstr "እንደገና ይሞክሩ"
481+
482+#: qml/Greeter/LoginList.qml:99
483+msgid "Log In"
484+msgstr "መግቢያ"
485+
486+#: qml/Greeter/NarrowView.qml:252
487+msgid "Emergency"
488+msgstr "ድንገተኛ"
489+
422−#: qml/Greeter/SessionsList.qml:124
490+#: qml/Greeter/SessionsList.qml:122
423msgid "Select desktop environment"
491msgid "Select desktop environment"
424msgstr "የ ዴስክቶፕ አይነት ይምረጡ"
492msgstr "የ ዴስክቶፕ አይነት ይምረጡ"
425
493
426−#: qml/Launcher/Drawer.qml:250
494+#: qml/Launcher/Drawer.qml:80
427msgid "Search…"
495msgid "Search…"
428−msgstr "መፈለጊያ…"
496+msgstr ""
429
497
430−#: qml/Launcher/PullToRefreshScopeStyle.qml:56
498+#: qml/Launcher/Drawer.qml:101
499+msgctxt "Apps sorted alphabetically"
431−msgid "Pull to refresh…"
500+msgid "A-Z"
432−msgstr "ይሳቡ ለማነቃቃት…"
501+msgstr ""
433
502
434−#: qml/Launcher/PullToRefreshScopeStyle.qml:61
503+#: qml/Launcher/MoreAppsHeader.qml:32
435−msgid "Release to refresh…"
504+msgid "More apps in the store"
436−msgstr "ይልቀቁ ለማነቃቃት…"
505+msgstr ""
437
506
438#: qml/Notifications/NotificationMenuItemFactory.qml:124
507#: qml/Notifications/NotificationMenuItemFactory.qml:124
439msgid "Show password"
508msgid "Show password"
@@ -522,33 +591,23 @@ msgctxt "Button: Call back on phone"
522msgid "Call back"
591msgid "Call back"
523msgstr "መልሶ መደወያ"
592msgstr "መልሶ መደወያ"
524
593
525−#: qml/Panel/PanelMenuPage.qml:92
526−msgid "Back"
527−msgstr "ወደ ኋላ"
528−
529#: qml/Stage/SideStage.qml:76
594#: qml/Stage/SideStage.qml:76
530msgid "Drag using 3 fingers any application from one window to the other"
595msgid "Drag using 3 fingers any application from one window to the other"
531msgstr "መጎተቻ 3 ጣቶች በ መጠቀም ማንኛውንም መተግበሪያ ከ አንድ መስኮት ወደ ሌላ"
596msgstr "መጎተቻ 3 ጣቶች በ መጠቀም ማንኛውንም መተግበሪያ ከ አንድ መስኮት ወደ ሌላ"
532
597
533−#: qml/Stage/Stage.qml:671
534−msgid "No running apps"
535−msgstr ""
536−
537#: qml/Tutorial/TutorialLeftLong.qml:49
598#: qml/Tutorial/TutorialLeftLong.qml:49
538−#, fuzzy
539−#| msgid "Long swipe from the left edge to open the Today scope"
599+msgid "Long swipe from the left edge to open the Today scope"
540−msgid "Long swipe from the left edge to open the Application Drawer"
541msgstr "በ ረጅሙ ከ ግራ ጠርዝ በኩል ይጥረጉ የ ዛሬን ክልል ለ መክፈት"
600msgstr "በ ረጅሙ ከ ግራ ጠርዝ በኩል ይጥረጉ የ ዛሬን ክልል ለ መክፈት"
542
601
543#: qml/Tutorial/TutorialLeft.qml:47
602#: qml/Tutorial/TutorialLeft.qml:47
544msgid "Short swipe from the left edge to open the launcher"
603msgid "Short swipe from the left edge to open the launcher"
545msgstr "በ አጭሩ ይጥረጉ ከ ግራ ጠርዝ በኩል ማስጀመሪያውን ለ መክፈት"
604msgstr "በ አጭሩ ይጥረጉ ከ ግራ ጠርዝ በኩል ማስጀመሪያውን ለ መክፈት"
546
605
547−#: qml/Tutorial/TutorialRight.qml:54
606+#: qml/Tutorial/TutorialRight.qml:55
548msgid "Push your mouse against the right edge to view your open apps"
607msgid "Push your mouse against the right edge to view your open apps"
549msgstr "የ እርስዎን አይጥ መጠቆሚያ ወደ ቀኝ ጠርዝ በኩል ያስጠጉ የ ተከፈቱ መተግበሪያዎችን ለ መመልከት"
608msgstr "የ እርስዎን አይጥ መጠቆሚያ ወደ ቀኝ ጠርዝ በኩል ያስጠጉ የ ተከፈቱ መተግበሪያዎችን ለ መመልከት"
550
609
551−#: qml/Tutorial/TutorialRight.qml:55
610+#: qml/Tutorial/TutorialRight.qml:56
552msgid "Swipe from the right edge to view your open apps"
611msgid "Swipe from the right edge to view your open apps"
553msgstr "ከ ቀኝ በኩል ይጥረጉ የ ተከፈቱ መተግበሪያዎችን ለ መመልከት"
612msgstr "ከ ቀኝ በኩል ይጥረጉ የ ተከፈቱ መተግበሪያዎችን ለ መመልከት"
554
613
@@ -556,44 +615,28 @@ msgstr "ከ ቀኝ በኩል ይጥረጉ የ ተከፈቱ መተግበሪያዎ
556msgid "Swipe from the top edge to access notifications and quick settings"
615msgid "Swipe from the top edge to access notifications and quick settings"
557msgstr "ከ ላይ ጠረዝ በኩል ይጥረጉ ማስታወቂያዎች እና በፍጥነት ማሰናጃዎች ጋር ለ መድረስ"
616msgstr "ከ ላይ ጠረዝ በኩል ይጥረጉ ማስታወቂያዎች እና በፍጥነት ማሰናጃዎች ጋር ለ መድረስ"
558
617
559−#: qml/Wizard/Page.qml:59
618+#: qml/Wizard/Page.qml:54
560msgctxt "Button: Go back one page in the Wizard"
619msgctxt "Button: Go back one page in the Wizard"
561msgid "Back"
620msgid "Back"
562msgstr "ወደ ኋላ"
621msgstr "ወደ ኋላ"
563
622
564−#: qml/Wizard/Pages/10-welcome.qml:29
623+#: qml/Wizard/Pages/10-welcome.qml:28
565msgid "Language"
624msgid "Language"
566msgstr "ቋንቋ"
625msgstr "ቋንቋ"
567
626
568−#: qml/Wizard/Pages/10-welcome.qml:176
627+#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
569−#: qml/Wizard/Pages/10-welcome-update.qml:126
628+#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
570−#: qml/Wizard/Pages/11-changelog.qml:74 qml/Wizard/Pages/20-keyboard.qml:152
571−#: qml/Wizard/Pages/30-wifi.qml:214 qml/Wizard/Pages/50-timezone.qml:272
629+#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
572−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/70-passwd-type.qml:146
630+#: qml/Wizard/Pages/70-passwd-type.qml:145
631+#: qml/Wizard/Pages/75-report-check.qml:84
573−#: qml/Wizard/Pages/passcode-desktop.qml:154
632+#: qml/Wizard/Pages/passcode-desktop.qml:142
574−#: qml/Wizard/Pages/password-set.qml:153
633+#: qml/Wizard/Pages/password-set.qml:142
575msgid "Next"
634msgid "Next"
576msgstr "ይቀጥሉ"
635msgstr "ይቀጥሉ"
577
636
578−#: qml/Wizard/Pages/10-welcome-update.qml:91
579−msgid "Welcome to "
580−msgstr "እንኳን ደህና መጡ ወደ: "
581−
582−#: qml/Wizard/Pages/10-welcome-update.qml:106
583−msgid "We will make sure your device is ready to use "
584−msgstr "የ እርስዎ አካል ለ መጠቀም ዝግጁ ነው: "
585−
586−#: qml/Wizard/Pages/11-changelog.qml:28
587−msgid "What's new"
588−msgstr "ምን አዲስ ነገር አለ"
589−
590−#: qml/Wizard/Pages/11-changelog.qml:74
591−msgid "Loading..."
592−msgstr "በ መጫን ላይ..."
593−
594#: qml/Wizard/Pages/20-keyboard.qml:31
637#: qml/Wizard/Pages/20-keyboard.qml:31
595msgid "Select Keyboard"
638msgid "Select Keyboard"
596−msgstr "የ ፊደል ገበታ ይምረጡ"
639+msgstr "ቋንቋ ይምረጡ"
597
640
598#: qml/Wizard/Pages/20-keyboard.qml:71
641#: qml/Wizard/Pages/20-keyboard.qml:71
599msgid "Keyboard language"
642msgid "Keyboard language"
@@ -603,8 +646,8 @@ msgstr "የ ፊደል ገበታ ቋንቋ"
603msgid "Keyboard layout"
646msgid "Keyboard layout"
604msgstr "የ ፊደል ገበታ አቀራረብ"
647msgstr "የ ፊደል ገበታ አቀራረብ"
605
648
606−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
649+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
607−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
650+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
608#: qml/Wizard/Pages/sim.qml:101
651#: qml/Wizard/Pages/sim.qml:101
609msgid "Skip"
652msgid "Skip"
610msgstr "መዝለያ"
653msgstr "መዝለያ"
@@ -613,23 +656,55 @@ msgstr "መዝለያ"
613msgid "Connect to Wi‑Fi"
656msgid "Connect to Wi‑Fi"
614msgstr "ወደ ዋይ‑ፋይ መገናኛ"
657msgstr "ወደ ዋይ‑ፋይ መገናኛ"
615
658
616−#: qml/Wizard/Pages/30-wifi.qml:139
659+#: qml/Wizard/Pages/30-wifi.qml:132
617msgid "Connected"
660msgid "Connected"
618msgstr "ተገናኝቷል"
661msgstr "ተገናኝቷል"
619
662
620−#: qml/Wizard/Pages/30-wifi.qml:172
663+#: qml/Wizard/Pages/30-wifi.qml:165
621msgid "Available Wi-Fi networks"
664msgid "Available Wi-Fi networks"
622msgstr "ዝግጁ የ ዋይ-ፋይ ኔትዎርኮች"
665msgstr "ዝግጁ የ ዋይ-ፋይ ኔትዎርኮች"
623
666
624−#: qml/Wizard/Pages/30-wifi.qml:173
667+#: qml/Wizard/Pages/30-wifi.qml:166
625msgid "No available Wi-Fi networks"
668msgid "No available Wi-Fi networks"
626msgstr "ምንም ዝግጁ ዋይ-ፋይ ኔትዎርኮች አልተገኙም"
669msgstr "ምንም ዝግጁ ዋይ-ፋይ ኔትዎርኮች አልተገኙም"
627
670
671+#: qml/Wizard/Pages/40-location.qml:27
672+msgid "Location Services"
673+msgstr "የ አካባቢ ግልጋሎት"
674+
675+#: qml/Wizard/Pages/40-location.qml:83
676+msgid ""
677+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
678+"(recommended)"
679+msgstr "ይጠቀሙ ጂፒኤስ: ዋይ-ፋይ: hotspots እና ተንቀሳቃሽ ኔትዎርክ ሳይታወቁ አካባቢ ለማግኘት (ይመከራሉ)"
680+
681+#: qml/Wizard/Pages/40-location.qml:105
682+#, qt-format
683+msgid "By selecting this option you agree to the Nokia HERE %1."
684+msgstr "ይህን ምርጫ በ መምረጥ እርስዎ ተስማምተዋል ከ Nokia HERE %1."
685+
686+#: qml/Wizard/Pages/40-location.qml:106
687+msgctxt "part of: Nokia HERE terms and conditions"
688+msgid "terms and conditions"
689+msgstr "ስምምነት እና ሁኔታዎች"
690+
691+#: qml/Wizard/Pages/40-location.qml:160
692+msgid "GPS only"
693+msgstr "ጂፒኤስ ብቻ"
694+
695+#: qml/Wizard/Pages/40-location.qml:214
696+msgid "Don't use my location"
697+msgstr "የ እኔን አካባቢ አትጠቀም"
698+
699+#: qml/Wizard/Pages/40-location.qml:260
700+msgid "You can change it later in System Settings."
701+msgstr "እርስዎ በኋላ በ ስርአት ማሰናጃ ውስጥ መቀየር ይችላሉ"
702+
628#: qml/Wizard/Pages/50-timezone.qml:30
703#: qml/Wizard/Pages/50-timezone.qml:30
629msgid "Time Zone"
704msgid "Time Zone"
630msgstr "የ ሰአት ክልል"
705msgstr "የ ሰአት ክልል"
631
706
632−#: qml/Wizard/Pages/50-timezone.qml:183
707+#: qml/Wizard/Pages/50-timezone.qml:182
633msgid "Enter your city"
708msgid "Enter your city"
634msgstr "የ እርስዎን ከተማ ያስገቡ"
709msgstr "የ እርስዎን ከተማ ያስገቡ"
635
710
@@ -637,7 +712,7 @@ msgstr "የ እርስዎን ከተማ ያስገቡ"
637msgid "Personalize Your Device"
712msgid "Personalize Your Device"
638msgstr "የ እርስዎን አካል የ ግልዎ ያድርጉ"
713msgstr "የ እርስዎን አካል የ ግልዎ ያድርጉ"
639
714
640−#: qml/Wizard/Pages/60-account.qml:54
715+#: qml/Wizard/Pages/60-account.qml:48
641msgid "Preferred Name"
716msgid "Preferred Name"
642msgstr "የመረጡት ስም"
717msgstr "የመረጡት ስም"
643
718
@@ -645,75 +720,112 @@ msgstr "የመረጡት ስም"
645msgid "Lock Screen"
720msgid "Lock Screen"
646msgstr "መመልከቻውን መቆለፊያ"
721msgstr "መመልከቻውን መቆለፊያ"
647
722
648−#: qml/Wizard/Pages/70-passwd-type.qml:103
723+#: qml/Wizard/Pages/70-passwd-type.qml:102
649msgctxt "Label: Type of security method"
724msgctxt "Label: Type of security method"
650msgid "Create new password"
725msgid "Create new password"
651msgstr "አዲስ የ መግቢያ ቃል መፍጠሪያ"
726msgstr "አዲስ የ መግቢያ ቃል መፍጠሪያ"
652
727
653−#: qml/Wizard/Pages/70-passwd-type.qml:105
728+#: qml/Wizard/Pages/70-passwd-type.qml:104
654msgctxt "Label: Type of security method"
729msgctxt "Label: Type of security method"
655msgid "Create passcode (numbers only)"
730msgid "Create passcode (numbers only)"
656msgstr "አዲስ የ ማለፊያ ኮድ መፍጠሪያ (ቁጥር ብቻ)"
731msgstr "አዲስ የ ማለፊያ ኮድ መፍጠሪያ (ቁጥር ብቻ)"
657
732
658−#: qml/Wizard/Pages/70-passwd-type.qml:107
733+#: qml/Wizard/Pages/70-passwd-type.qml:106
659msgctxt "Label: Type of security method"
734msgctxt "Label: Type of security method"
660msgid "No lock code"
735msgid "No lock code"
661msgstr "ምንም መቆለፊያ ኮድ አልተገኘም"
736msgstr "ምንም መቆለፊያ ኮድ አልተገኘም"
662
737
738+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
739+msgid "Privacy Policy"
740+msgstr "የ ግላዊነት መመሪያ"
741+
742+#: qml/Wizard/Pages/75-report-check.qml:26
743+msgid "Help Us Improve"
744+msgstr "እንድንሻሻል ይርዱን"
745+
746+#: qml/Wizard/Pages/75-report-check.qml:59
747+msgid "Improve system performance by sending us crashes and error reports."
748+msgstr "የ ስርአቱን አፈጻጸም ለማሻሻል የ ግጭት እና የ ስህተት መልእክቶች ይላኩልን"
749+
750+#: qml/Wizard/Pages/75-report-check.qml:60
751+msgid "Privacy policy"
752+msgstr "የ ግላዊነት መመሪያ"
753+
663−#: qml/Wizard/Pages/79-system-update.qml:28
754+#: qml/Wizard/Pages/77-system-update.qml:28
664msgid "Update Device"
755msgid "Update Device"
665msgstr "አካሉን ማሻሻያ"
756msgstr "አካሉን ማሻሻያ"
666
757
667−#: qml/Wizard/Pages/79-system-update.qml:55
758+#: qml/Wizard/Pages/77-system-update.qml:55
668msgid ""
759msgid ""
669"There is a system update available and ready to install. Afterwards, the "
760"There is a system update available and ready to install. Afterwards, the "
670"device will automatically restart."
761"device will automatically restart."
671msgstr "የ ስርአት ማሻሻያ ዝግጁ ነው ለ መግጠም: ከዚያ በኋላ አካሉ ራሱ በራሱ እንደገና ይጀምራል"
762msgstr "የ ስርአት ማሻሻያ ዝግጁ ነው ለ መግጠም: ከዚያ በኋላ አካሉ ራሱ በራሱ እንደገና ይጀምራል"
672
763
673−#: qml/Wizard/Pages/79-system-update.qml:76
764+#: qml/Wizard/Pages/77-system-update.qml:76
674−#, fuzzy
675−#| msgctxt "string identifying name of the update"
676−#| msgid "Ubuntu system"
677msgctxt "string identifying name of the update"
765msgctxt "string identifying name of the update"
678−msgid "Ubuntu Touch system"
766+msgid "Ubuntu system"
679msgstr "የ ኡቡቱ ስርአት"
767msgstr "የ ኡቡቱ ስርአት"
680
768
681−#: qml/Wizard/Pages/79-system-update.qml:83
769+#: qml/Wizard/Pages/77-system-update.qml:83
682#, qt-format
770#, qt-format
683msgctxt "version of the system update"
771msgctxt "version of the system update"
684msgid "Version %1"
772msgid "Version %1"
685msgstr "እትም %1"
773msgstr "እትም %1"
686
774
687−#: qml/Wizard/Pages/79-system-update.qml:95
775+#: qml/Wizard/Pages/77-system-update.qml:102
688msgid "This could take a few minutes..."
776msgid "This could take a few minutes..."
689−msgstr "ይህ ትንሽ ደቂቃዎች ይወስዳል..."
777+msgstr "ይህ ትንሽ ደቂቆች ይወስዳል"
690
778
691−#: qml/Wizard/Pages/79-system-update.qml:109
779+#: qml/Wizard/Pages/77-system-update.qml:116
692msgid "Install and restart now"
780msgid "Install and restart now"
693msgstr "መግጠሚያ እና እንደገና ማስጀመሪያ"
781msgstr "መግጠሚያ እና እንደገና ማስጀመሪያ"
694
782
695−#: qml/Wizard/Pages/80-finished.qml:91
783+#: qml/Wizard/Pages/80-finished.qml:89
696−msgid "Welcome Back"
697−msgstr "እንኳን ደህና መጡ:"
698−
699−#: qml/Wizard/Pages/80-finished.qml:91
700msgid "Welcome to Ubuntu"
784msgid "Welcome to Ubuntu"
701msgstr "እንኳን ደህና መጡ ወደ ኡቡንቱ"
785msgstr "እንኳን ደህና መጡ ወደ ኡቡንቱ"
702
786
703−#: qml/Wizard/Pages/80-finished.qml:106
787+#: qml/Wizard/Pages/80-finished.qml:104
704msgid "You are ready to use your device now"
788msgid "You are ready to use your device now"
705msgstr "የ እርስዎን አካል ለ መጠቀም አሁን ዝግጁ ነው"
789msgstr "የ እርስዎን አካል ለ መጠቀም አሁን ዝግጁ ነው"
706
790
707−#: qml/Wizard/Pages/80-finished.qml:126
791+#: qml/Wizard/Pages/80-finished.qml:124
708−msgid "Continue"
709−msgstr "ይቀጥሉ"
710−
711−#: qml/Wizard/Pages/80-finished.qml:126
712msgid "Get Started"
792msgid "Get Started"
713msgstr "እንጀምር"
793msgstr "እንጀምር"
714
794
795+#: qml/Wizard/Pages/here-terms.qml:25
796+msgid "Terms & Conditions"
797+msgstr "ውሎች & ሁኔታዎች"
798+
799+#: qml/Wizard/Pages/here-terms.qml:69
800+msgid "Your device uses positioning technologies provided by HERE."
801+msgstr "የ እርስዎ አካል ይጠቀማል ያሉበትን አካባቢ ቴክኖሎጂ የቀረበውን በ HERE."
802+
803+#: qml/Wizard/Pages/here-terms.qml:81
804+msgid ""
805+"To provide you with positioning services and to improve their quality, HERE "
806+"collects information about nearby cell towers and Wi-Fi hotspots around your "
807+"current location whenever your position is being found."
808+msgstr ""
809+"እርስዎ ያሉበትን አካባቢ ግልጋሎት ለ መስጠት እና ለማሻሻል: HERE መረጃ ይሰበስባል በቅርብ ያሉ የ ሴል ምሶሶዎች እና "
810+"ዋይ-ፋይ hotspots እርስዎ አሁን ያሉበትን አካባቢ ሲታወቅ"
811+
812+#: qml/Wizard/Pages/here-terms.qml:93
813+msgid ""
814+"The information collected is used to analyze the service and to improve the "
815+"use of service, but not to identify you personally."
816+msgstr "የ ተሰበሰበው መረጃ የሚጠቅመው ግልጋሎት ለማሻሻል ነው: ነገር ግን እርስዎን በ ግል ለ መለየት አይደለም"
817+
818+#: qml/Wizard/Pages/here-terms.qml:106
819+#, qt-format
820+msgid "By continuing, you agree to the HERE platform %1 and %2."
821+msgstr "በ መቀጠል እርስዎ ተስማምተዋል ከ HERE platform %1 እና %2."
822+
823+#: qml/Wizard/Pages/here-terms.qml:107
824+msgid "Service Terms"
825+msgstr "የ ግልጋሎት ስምምነቶች"
826+
715#: qml/Wizard/Pages/passcode-confirm.qml:43
827#: qml/Wizard/Pages/passcode-confirm.qml:43
716−#: qml/Wizard/Pages/passcode-desktop.qml:104
828+#: qml/Wizard/Pages/passcode-desktop.qml:97
717msgid "Confirm passcode"
829msgid "Confirm passcode"
718msgstr "የማለፊያ ኮድ ማረጋገጫ"
830msgstr "የማለፊያ ኮድ ማረጋገጫ"
719
831
@@ -730,24 +842,24 @@ msgstr "እባክዎን እንደገና-ያስገቡ"
730msgid "Lock Screen Passcode"
842msgid "Lock Screen Passcode"
731msgstr "የ መመልከቻው መቆለፊያ የ ማለፊያ ኮድ"
843msgstr "የ መመልከቻው መቆለፊያ የ ማለፊያ ኮድ"
732
844
733−#: qml/Wizard/Pages/passcode-desktop.qml:68
845+#: qml/Wizard/Pages/passcode-desktop.qml:61
734msgid "Enter 4 numbers to setup your passcode"
846msgid "Enter 4 numbers to setup your passcode"
735msgstr "ያስገቡ 4 ቁጥሮች የ እርስዎን የ ማለፊያ ኮድ ለማሰናዳት"
847msgstr "ያስገቡ 4 ቁጥሮች የ እርስዎን የ ማለፊያ ኮድ ለማሰናዳት"
736
848
737−#: qml/Wizard/Pages/passcode-desktop.qml:84
849+#: qml/Wizard/Pages/passcode-desktop.qml:77
738#: qml/Wizard/Pages/passcode-set.qml:54
850#: qml/Wizard/Pages/passcode-set.qml:54
739msgid "Choose passcode"
851msgid "Choose passcode"
740msgstr "የ ማለፊያ ኮድ ይምረጡ"
852msgstr "የ ማለፊያ ኮድ ይምረጡ"
741
853
742−#: qml/Wizard/Pages/passcode-desktop.qml:139
854+#: qml/Wizard/Pages/passcode-desktop.qml:127
743msgid "Passcode too short"
855msgid "Passcode too short"
744msgstr "የ ማለፊያ ኮዱ በጣም አጭር ነው"
856msgstr "የ ማለፊያ ኮዱ በጣም አጭር ነው"
745
857
746−#: qml/Wizard/Pages/passcode-desktop.qml:141
858+#: qml/Wizard/Pages/passcode-desktop.qml:129
747msgid "Passcodes match"
859msgid "Passcodes match"
748msgstr "የ ማለፊያ ኮዶቹ ተመሳሳይ ናቸው"
860msgstr "የ ማለፊያ ኮዶቹ ተመሳሳይ ናቸው"
749
861
750−#: qml/Wizard/Pages/passcode-desktop.qml:143
862+#: qml/Wizard/Pages/passcode-desktop.qml:131
751msgid "Passcodes do not match"
863msgid "Passcodes do not match"
752msgstr "የ ማለፊያ ኮዶቹ አይመሳሰሉም"
864msgstr "የ ማለፊያ ኮዶቹ አይመሳሰሉም"
753
865
@@ -759,15 +871,15 @@ msgstr "የ ማለፊያ ኮድ 4 ባህሪዎች መሆን አለበት"
759msgid "Lock Screen Password"
871msgid "Lock Screen Password"
760msgstr "የ መመልከቻ መቆለፊያ የ መግቢያ ቃል"
872msgstr "የ መመልከቻ መቆለፊያ የ መግቢያ ቃል"
761
873
762−#: qml/Wizard/Pages/password-set.qml:68
874+#: qml/Wizard/Pages/password-set.qml:62
763msgid "Enter at least 8 characters"
875msgid "Enter at least 8 characters"
764msgstr "ያስገቡ ቢያንስ 8 ባህሪዎች"
876msgstr "ያስገቡ ቢያንስ 8 ባህሪዎች"
765
877
766−#: qml/Wizard/Pages/password-set.qml:80
878+#: qml/Wizard/Pages/password-set.qml:74
767msgid "Choose password"
879msgid "Choose password"
768msgstr "የ መግቢያ ቃል ይምረጡ"
880msgstr "የ መግቢያ ቃል ይምረጡ"
769
881
770−#: qml/Wizard/Pages/password-set.qml:110
882+#: qml/Wizard/Pages/password-set.qml:104
771msgid "Confirm password"
883msgid "Confirm password"
772msgstr "የ መግቢያ ቃሉን ያረጋግጡ"
884msgstr "የ መግቢያ ቃሉን ያረጋግጡ"
773
885
@@ -823,217 +935,6 @@ msgstr "ደካማ የ መግቢያ ቃል"
823msgid "Very weak password"
935msgid "Very weak password"
824msgstr "በጣም ደካማ የ መግቢያ ቃል"
936msgstr "በጣም ደካማ የ መግቢያ ቃል"
825
937
826−#~ msgid "Unity 8"
827−#~ msgstr "Unity 8"
828−
829−#~ msgid "Scopes"
830−#~ msgstr "ክልል"
831−
832−#~ msgid "Super (Tap)"
833−#~ msgstr "Super (Tap)"
834−
835−#~ msgid "Opens the Scopes home."
836−#~ msgstr "የ ክልል ቤት መክፈቻ"
837−
838−#~ msgctxt "Button: Open the Ubuntu Store"
839−#~ msgid "Store"
840−#~ msgstr "ማስቀመጫ"
841−
842−#~ msgctxt "Button: Start a search in the current dash scope"
843−#~ msgid "Search"
844−#~ msgstr "መፈለጊያ"
845−
846−#~ msgctxt "Button: Show the current dash scope settings"
847−#~ msgid "Settings"
848−#~ msgstr "ማሰናጃዎች"
849−
850−#~ msgid "Remove from Favorites"
851−#~ msgstr "ከምወዳቸው ማስወገጃ"
852−
853−#~ msgid "Add to Favorites"
854−#~ msgstr "ወደምወዳቸው መጨመሪያ"
855−
856−#~ msgid "Refine your results"
857−#~ msgstr "የ እርስዎን ውጤቶች እንደገና ማጣሪያ"
858−
859−#~ msgid "Reset"
860−#~ msgstr "እንደ ነበረ መመለሻ"
861−
862−#~ msgid "Show less"
863−#~ msgstr "ትንሽ ማሳያ"
864−
865−#~ msgid "Show all"
866−#~ msgstr "ሁሉንም ማሳያ"
867−
868−#~ msgctxt "Label: Hint for dash search line edit"
869−#~ msgid "Search"
870−#~ msgstr "መፈለጊያ"
871−
872−#~ msgid "Recent Searches"
873−#~ msgstr "የ ቅርብ ጊዜ ፍለጋዎች"
874−
875−#~ msgid "Clear All"
876−#~ msgstr "ሁሉንም ማጽጃ"
877−
878−#~ msgid "More..."
879−#~ msgstr "ተጨማሪ..."
880−
881−#~ msgid "Less..."
882−#~ msgstr "አነስተኛ..."
883−
884−#~ msgid "Send"
885−#~ msgstr "መላኪያ"
886−
887−#~ msgid "Rate this"
888−#~ msgstr "ለዚህ ደረጃ ይስጡ"
889−
890−#~ msgid "Add a review"
891−#~ msgstr "ግምገማ መጨመሪያ"
892−
893−#~ msgid "Enable location data"
894−#~ msgstr "የአካባቢ ዳታ ማስቻያ"
895−
896−#~ msgid "Manage"
897−#~ msgstr "አስተዳዳሪ"
898−
899−#~ msgid "Home"
900−#~ msgstr "ቤት"
901−
902−#~ msgid "Also installed"
903−#~ msgstr "እንዲሁም የተገጠሙ"
904−
905−#~ msgid "Privacy Policy"
906−#~ msgstr "የ ግላዊነት መመሪያ"
907−
908−#~ msgid "Help Us Improve"
909−#~ msgstr "እንድንሻሻል ይርዱን"
910−
911−#~ msgid "Improve system performance by sending us crashes and error reports."
912−#~ msgstr "የ ስርአቱን አፈጻጸም ለማሻሻል የ ግጭት እና የ ስህተት መልእክቶች ይላኩልን"
913−
914−#~ msgid "Privacy policy"
915−#~ msgstr "የ ግላዊነት መመሪያ"
916−
917−#~ msgid "Update Apps"
918−#~ msgstr "መተግበሪያ ማሻሻያ"
919−
920−#~ msgid "This device is not connected to the internet."
921−#~ msgstr "ይህ አካል ከ ኢንተርኔት ጋር አልተገናኘም:"
922−
923−#~ msgid "Software is up to date"
924−#~ msgstr "ሶፍትዌሩ ዘመናዊ ነው:"
925−
926−#~ msgid "The update server is not responding."
927−#~ msgstr "የ ማሻሻያ ሰርቨር አይመልስም:"
928−
929−#~ msgid "Please wait..."
930−#~ msgstr "እባክዎን ይቆዩ..."
931−
932−#~ msgid "Installation failed"
933−#~ msgstr "መግጠሙ አልተሳካም:"
934−
935−#~ msgid "Checking for updates…"
936−#~ msgstr "ማሻሻያ በ መፈለግ ላይ…"
937−
938−#~ msgid "%1 update available"
939−#~ msgid_plural "%1 updates available"
940−#~ msgstr[0] "%1 ማሻሻያ ዝግጁ ነው:"
941−#~ msgstr[1] "%1 ማሻሻያዎች ዝግጁ ናቸው:"
942−
943−#~ msgid "Update all…"
944−#~ msgstr "ሁሉንም ማሻሻያ…"
945−
946−#~ msgid "Update all"
947−#~ msgstr "ሁሉንም ማሻሻያ"
948−
949−#~ msgid "Update"
950−#~ msgstr "ማሻሻያ"
951−
952−#~ msgid "Download"
953−#~ msgstr "የ ወረደ"
954−
955−#~ msgid "Resume"
956−#~ msgstr "ይቀጥሉ"
957−
958−#~ msgid "Install…"
959−#~ msgstr "መግጠሚያ…"
960−
961−#~ msgid "Install"
962−#~ msgstr "መግጠሚያ"
963−
964−#~ msgid "Open"
965−#~ msgstr "መክፈቻ"
966−
967−#~ msgid "Installing"
968−#~ msgstr "በ መግጠም ላይ"
969−
970−#~ msgid "Waiting to download"
971−#~ msgstr "ለ ማውረድ በ መጠበቅ ላይ"
972−
973−#~ msgid "%1 of %2"
974−#~ msgstr "%1 ከ %2"
975−
976−#~ msgid "Downloaded"
977−#~ msgstr "የ ወረደ"
978−
979−#~ msgid "Installed"
980−#~ msgstr "ተገጥሟል:"
981−
982−#~ msgid "Updated %1"
983−#~ msgstr "ተሻሽሏል %1"
984−
985−#~ msgid "Update failed"
986−#~ msgstr "ማሻሻል አልተቻለም:"
987−
988−#~ msgid "Location Services"
989−#~ msgstr "የ አካባቢ ግልጋሎት"
990−
991−#~ msgid ""
992−#~ "Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
993−#~ "(recommended)"
994−#~ msgstr "ይጠቀሙ ጂፒኤስ: ዋይ-ፋይ: hotspots እና ተንቀሳቃሽ ኔትዎርክ ሳይታወቁ አካባቢ ለማግኘት (ይመከራሉ)"
995−
996−#~ msgid "By selecting this option you agree to the Nokia HERE %1."
997−#~ msgstr "ይህን ምርጫ በ መምረጥ እርስዎ ተስማምተዋል ከ Nokia HERE %1."
998−
999−#~ msgctxt "part of: Nokia HERE terms and conditions"
1000−#~ msgid "terms and conditions"
1001−#~ msgstr "ስምምነት እና ሁኔታዎች"
1002−
1003−#~ msgid "GPS only"
1004−#~ msgstr "ጂፒኤስ ብቻ"
1005−
1006−#~ msgid "Don't use my location"
1007−#~ msgstr "የ እኔን አካባቢ አትጠቀም"
1008−
1009−#~ msgid "You can change it later in System Settings."
1010−#~ msgstr "እርስዎ በኋላ በ ስርአት ማሰናጃ ውስጥ መቀየር ይችላሉ"
1011−
1012−#~ msgid "Terms & Conditions"
1013−#~ msgstr "ውሎች & ሁኔታዎች"
1014−
1015−#~ msgid "Your device uses positioning technologies provided by HERE."
1016−#~ msgstr "የ እርስዎ አካል ይጠቀማል ያሉበትን አካባቢ ቴክኖሎጂ የቀረበውን በ HERE."
1017−
1018−#~ msgid ""
1019−#~ "To provide you with positioning services and to improve their quality, "
1020−#~ "HERE collects information about nearby cell towers and Wi-Fi hotspots "
1021−#~ "around your current location whenever your position is being found."
1022−#~ msgstr ""
1023−#~ "እርስዎ ያሉበትን አካባቢ ግልጋሎት ለ መስጠት እና ለማሻሻል: HERE መረጃ ይሰበስባል በቅርብ ያሉ የ ሴል ምሶሶዎች "
1024−#~ "እና ዋይ-ፋይ hotspots እርስዎ አሁን ያሉበትን አካባቢ ሲታወቅ"
1025−
1026−#~ msgid ""
1027−#~ "The information collected is used to analyze the service and to improve "
1028−#~ "the use of service, but not to identify you personally."
1029−#~ msgstr "የ ተሰበሰበው መረጃ የሚጠቅመው ግልጋሎት ለማሻሻል ነው: ነገር ግን እርስዎን በ ግል ለ መለየት አይደለም"
1030−
1031−#~ msgid "By continuing, you agree to the HERE platform %1 and %2."
1032−#~ msgstr "በ መቀጠል እርስዎ ተስማምተዋል ከ HERE platform %1 እና %2."
1033−
1034−#~ msgid "Service Terms"
1035−#~ msgstr "የ ግልጋሎት ስምምነቶች"
1036−
1037#~ msgid "Top edge"
938#~ msgid "Top edge"
1038#~ msgstr "የላይ ጠርዝ"
939#~ msgstr "የላይ ጠርዝ"
1039
940
@@ -1049,12 +950,21 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1049#~ msgid "Type or say a command"
950#~ msgid "Type or say a command"
1050#~ msgstr "ትእዛዝ ይናገሩ ወይንም ይጻፉ"
951#~ msgstr "ትእዛዝ ይናገሩ ወይንም ይጻፉ"
1051
952
953+#~ msgid "Loading. Please Wait..."
954+#~ msgstr "እባክዎን ይቆዩ በመጫን ላይ..."
955+
956+#~ msgid "Speaking..."
957+#~ msgstr "በመናገር ላይ..."
958+
1052#~ msgid "Speak Now..."
959#~ msgid "Speak Now..."
1053#~ msgstr "አሁን ይናገሩ..."
960#~ msgstr "አሁን ይናገሩ..."
1054
961
1055#~ msgid "Confirm"
962#~ msgid "Confirm"
1056#~ msgstr "ማረጋገጫ"
963#~ msgstr "ማረጋገጫ"
1057
964
965+#~ msgid "Search"
966+#~ msgstr "መፈለጊያ"
967+
1058#~ msgid "See less"
968#~ msgid "See less"
1059#~ msgstr "አነስተኛ መመልከቻ"
969#~ msgstr "አነስተኛ መመልከቻ"
1060
970
@@ -1097,6 +1007,7 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1097#~ msgid "This will be your last attempt."
1007#~ msgid "This will be your last attempt."
1098#~ msgstr "ይህ የመጨረሻ ሙከራዎ ነው"
1008#~ msgstr "ይህ የመጨረሻ ሙከራዎ ነው"
1099
1009
1010+#, qt-format
1100#~ msgid "Sorry, incorrect %1"
1011#~ msgid "Sorry, incorrect %1"
1101#~ msgstr "አዝናለሁ: የተሳሳተ%1"
1012#~ msgstr "አዝናለሁ: የተሳሳተ%1"
1102
1013
@@ -1137,12 +1048,11 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1137#~ "You have now mastered the edge gestures and can start using the "
1048#~ "You have now mastered the edge gestures and can start using the "
1138#~ "phone<br><br>Tap on the screen to start"
1049#~ "phone<br><br>Tap on the screen to start"
1139#~ msgstr ""
1050#~ msgstr ""
1140−#~ "አሁን የ ጠርዝ እንቅስቃሴን አውቀዋል እና መጀመር ይችላሉ ስልኩን መጠቀም <br><br>መመልከቻውን መታ ያድርጉ "
1051+#~ "አሁን የ ጠርዝ እንቅስቃሴን አውቀዋል እና መጀመር ይችላሉ ስልኩን መጠቀም <br><br>መመልከቻውን መታ ያድርጉ ለመጀመር"
1141−#~ "ለመጀመር"
1142
1052
1143#~ msgid ""
1053#~ msgid ""
1144−#~ "If passcode is entered incorrectly, your phone will conduct a factory "
1054+#~ "If passcode is entered incorrectly, your phone will conduct a factory reset "
1145−#~ "reset and all personal data will be deleted."
1055+#~ "and all personal data will be deleted."
1146#~ msgstr ""
1056#~ msgstr ""
1147#~ "የተሳሳተ የማለፊያ ኮድ ካስገቡ የ እርስዎ ስልክ ወደ ነበረበት ወደ ፋክቶሪው ዘዴ ይመለሳል: እና የ ግል ዳታ በሙሉ "
1057#~ "የተሳሳተ የማለፊያ ኮድ ካስገቡ የ እርስዎ ስልክ ወደ ነበረበት ወደ ፋክቶሪው ዘዴ ይመለሳል: እና የ ግል ዳታ በሙሉ "
1148#~ "ይጠፋል"
1058#~ "ይጠፋል"
@@ -1151,8 +1061,8 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1151#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
1061#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
1152#~ "reset and all personal data will be deleted."
1062#~ "reset and all personal data will be deleted."
1153#~ msgstr ""
1063#~ msgstr ""
1154−#~ "የተሳሳተ የማለፊያ ሐረግ ካስገቡ የ እርስዎ ስልክ ወደ ነበረበት ወደ ፋክቶሪው ዘዴ ይመለሳል: እና የ ግል ዳታ "
1064+#~ "የተሳሳተ የማለፊያ ሐረግ ካስገቡ የ እርስዎ ስልክ ወደ ነበረበት ወደ ፋክቶሪው ዘዴ ይመለሳል: እና የ ግል ዳታ በሙሉ "
1155−#~ "በሙሉ ይጠፋል"
1065+#~ "ይጠፋል"
1156
1066
1157#~ msgid "Roaming"
1067#~ msgid "Roaming"
1158#~ msgstr "ማዘዋወሪያ"
1068#~ msgstr "ማዘዋወሪያ"
@@ -1160,12 +1070,19 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1160#~ msgid "Manage Scopes"
1070#~ msgid "Manage Scopes"
1161#~ msgstr "የ ክልል አስተዳዳሪ"
1071#~ msgstr "የ ክልል አስተዳዳሪ"
1162
1072
1073+#, qt-format
1163#~ msgid "Enter %1"
1074#~ msgid "Enter %1"
1164#~ msgstr "ማስገቢያ %1"
1075#~ msgstr "ማስገቢያ %1"
1165
1076
1166#~ msgid "Please re-enter"
1077#~ msgid "Please re-enter"
1167#~ msgstr "እባክዎን እንደገና-ያስገቡ"
1078#~ msgstr "እባክዎን እንደገና-ያስገቡ"
1168
1079
1080+#~ msgid "Enter passphrase"
1081+#~ msgstr "የ ማለፊያ ሀረግ ያስገቡ"
1082+
1083+#~ msgid "Enter passcode"
1084+#~ msgstr "የ ማለፊያ ኮድ ያስገቡ"
1085+
1169#~ msgid "Lock security"
1086#~ msgid "Lock security"
1170#~ msgstr "ደህንነት መቆለፊያ"
1087#~ msgstr "ደህንነት መቆለፊያ"
1171
1088
@@ -1188,8 +1105,7 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1188#~ "This can be disabled in <b>System Settings</b> under <b>Security &amp; "
1105#~ "This can be disabled in <b>System Settings</b> under <b>Security &amp; "
1189#~ "Privacy</b>"
1106#~ "Privacy</b>"
1190#~ msgstr ""
1107#~ msgstr ""
1191−#~ "ይህን ግልጋሎት ማሰናከል ይችላሉ ከ <b>ስርአት ማሰናጃዎች</b> under <b>Security &amp; "
1108+#~ "ይህን ግልጋሎት ማሰናከል ይችላሉ ከ <b>ስርአት ማሰናጃዎች</b> under <b>Security &amp; Privacy</b>"
1192−#~ "Privacy</b>"
1193
1109
1194#~ msgid "Nice work!"
1110#~ msgid "Nice work!"
1195#~ msgstr "ጥሩ ሰርተዋል!"
1111#~ msgstr "ጥሩ ሰርተዋል!"
@@ -1224,6 +1140,9 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1224#~ msgid "Let’s get started."
1140#~ msgid "Let’s get started."
1225#~ msgstr "ስራ እንጀምር"
1141#~ msgstr "ስራ እንጀምር"
1226
1142
1143+#~ msgid "Continue"
1144+#~ msgstr "ይቀጥሉ"
1145+
1227#~ msgid "Passphrase must be 4 characters long"
1146#~ msgid "Passphrase must be 4 characters long"
1228#~ msgstr "የ ማለፊያ ሀረግ ቢያንስ 4 ባህሪዎች መሆን አለበት"
1147#~ msgstr "የ ማለፊያ ሀረግ ቢያንስ 4 ባህሪዎች መሆን አለበት"
1229
1148
@@ -1233,9 +1152,11 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1233#~ msgid "Let the phone detect your location:"
1152#~ msgid "Let the phone detect your location:"
1234#~ msgstr "እባክዎን እርስዎ ያሉበትን አካባቢ ስልኩ እራሱ ይፈልግ:"
1153#~ msgstr "እባክዎን እርስዎ ያሉበትን አካባቢ ስልኩ እራሱ ይፈልግ:"
1235
1154
1155+#, qt-format
1236#~ msgid "〈 %1"
1156#~ msgid "〈 %1"
1237#~ msgstr "〈 %1"
1157#~ msgstr "〈 %1"
1238
1158
1159+#, qt-format
1239#~ msgid "%1 〉"
1160#~ msgid "%1 〉"
1240#~ msgstr "%1 〉"
1161#~ msgstr "%1 〉"
1241
1162
@@ -1252,12 +1173,12 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1252#~ "Your phone is set up to automatically report errors to Canonical and its "
1173#~ "Your phone is set up to automatically report errors to Canonical and its "
1253#~ "partners, the makers of the operating system."
1174#~ "partners, the makers of the operating system."
1254#~ msgstr ""
1175#~ msgstr ""
1255−#~ "የ እርስዎ ስልክ ራሱ በራሱ የ ስህተት መግለጫዎች ወደ Canonical and its partners, የ መስሪያ "
1176+#~ "የ እርስዎ ስልክ ራሱ በራሱ የ ስህተት መግለጫዎች ወደ Canonical and its partners, የ መስሪያ ስርአት "
1256−#~ "ስርአት አምራቾች"
1177+#~ "አምራቾች"
1257
1178
1258#~ msgid ""
1179#~ msgid ""
1259−#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms "
1180+#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
1260−#~ "and conditions</a>."
1181+#~ "conditions</a>."
1261#~ msgstr "ይህን ምርጫ በመምረጥ ተስማምቻለሁ ከ Nokia HERE <a href='#'>ውሎች እና ሁኔታዎች ጋር</a>."
1182#~ msgstr "ይህን ምርጫ በመምረጥ ተስማምቻለሁ ከ Nokia HERE <a href='#'>ውሎች እና ሁኔታዎች ጋር</a>."
1262
1183
1263#~ msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
1184#~ msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
@@ -1272,6 +1193,9 @@ msgstr "በጣም ደካማ የ መግቢያ ቃል"
1272#~ msgid "Short swipe from the left edge."
1193#~ msgid "Short swipe from the left edge."
1273#~ msgstr "ከ ግራ ጠርዝ በኩል በትንሹ ይጥረጉ"
1194#~ msgstr "ከ ግራ ጠርዝ በኩል በትንሹ ይጥረጉ"
1274
1195
1196+#~ msgid "Open the launcher"
1197+#~ msgstr "ማስጀመሪያውን መክፈቻ"
1198+
1275#~ msgid "Tap here to continue."
1199#~ msgid "Tap here to continue."
1276#~ msgstr "እዚህ መታ ይድርጉ ለመቀጠል"
1200#~ msgstr "እዚህ መታ ይድርጉ ለመቀጠል"
1277
1201
po/ar.po+484−474
@@ -6,114 +6,85 @@
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9−"Report-Msgid-Bugs-To: \n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2021-01-29 11:42-0600\n"
10+"POT-Creation-Date: 2017-01-10 14:48+0000\n"
11−"PO-Revision-Date: 2021-10-12 07:49+0000\n"
11+"PO-Revision-Date: 2017-01-14 05:20+0000\n"
12−"Last-Translator: HEROBRINE7GAMER <tapermeerkat77@gmail.com>\n"
12+"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
13−"Language-Team: Arabic <https://translate.ubports.com/projects/ubports/lomiri/"
13+"Language-Team: Arabic <ar@li.org>\n"
14−"ar/>\n"
15−"Language: ar\n"
16"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
19−"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
17+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
20−"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
18+"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
21−"X-Generator: Weblate 3.11.3\n"
22−"X-Launchpad-Export-Date: 2016-11-23 06:34+0000\n"
19+"X-Launchpad-Export-Date: 2017-01-16 05:47+0000\n"
20+"X-Generator: Launchpad (build 18302)\n"
23
21
24−#: plugins/LightDM/Greeter.cpp:199
22+#: plugins/LightDM/Greeter.cpp:123
25msgid "Password: "
23msgid "Password: "
26msgstr "كلمة السر: "
24msgstr "كلمة السر: "
27
25
28−#: plugins/LightDM/Greeter.cpp:214
29−msgid "Username"
30−msgstr "اسم المستخدم"
31−
32−#: plugins/LightDM/Greeter.cpp:258
33−msgid "Failed to authenticate"
34−msgstr "فشل التحقق"
35−
36−#: plugins/LightDM/Greeter.cpp:260
37−msgid "Invalid password, please try again"
38−msgstr "كلمة المرور غير صحيحة، الرجاء المحاولة مرة أخرى"
39−
40−#: plugins/LightDM/Greeter.cpp:270
41−msgid "Log In"
42−msgstr "سجل الدخول"
43−
44−#: plugins/LightDM/Greeter.cpp:270
45−msgid "Retry"
46−msgstr "حاول مجدداً"
47−
48−#: plugins/LightDM/UsersModel.cpp:157
49−msgid "Login"
50−msgstr "سجل الدخول"
51−
52−#: plugins/LightDM/UsersModel.cpp:165
53−msgid "Guest Session"
54−msgstr "جلسة ضيف"
55−
56−#: plugins/Unity/Launcher/launcheritem.cpp:48
26+#: plugins/Unity/Launcher/launcheritem.cpp:50
57#: plugins/Unity/Launcher/launcheritem.cpp:122
27#: plugins/Unity/Launcher/launcheritem.cpp:122
58msgid "Pin shortcut"
28msgid "Pin shortcut"
59−msgstr "ثبت اختصارًا"
29+msgstr "تثبيت الاختصار"
60
30
61−#: plugins/Unity/Launcher/launcheritem.cpp:54
31+#: plugins/Unity/Launcher/launcheritem.cpp:55
62msgid "Quit"
32msgid "Quit"
63msgstr "خروج"
33msgstr "خروج"
64
34
65#: plugins/Unity/Launcher/launcheritem.cpp:122
35#: plugins/Unity/Launcher/launcheritem.cpp:122
66msgid "Unpin shortcut"
36msgid "Unpin shortcut"
67−msgstr "ألغ تثبيت الاختصار"
37+msgstr "إزالة تثبيت الاختصار"
68
38
69−#: qml/Components/Dialogs.qml:176
39+#: qml/Components/Dialogs.qml:149
70msgctxt "Title: Lock/Log out dialog"
40msgctxt "Title: Lock/Log out dialog"
71msgid "Log out"
41msgid "Log out"
72−msgstr "اخرج"
42+msgstr "خروج"
73
43
74−#: qml/Components/Dialogs.qml:177
44+#: qml/Components/Dialogs.qml:150
75msgid "Are you sure you want to log out?"
45msgid "Are you sure you want to log out?"
76−msgstr "أمتأكد أنك تريد تسجيل الخروج ؟"
46+msgstr "هل أنت متأكد من رغبتك في تسجيل الخروج؟"
77
47
78−#: qml/Components/Dialogs.qml:180
48+#: qml/Components/Dialogs.qml:152
79msgctxt "Button: Lock the system"
49msgctxt "Button: Lock the system"
80msgid "Lock"
50msgid "Lock"
81msgstr "أوصِد"
51msgstr "أوصِد"
82
52
83−#: qml/Components/Dialogs.qml:191
53+#: qml/Components/Dialogs.qml:160
84msgctxt "Button: Log out from the system"
54msgctxt "Button: Log out from the system"
85msgid "Log Out"
55msgid "Log Out"
86−msgstr "اخرج"
56+msgstr "خروج"
87
57
88−#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
58+#: qml/Components/Dialogs.qml:167 qml/Components/Dialogs.qml:225
59+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:232
89−#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
60+#: qml/Wizard/Pages/passcode-confirm.qml:32
90#: qml/Wizard/Pages/passcode-set.qml:32
61#: qml/Wizard/Pages/passcode-set.qml:32
91msgid "Cancel"
62msgid "Cancel"
92−msgstr "ألغ"
63+msgstr "إلغاء"
93
64
94−#: qml/Components/Dialogs.qml:211
65+#: qml/Components/Dialogs.qml:179
95msgctxt "Title: Reboot dialog"
66msgctxt "Title: Reboot dialog"
96msgid "Reboot"
67msgid "Reboot"
97−msgstr "أعد التشغيل"
68+msgstr "إعادة التشغيل"
98
69
99−#: qml/Components/Dialogs.qml:212
70+#: qml/Components/Dialogs.qml:180
100msgid "Are you sure you want to reboot?"
71msgid "Are you sure you want to reboot?"
101−msgstr "أمتأكد أنك تريد إعادة التشغيل؟"
72+msgstr "هل أنت متأكد من رغبتك في إعادة تشغيل الجهاز؟"
102
73
103−#: qml/Components/Dialogs.qml:215
74+#: qml/Components/Dialogs.qml:182
104msgid "No"
75msgid "No"
105msgstr "لا"
76msgstr "لا"
106
77
107−#: qml/Components/Dialogs.qml:223
78+#: qml/Components/Dialogs.qml:189
108msgid "Yes"
79msgid "Yes"
109msgstr "نعم"
80msgstr "نعم"
110
81
111−#: qml/Components/Dialogs.qml:243
82+#: qml/Components/Dialogs.qml:204
112msgctxt "Title: Power off/Restart dialog"
83msgctxt "Title: Power off/Restart dialog"
113msgid "Power"
84msgid "Power"
114msgstr "الطاقة"
85msgstr "الطاقة"
115
86
116−#: qml/Components/Dialogs.qml:244
87+#: qml/Components/Dialogs.qml:205
117msgid ""
88msgid ""
118"Are you sure you would like\n"
89"Are you sure you would like\n"
119"to power off?"
90"to power off?"
@@ -121,27 +92,23 @@ msgstr ""
121"هل أنت متأكد من رغبتك\n"
92"هل أنت متأكد من رغبتك\n"
122"في إيقاف التشغيل؟"
93"في إيقاف التشغيل؟"
123
94
124−#: qml/Components/Dialogs.qml:248
95+#: qml/Components/Dialogs.qml:208
125msgctxt "Button: Power off the system"
96msgctxt "Button: Power off the system"
126msgid "Power off"
97msgid "Power off"
127−msgstr "أوقف التشغيل"
98+msgstr "إيقاف التشغيل"
128
99
129−#: qml/Components/Dialogs.qml:263
100+#: qml/Components/Dialogs.qml:217
130msgctxt "Button: Restart the system"
101msgctxt "Button: Restart the system"
131msgid "Restart"
102msgid "Restart"
132−msgstr "أعد التشغيل"
103+msgstr "إعادة التشغيل"
133−
134−#: qml/Components/Dialogs.qml:276
135−msgid "Screenshot"
136−msgstr "لقطة شاشة"
137
104
138#: qml/Components/KeyboardShortcutsOverlay.qml:41
105#: qml/Components/KeyboardShortcutsOverlay.qml:41
139msgid "Keyboard Shortcuts"
106msgid "Keyboard Shortcuts"
140msgstr "اختصارات لوحة المفاتيح"
107msgstr "اختصارات لوحة المفاتيح"
141
108
142#: qml/Components/KeyboardShortcutsOverlay.qml:55
109#: qml/Components/KeyboardShortcutsOverlay.qml:55
143−msgid "Lomiri"
110+msgid "Unity 8"
144−msgstr "لوميري"
111+msgstr "يونتي 8"
145
112
146#: qml/Components/KeyboardShortcutsOverlay.qml:62
113#: qml/Components/KeyboardShortcutsOverlay.qml:62
147msgid "PrtScr"
114msgid "PrtScr"
@@ -149,15 +116,15 @@ msgstr "PrtScr"
149
116
150#: qml/Components/KeyboardShortcutsOverlay.qml:67
117#: qml/Components/KeyboardShortcutsOverlay.qml:67
151msgid "Takes a screenshot."
118msgid "Takes a screenshot."
152−msgstr "خُذ لقطة للشاشة."
119+msgstr "أخذ لقطة للشاشة"
153
120
154#: qml/Components/KeyboardShortcutsOverlay.qml:75
121#: qml/Components/KeyboardShortcutsOverlay.qml:75
155msgid "Alt + PrtScr"
122msgid "Alt + PrtScr"
156msgstr "Alt + PrtScr"
123msgstr "Alt + PrtScr"
157
124
158#: qml/Components/KeyboardShortcutsOverlay.qml:80
125#: qml/Components/KeyboardShortcutsOverlay.qml:80
159−msgid "Takes a screenshot of the current window."
126+msgid "Takes a screenshot of a window."
160−msgstr "خُذ لقطة شاشة للنافذة الحالية."
127+msgstr "أخذ لقطة شاشة للنافذة"
161
128
162#: qml/Components/KeyboardShortcutsOverlay.qml:88
129#: qml/Components/KeyboardShortcutsOverlay.qml:88
163msgid "Super + Space"
130msgid "Super + Space"
@@ -165,7 +132,7 @@ msgstr "Super + Space"
165
132
166#: qml/Components/KeyboardShortcutsOverlay.qml:93
133#: qml/Components/KeyboardShortcutsOverlay.qml:93
167msgid "Switches to next keyboard layout."
134msgid "Switches to next keyboard layout."
168−msgstr "بدل إلى تخطيط لوحة المفاتيح التالي."
135+msgstr "للتحويل إلى مخطط لوحة المفاتيح التالي."
169
136
170#: qml/Components/KeyboardShortcutsOverlay.qml:101
137#: qml/Components/KeyboardShortcutsOverlay.qml:101
171msgid "Super + Shift + Space"
138msgid "Super + Shift + Space"
@@ -173,189 +140,193 @@ msgstr "Super + Shift + Space"
173
140
174#: qml/Components/KeyboardShortcutsOverlay.qml:106
141#: qml/Components/KeyboardShortcutsOverlay.qml:106
175msgid "Switches to previous keyboard layout."
142msgid "Switches to previous keyboard layout."
176−msgstr "بدل إلى تخطيط لوحة المفاتيح السابق."
143+msgstr "للتحويل إلى مخطط لوحة المفاتيح السابق."
177−
178−#: qml/Components/KeyboardShortcutsOverlay.qml:114
179−msgid "Ctrl + Alt + T"
180−msgstr "Ctrl + Alt + T"
181
144
182−#: qml/Components/KeyboardShortcutsOverlay.qml:119
145+#: qml/Components/KeyboardShortcutsOverlay.qml:118
183−msgid "Starts the Terminal application."
184−msgstr "شغِل الطرفية."
185−
186−#: qml/Components/KeyboardShortcutsOverlay.qml:131
187msgid "Launcher"
146msgid "Launcher"
188−msgstr "مطلق"
147+msgstr "شريط بدء التطبيقات"
189
148
190−#: qml/Components/KeyboardShortcutsOverlay.qml:138
149+#: qml/Components/KeyboardShortcutsOverlay.qml:125
191msgid "Super (Hold)"
150msgid "Super (Hold)"
192−msgstr "Super (ضغط مع التعليق)"
151+msgstr "Super (Hold)"
193
152
194−#: qml/Components/KeyboardShortcutsOverlay.qml:143
153+#: qml/Components/KeyboardShortcutsOverlay.qml:130
195msgid "Opens the launcher, displays shortcuts."
154msgid "Opens the launcher, displays shortcuts."
196−msgstr "يشغل المطلق، ويعرض الاختصارات."
155+msgstr "لفتح شريط بدء التطبيقات، وإظهار الاختصارات."
197
156
198−#: qml/Components/KeyboardShortcutsOverlay.qml:151
157+#: qml/Components/KeyboardShortcutsOverlay.qml:138
199msgid "Alt + F1"
158msgid "Alt + F1"
200msgstr "Alt + F1"
159msgstr "Alt + F1"
201
160
202−#: qml/Components/KeyboardShortcutsOverlay.qml:156
161+#: qml/Components/KeyboardShortcutsOverlay.qml:143
203msgid "Opens launcher keyboard navigation mode."
162msgid "Opens launcher keyboard navigation mode."
204−msgstr "فتح وضع التنقل بلوحة المفاتيح المشغلة."
163+msgstr ""
205
164
206−#: qml/Components/KeyboardShortcutsOverlay.qml:164
165+#: qml/Components/KeyboardShortcutsOverlay.qml:151
207msgid "Super + Tab"
166msgid "Super + Tab"
208msgstr "Super + Tab"
167msgstr "Super + Tab"
209
168
210−#: qml/Components/KeyboardShortcutsOverlay.qml:169
169+#: qml/Components/KeyboardShortcutsOverlay.qml:156
211msgid "Switches applications via the launcher."
170msgid "Switches applications via the launcher."
212−msgstr "انتقل بين التطبيقات عبر المُطلق."
171+msgstr "للتحويل بين التطبيقات عبر شريط بدء التطبيقات."
213
172
214−#: qml/Components/KeyboardShortcutsOverlay.qml:177
173+#: qml/Components/KeyboardShortcutsOverlay.qml:164
215−msgid "Super + 1 to 0"
174+msgid "Super + 0 to 9"
216−msgstr "Super + 1 to 0"
175+msgstr "Super + 0 to 9"
217
176
218−#: qml/Components/KeyboardShortcutsOverlay.qml:182
177+#: qml/Components/KeyboardShortcutsOverlay.qml:169
219msgid "Same as clicking on a launcher icon."
178msgid "Same as clicking on a launcher icon."
220−msgstr "نفس تأثير النقر على أيقونة المطلق."
179+msgstr "نفس إجراء الضغط على أيقونة في الشريط."
221
180
222−#: qml/Components/KeyboardShortcutsOverlay.qml:190
181+#: qml/Components/KeyboardShortcutsOverlay.qml:177
223msgid "Super + A"
182msgid "Super + A"
224msgstr "Super + A"
183msgstr "Super + A"
225
184
226−#: qml/Components/KeyboardShortcutsOverlay.qml:195
185+#: qml/Components/KeyboardShortcutsOverlay.qml:182
227msgid "Opens the Application Drawer."
186msgid "Opens the Application Drawer."
228−msgstr "يفتح درج التطبيقات."
187+msgstr ""
188+
189+#: qml/Components/KeyboardShortcutsOverlay.qml:194
190+msgid "Scopes"
191+msgstr ""
192+
193+#: qml/Components/KeyboardShortcutsOverlay.qml:201
194+msgid "Super (Tap)"
195+msgstr ""
196+
197+#: qml/Components/KeyboardShortcutsOverlay.qml:206
198+msgid "Opens the Scopes home."
199+msgstr ""
229
200
230−#: qml/Components/KeyboardShortcutsOverlay.qml:235
201+#: qml/Components/KeyboardShortcutsOverlay.qml:222
231msgid "Switching"
202msgid "Switching"
232−msgstr "يبدل"
203+msgstr "التبديل"
233
204
234−#: qml/Components/KeyboardShortcutsOverlay.qml:242
205+#: qml/Components/KeyboardShortcutsOverlay.qml:229
235msgid "Alt + Tab"
206msgid "Alt + Tab"
236msgstr "Alt + Tab"
207msgstr "Alt + Tab"
237
208
238−#: qml/Components/KeyboardShortcutsOverlay.qml:247
209+#: qml/Components/KeyboardShortcutsOverlay.qml:234
239msgid "Switches between applications."
210msgid "Switches between applications."
240−msgstr "يبدل بين التطبيقات."
211+msgstr "للتبديل بين التطبيقات المفتوحة."
241
212
242−#: qml/Components/KeyboardShortcutsOverlay.qml:255
213+#: qml/Components/KeyboardShortcutsOverlay.qml:242
243msgid "Super + W"
214msgid "Super + W"
244−msgstr "Super + W"
215+msgstr ""
245
216
246−#: qml/Components/KeyboardShortcutsOverlay.qml:260
217+#: qml/Components/KeyboardShortcutsOverlay.qml:247
247msgid "Opens the desktop spread."
218msgid "Opens the desktop spread."
248−msgstr "يفتح وضع سطح المكتب."
219+msgstr ""
249
220
250−#: qml/Components/KeyboardShortcutsOverlay.qml:268
221+#: qml/Components/KeyboardShortcutsOverlay.qml:255
251msgid "Cursor Left or Right"
222msgid "Cursor Left or Right"
252−msgstr "اتجاه المؤشر لليمين أو اليسار"
223+msgstr ""
253
224
254−#: qml/Components/KeyboardShortcutsOverlay.qml:273
225+#: qml/Components/KeyboardShortcutsOverlay.qml:260
255msgid "Moves the focus."
226msgid "Moves the focus."
256−msgstr "بدّل التركيز."
227+msgstr "لنقل التركيز."
257
228
258−#: qml/Components/KeyboardShortcutsOverlay.qml:285
229+#: qml/Components/KeyboardShortcutsOverlay.qml:272
259msgid "Windows"
230msgid "Windows"
260−msgstr "نوافذ"
231+msgstr "النوافذ"
261
232
262−#: qml/Components/KeyboardShortcutsOverlay.qml:292
233+#: qml/Components/KeyboardShortcutsOverlay.qml:279
263msgid "Ctrl + Super + D"
234msgid "Ctrl + Super + D"
264msgstr "Ctrl + Super + D"
235msgstr "Ctrl + Super + D"
265
236
266−#: qml/Components/KeyboardShortcutsOverlay.qml:297
237+#: qml/Components/KeyboardShortcutsOverlay.qml:284
267msgid "Minimizes all windows."
238msgid "Minimizes all windows."
268−msgstr "يصغر كل النوافذ."
239+msgstr "لتصغير جميع النوافذ."
269
240
270−#: qml/Components/KeyboardShortcutsOverlay.qml:305
241+#: qml/Components/KeyboardShortcutsOverlay.qml:292
271msgid "Ctrl + Super + Up"
242msgid "Ctrl + Super + Up"
272msgstr "Ctrl + Super + Up"
243msgstr "Ctrl + Super + Up"
273
244
274−#: qml/Components/KeyboardShortcutsOverlay.qml:310
245+#: qml/Components/KeyboardShortcutsOverlay.qml:297
275msgid "Maximizes the current window."
246msgid "Maximizes the current window."
276−msgstr "يكبر النافذة الحالية."
247+msgstr "لتكبير النافذة الحالية."
277
248
278−#: qml/Components/KeyboardShortcutsOverlay.qml:318
249+#: qml/Components/KeyboardShortcutsOverlay.qml:305
279msgid "Ctrl + Super + Down"
250msgid "Ctrl + Super + Down"
280msgstr "Ctrl + Super + Down"
251msgstr "Ctrl + Super + Down"
281
252
282−#: qml/Components/KeyboardShortcutsOverlay.qml:323
253+#: qml/Components/KeyboardShortcutsOverlay.qml:310
283msgid "Minimizes or restores the current window."
254msgid "Minimizes or restores the current window."
284−msgstr "يصغر أو يستعيد النافذة الحالية."
255+msgstr "لتصغير او استعادة النافذة الحالية."
285
256
286−#: qml/Components/KeyboardShortcutsOverlay.qml:331
257+#: qml/Components/KeyboardShortcutsOverlay.qml:318
287msgid "Ctrl + Super + Left or Right"
258msgid "Ctrl + Super + Left or Right"
288−msgstr "Ctrl + Super + Left or Right"
259+msgstr ""
289
260
290−#: qml/Components/KeyboardShortcutsOverlay.qml:336
261+#: qml/Components/KeyboardShortcutsOverlay.qml:323
291msgid "Semi-maximizes the current window."
262msgid "Semi-maximizes the current window."
292−msgstr "كبر النافذة الحالة جزئيا."
263+msgstr ""
293
264
294−#: qml/Components/KeyboardShortcutsOverlay.qml:344
265+#: qml/Components/KeyboardShortcutsOverlay.qml:331
295msgid "Alt + F4"
266msgid "Alt + F4"
296−msgstr "Alt + F4"
267+msgstr ""
297
268
298−#: qml/Components/KeyboardShortcutsOverlay.qml:349
269+#: qml/Components/KeyboardShortcutsOverlay.qml:336
299msgid "Closes the current window."
270msgid "Closes the current window."
300−msgstr "يغلق النافذة الحالية."
271+msgstr ""
301
272
302−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:235
273+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:252
303msgid "Return to Call"
274msgid "Return to Call"
304−msgstr "عُد للمكالمة"
275+msgstr "العودة إلى المكالمة"
305
276
306#: qml/Components/Lockscreen.qml:212
277#: qml/Components/Lockscreen.qml:212
307msgid "Emergency Call"
278msgid "Emergency Call"
308msgstr "مكالمة طوارئ"
279msgstr "مكالمة طوارئ"
309
280
310−#: qml/Components/Lockscreen.qml:245
281+#: qml/Components/Lockscreen.qml:244
311msgid "OK"
282msgid "OK"
312msgstr "موافق"
283msgstr "موافق"
313
284
314#: qml/Components/MediaServices/VideoPlayerControls.qml:44
285#: qml/Components/MediaServices/VideoPlayerControls.qml:44
315#, qt-format
286#, qt-format
316msgid "%1:%2:%3"
287msgid "%1:%2:%3"
317−msgstr "%1:%2:%3"
288+msgstr ""
318
289
319#: qml/Components/MediaServices/VideoPlayerControls.qml:49
290#: qml/Components/MediaServices/VideoPlayerControls.qml:49
320#, qt-format
291#, qt-format
321msgid "%1:%2"
292msgid "%1:%2"
322−msgstr "%1:%2"
293+msgstr ""
323
294
324−#: qml/Components/ModeSwitchWarningDialog.qml:33
295+#: qml/Components/ModeSwitchWarningDialog.qml:32
325msgid "Apps may have unsaved data:"
296msgid "Apps may have unsaved data:"
326−msgstr "ربما لم تَحفظ بيانات هذه التطبيقات:"
297+msgstr ""
327
298
328−#: qml/Components/ModeSwitchWarningDialog.qml:60
299+#: qml/Components/ModeSwitchWarningDialog.qml:57
329msgctxt ""
300msgctxt ""
330"Re-dock means connect the device again to an external screen/mouse/keyboard"
301"Re-dock means connect the device again to an external screen/mouse/keyboard"
331msgid "Re-dock, save your work and close these apps to continue."
302msgid "Re-dock, save your work and close these apps to continue."
332−msgstr "أعد الوصل، احفظ عملك على هذه التطبيقات ثم أغلقها للمتابعة."
303+msgstr ""
333
304
334−#: qml/Components/ModeSwitchWarningDialog.qml:67
305+#: qml/Components/ModeSwitchWarningDialog.qml:63
335msgid "Or force close now (unsaved data will be lost)."
306msgid "Or force close now (unsaved data will be lost)."
336−msgstr "أو أغلقها قسريا (ستفقد البيانات غير المحفوظة)."
307+msgstr "أو أغلق إجباريا الآن (ستفقد أي بيانات غير محفوظة)."
337
308
338−#: qml/Components/ModeSwitchWarningDialog.qml:80
309+#: qml/Components/ModeSwitchWarningDialog.qml:75
339msgid "OK, I will reconnect"
310msgid "OK, I will reconnect"
340−msgstr "موافق، سؤعيد الاتصال"
311+msgstr ""
341
312
342−#: qml/Components/ModeSwitchWarningDialog.qml:81
313+#: qml/Components/ModeSwitchWarningDialog.qml:76
343msgid "Reconnect now!"
314msgid "Reconnect now!"
344−msgstr "أعد الاتصال الآن!"
315+msgstr ""
345
316
346−#: qml/Components/ModeSwitchWarningDialog.qml:94
317+#: qml/Components/ModeSwitchWarningDialog.qml:88
347msgid "Close all"
318msgid "Close all"
348−msgstr "أغلق الكل"
319+msgstr ""
349
320
350#: qml/Components/SharingPicker.qml:54
321#: qml/Components/SharingPicker.qml:54
351msgid "Preview Share Item"
322msgid "Preview Share Item"
352−msgstr "معاينة الملف المشارك"
323+msgstr ""
353
324
354#: qml/Components/VirtualTouchPad.qml:317
325#: qml/Components/VirtualTouchPad.qml:317
355msgid ""
326msgid ""
356"Your device is now connected to an external display. Use this screen as a "
327"Your device is now connected to an external display. Use this screen as a "
357"touch pad to interact with the pointer."
328"touch pad to interact with the pointer."
358−msgstr "جهازك متصل بجهاز عرض خارجي. استخدم جهازك كلوحة لمس لتحكم بالمؤشر."
329+msgstr ""
359
330
360#: qml/Components/VirtualTouchPad.qml:327
331#: qml/Components/VirtualTouchPad.qml:327
361msgid "Tap left button to click."
332msgid "Tap left button to click."
@@ -363,19 +334,116 @@ msgstr "اضغط الزر الأيسر للنقر."
363
334
364#: qml/Components/VirtualTouchPad.qml:339
335#: qml/Components/VirtualTouchPad.qml:339
365msgid "Tap right button to right click."
336msgid "Tap right button to right click."
366−msgstr "اضغط على الزر الأيمن للنقر."
337+msgstr "اضغط الزر الأيمن للنقر الأيمن."
367
338
368#: qml/Components/VirtualTouchPad.qml:351
339#: qml/Components/VirtualTouchPad.qml:351
369msgid "Swipe with two fingers to scroll."
340msgid "Swipe with two fingers to scroll."
370−msgstr "اسحب بإصبعين للتمرير."
341+msgstr ""
371
342
372#: qml/Components/VirtualTouchPad.qml:396
343#: qml/Components/VirtualTouchPad.qml:396
373msgid "Find more settings in the system settings."
344msgid "Find more settings in the system settings."
374−msgstr "جد إعدادات إضافية في إعدادات النظام."
345+msgstr "اعثر على مزيد من الإعدادات في إعدادات النظام."
346+
347+#: qml/Dash/DashPageHeader.qml:361
348+msgctxt "Button: Open the Ubuntu Store"
349+msgid "Store"
350+msgstr "المتجر"
351+
352+#: qml/Dash/DashPageHeader.qml:368
353+msgctxt "Button: Start a search in the current dash scope"
354+msgid "Search"
355+msgstr "بحث"
356+
357+#: qml/Dash/DashPageHeader.qml:378
358+msgctxt "Button: Show the current dash scope settings"
359+msgid "Settings"
360+msgstr "الإعدادات"
361+
362+#: qml/Dash/DashPageHeader.qml:385
363+msgid "Remove from Favorites"
364+msgstr "حذف من المفضلات"
365+
366+#: qml/Dash/DashPageHeader.qml:385
367+msgid "Add to Favorites"
368+msgstr "إضافة إلى المفضلات"
369+
370+#: qml/Dash/FiltersPopover.qml:61
371+msgid "Refine your results"
372+msgstr ""
373+
374+#: qml/Dash/FiltersPopover.qml:70
375+msgid "Reset"
376+msgstr ""
377+
378+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
379+msgid "Show less"
380+msgstr "عرض أقل"
381+
382+#: qml/Dash/GenericScopeView.qml:547
383+msgid "Show all"
384+msgstr "عرض الكل"
385+
386+#: qml/Dash/GenericScopeView.qml:578
387+msgctxt "Label: Hint for dash search line edit"
388+msgid "Search"
389+msgstr "بحث"
390+
391+#: qml/Dash/PageHeaderExtraPanel.qml:67
392+msgid "Recent Searches"
393+msgstr ""
394+
395+#: qml/Dash/PageHeaderExtraPanel.qml:78
396+msgid "Clear All"
397+msgstr ""
398+
399+#: qml/Dash/Previews/PreviewActionCombo.qml:36
400+msgid "More..."
401+msgstr "المزيد..."
402+
403+#: qml/Dash/Previews/PreviewActionCombo.qml:36
404+msgid "Less..."
405+msgstr "أقل..."
406+
407+#: qml/Dash/Previews/PreviewCommentInput.qml:83
408+#: qml/Dash/Previews/PreviewRatingInput.qml:202
409+msgid "Send"
410+msgstr "أرسل"
411+
412+#: qml/Dash/Previews/PreviewRatingInput.qml:109
413+msgid "Rate this"
414+msgstr "قيّم ذلك"
415+
416+#: qml/Dash/Previews/PreviewRatingInput.qml:184
417+msgid "Add a review"
418+msgstr "أضف تعليق"
419+
420+#: qml/Dash/PullToRefreshScopeStyle.qml:56
421+msgid "Pull to refresh…"
422+msgstr "اسحب للتحديث..."
423+
424+#: qml/Dash/PullToRefreshScopeStyle.qml:61
425+msgid "Release to refresh…"
426+msgstr "حرّر للتحديث..."
427+
428+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
429+msgid "Enable location data"
430+msgstr "تفعيل بيانات الموقع"
431+
432+#: qml/Dash/ScopesList.qml:146
433+msgid "Manage"
434+msgstr "إدارة"
435+
436+#: qml/Dash/ScopesList.qml:187
437+msgid "Home"
438+msgstr "الرئيسية"
439+
440+#: qml/Dash/ScopesList.qml:188
441+msgid "Also installed"
442+msgstr "أيضا تم تثبيت"
375
443
376#: qml/Greeter/CoverPage.qml:127
444#: qml/Greeter/CoverPage.qml:127
377msgid "Unlock"
445msgid "Unlock"
378−msgstr "فك الإيصاد"
446+msgstr "فك القفل"
379
447
380#: qml/Greeter/DelayedLockscreen.qml:43
448#: qml/Greeter/DelayedLockscreen.qml:43
381msgid "Device Locked"
449msgid "Device Locked"
@@ -395,56 +463,57 @@ msgstr ""
395#, qt-format
463#, qt-format
396msgid "Please wait %1 minute and then try again…"
464msgid "Please wait %1 minute and then try again…"
397msgid_plural "Please wait %1 minutes and then try again…"
465msgid_plural "Please wait %1 minutes and then try again…"
398−msgstr[0] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا…"
466+msgstr[0] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا..."
399−msgstr[1] "برجاء الانتظار دقيقة واحدة (%1) ثم المحاولة مجددًا…"
467+msgstr[1] "برجاء الانتظار دقيقة واحدة (%1) ثم المحاولة مجددًا..."
400−msgstr[2] "برجاء الانتظار دقيقتين (%1) ثم المحاولة مجددًا…"
468+msgstr[2] "برجاء الانتظار دقيقتين (%1) ثم المحاولة مجددًا..."
401−msgstr[3] "برجاء الانتظار %1 دقائق ثم المحاولة مجددًا…"
469+msgstr[3] "برجاء الانتظار %1 دقائق ثم المحاولة مجددًا..."
402−msgstr[4] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا…"
470+msgstr[4] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا..."
403−msgstr[5] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا…"
471+msgstr[5] "برجاء الانتظار %1 دقيقة ثم المحاولة مجددًا..."
404−
472+
405−#: qml/Greeter/Greeter.qml:550
473+#: qml/Greeter/Greeter.qml:592
406msgid "Try again"
474msgid "Try again"
407−msgstr "حاول مجددا"
475+msgstr ""
408
476
409−#: qml/Greeter/Greeter.qml:551
477+#: qml/Greeter/LoginList.qml:70
410−msgid "Enter passphrase to unlock"
478+msgid "Passphrase"
411−msgstr "أدخِل العبارة السرية لفك الإيصاد"
479+msgstr ""
412
480
413−#: qml/Greeter/Greeter.qml:552
481+#: qml/Greeter/LoginList.qml:71
414−msgid "Enter passcode to unlock"
482+msgid "Passcode"
415−msgstr "أدخِل الرمز السرّي لفك الإيصاد"
483+msgstr ""
416
484
417−#: qml/Greeter/NarrowView.qml:235
485+#: qml/Greeter/LoginList.qml:98
418−msgid "Emergency"
486+msgid "Retry"
419−msgstr "طوارئ"
487+msgstr "إعادة المحاولة"
420
488
421−#: qml/Greeter/PromptList.qml:126
489+#: qml/Greeter/LoginList.qml:99
422−msgid "Passphrase"
490+msgid "Log In"
423−msgstr "كلمة السر"
491+msgstr ""
424
492
425−#: qml/Greeter/PromptList.qml:126
493+#: qml/Greeter/NarrowView.qml:252
426−msgid "Passcode"
494+msgid "Emergency"
427−msgstr "الرمز السري"
495+msgstr ""
428
496
429−#: qml/Greeter/SessionsList.qml:124
497+#: qml/Greeter/SessionsList.qml:122
430msgid "Select desktop environment"
498msgid "Select desktop environment"
431−msgstr "اختر بيئة سطح المكتب"
499+msgstr ""
432
500
433−#: qml/Launcher/Drawer.qml:250
501+#: qml/Launcher/Drawer.qml:80
434msgid "Search…"
502msgid "Search…"
435−msgstr "ابحث…"
503+msgstr ""
436
504
437−#: qml/Launcher/PullToRefreshScopeStyle.qml:56
505+#: qml/Launcher/Drawer.qml:101
506+msgctxt "Apps sorted alphabetically"
438−msgid "Pull to refresh…"
507+msgid "A-Z"
439−msgstr "اسحب للتحديث…"
508+msgstr ""
440
509
441−#: qml/Launcher/PullToRefreshScopeStyle.qml:61
510+#: qml/Launcher/MoreAppsHeader.qml:32
442−msgid "Release to refresh…"
511+msgid "More apps in the store"
443−msgstr "حرّر للتحديث…"
512+msgstr ""
444
513
445#: qml/Notifications/NotificationMenuItemFactory.qml:124
514#: qml/Notifications/NotificationMenuItemFactory.qml:124
446msgid "Show password"
515msgid "Show password"
447−msgstr "اعرض كلمة السر"
516+msgstr "عرض كلمة السر"
448
517
449#: qml/Panel/ActiveCallHint.qml:79
518#: qml/Panel/ActiveCallHint.qml:79
450msgid "Tap to return to call..."
519msgid "Tap to return to call..."
@@ -473,9 +542,9 @@ msgstr[5] "%1 ساعة"
473#, qt-format
542#, qt-format
474msgid "%1 minute"
543msgid "%1 minute"
475msgid_plural "%1 minutes"
544msgid_plural "%1 minutes"
476−msgstr[0] "%1 دقيقة"
545+msgstr[0] "أقل من دقيقة (%1)"
477−msgstr[1] "دقيقة واحدة"
546+msgstr[1] "دقيقة واحدة (%1)"
478−msgstr[2] "دقيقتان"
547+msgstr[2] "دقيقتان (%1)"
479msgstr[3] "%1 دقائق"
548msgstr[3] "%1 دقائق"
480msgstr[4] "%1 دقيقة"
549msgstr[4] "%1 دقيقة"
481msgstr[5] "%1 دقيقة"
550msgstr[5] "%1 دقيقة"
@@ -503,11 +572,11 @@ msgstr "باق %1"
503
572
504#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1017
573#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1017
505msgid "In queue…"
574msgid "In queue…"
506−msgstr "في الانتظار…"
575+msgstr "في الانتظار..."
507
576
508#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1021
577#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1021
509msgid "Downloading"
578msgid "Downloading"
510−msgstr "ينزل"
579+msgstr "التنزيل"
511
580
512#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1023
581#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1023
513msgid "Paused, tap to resume"
582msgid "Paused, tap to resume"
@@ -515,7 +584,7 @@ msgstr "مُلبث، انقر للاستئناف"
515
584
516#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1025
585#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1025
517msgid "Canceled"
586msgid "Canceled"
518−msgstr "أُلغي"
587+msgstr "تم إلغائه"
519
588
520#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
589#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
521msgid "Finished"
590msgid "Finished"
@@ -523,13 +592,13 @@ msgstr "انتهى"
523
592
524#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
593#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
525msgid "Failed, tap to retry"
594msgid "Failed, tap to retry"
526−msgstr "فشل، انقر لإعادة المحاولة"
595+msgstr "فشل، انقل لإعادة المحاولة"
527
596
528#: qml/Panel/Indicators/MessageMenuItemFactory.qml:151
597#: qml/Panel/Indicators/MessageMenuItemFactory.qml:151
529#: qml/Panel/Indicators/MessageMenuItemFactory.qml:210
598#: qml/Panel/Indicators/MessageMenuItemFactory.qml:210
530msgctxt "Button: Send a reply message"
599msgctxt "Button: Send a reply message"
531msgid "Send"
600msgid "Send"
532−msgstr "أرسل"
601+msgstr ""
533
602
534#: qml/Panel/Indicators/MessageMenuItemFactory.qml:152
603#: qml/Panel/Indicators/MessageMenuItemFactory.qml:152
535msgctxt "Label: Hint in message indicator line edit"
604msgctxt "Label: Hint in message indicator line edit"
@@ -539,431 +608,349 @@ msgstr "رد"
539#: qml/Panel/Indicators/MessageMenuItemFactory.qml:209
608#: qml/Panel/Indicators/MessageMenuItemFactory.qml:209
540msgctxt "Button: Call back on phone"
609msgctxt "Button: Call back on phone"
541msgid "Call back"
610msgid "Call back"
542−msgstr "عاود الاتصال"
611+msgstr ""
543−
544−#: qml/Panel/PanelMenuPage.qml:92
545−msgid "Back"
546−msgstr "للخلف"
547
612
548#: qml/Stage/SideStage.qml:76
613#: qml/Stage/SideStage.qml:76
549msgid "Drag using 3 fingers any application from one window to the other"
614msgid "Drag using 3 fingers any application from one window to the other"
550−msgstr "اسحب أي تطبيق بثلاث أصابع من نافذة لأخرى"
615+msgstr ""
551−
552−#: qml/Stage/Stage.qml:671
553−msgid "No running apps"
554−msgstr "لا توجد تطبيقات مشغلة"
555
616
556#: qml/Tutorial/TutorialLeftLong.qml:49
617#: qml/Tutorial/TutorialLeftLong.qml:49
557−msgid "Long swipe from the left edge to open the Application Drawer"
618+msgid "Long swipe from the left edge to open the Today scope"
558−msgstr "اسحب اصبعك مطولا بدءً من الحافة اليسرى لفتح درج التطبيقات"
619+msgstr ""
559
620
560#: qml/Tutorial/TutorialLeft.qml:47
621#: qml/Tutorial/TutorialLeft.qml:47
561msgid "Short swipe from the left edge to open the launcher"
622msgid "Short swipe from the left edge to open the launcher"
562−msgstr "اسحب اصبعك سحبا قصيرا بدءً من الحافة اليسرى لفتح المُطلِق"
623+msgstr ""
563
624
564−#: qml/Tutorial/TutorialRight.qml:54
625+#: qml/Tutorial/TutorialRight.qml:55
565msgid "Push your mouse against the right edge to view your open apps"
626msgid "Push your mouse against the right edge to view your open apps"
566−msgstr "حرك المؤشر للحافة اليمنى لعرض التطبيقات المفتوحة"
627+msgstr ""
567
628
568−#: qml/Tutorial/TutorialRight.qml:55
629+#: qml/Tutorial/TutorialRight.qml:56
569msgid "Swipe from the right edge to view your open apps"
630msgid "Swipe from the right edge to view your open apps"
570−msgstr "اسحب اصبعك بدءً من الحافة اليمنى لعرض التطبيقات المفتوحة"
631+msgstr ""
571
632
572#: qml/Tutorial/TutorialTop.qml:53
633#: qml/Tutorial/TutorialTop.qml:53
573msgid "Swipe from the top edge to access notifications and quick settings"
634msgid "Swipe from the top edge to access notifications and quick settings"
574msgstr ""
635msgstr ""
575−"اسحب اصبعك بدءً من الحافة العلوية للوصول الى التنبيهات والإعدادات السريعة"
576
636
577−#: qml/Wizard/Page.qml:59
637+#: qml/Wizard/Page.qml:54
578msgctxt "Button: Go back one page in the Wizard"
638msgctxt "Button: Go back one page in the Wizard"
579msgid "Back"
639msgid "Back"
580−msgstr "للخلف"
640+msgstr "عودة"
581
641
582−#: qml/Wizard/Pages/10-welcome.qml:29
642+#: qml/Wizard/Pages/10-welcome.qml:28
583msgid "Language"
643msgid "Language"
584−msgstr "اللغة"
644+msgstr ""
585−
586−#: qml/Wizard/Pages/10-welcome.qml:176
587−#: qml/Wizard/Pages/10-welcome-update.qml:126
588−#: qml/Wizard/Pages/11-changelog.qml:74 qml/Wizard/Pages/20-keyboard.qml:152
589−#: qml/Wizard/Pages/30-wifi.qml:214 qml/Wizard/Pages/50-timezone.qml:272
590−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/70-passwd-type.qml:146
591−#: qml/Wizard/Pages/passcode-desktop.qml:154
592−#: qml/Wizard/Pages/password-set.qml:153
593−msgid "Next"
594−msgstr "التالي"
595−
596−#: qml/Wizard/Pages/10-welcome-update.qml:91
597−msgid "Welcome to "
598−msgstr "مرحبا بك في "
599−
600−#: qml/Wizard/Pages/10-welcome-update.qml:106
601−msgid "We will make sure your device is ready to use "
602−msgstr "سوف نتأكد أن جهازك معد للاستخدام "
603−
604−#: qml/Wizard/Pages/11-changelog.qml:28
605−msgid "What's new"
606−msgstr "ما الجديد"
607
645
608−#: qml/Wizard/Pages/11-changelog.qml:74
646+#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
647+#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
648+#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
649+#: qml/Wizard/Pages/70-passwd-type.qml:145
650+#: qml/Wizard/Pages/75-report-check.qml:84
651+#: qml/Wizard/Pages/passcode-desktop.qml:142
652+#: qml/Wizard/Pages/password-set.qml:142
609−msgid "Loading..."
653+msgid "Next"
610−msgstr "يحمل..."
654+msgstr ""
611
655
612#: qml/Wizard/Pages/20-keyboard.qml:31
656#: qml/Wizard/Pages/20-keyboard.qml:31
613msgid "Select Keyboard"
657msgid "Select Keyboard"
614−msgstr "اختر لوحة المفاتيح"
658+msgstr ""
615
659
616#: qml/Wizard/Pages/20-keyboard.qml:71
660#: qml/Wizard/Pages/20-keyboard.qml:71
617msgid "Keyboard language"
661msgid "Keyboard language"
618−msgstr "لغة لوحة المفاتيح"
662+msgstr ""
619
663
620#: qml/Wizard/Pages/20-keyboard.qml:93
664#: qml/Wizard/Pages/20-keyboard.qml:93
621msgid "Keyboard layout"
665msgid "Keyboard layout"
622−msgstr "تخطيط لوحة المفاتيح"
666+msgstr ""
623
667
624−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
668+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
625−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
669+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
626#: qml/Wizard/Pages/sim.qml:101
670#: qml/Wizard/Pages/sim.qml:101
627msgid "Skip"
671msgid "Skip"
628−msgstr "تخط"
672+msgstr "تخطي"
629
673
630#: qml/Wizard/Pages/30-wifi.qml:31
674#: qml/Wizard/Pages/30-wifi.qml:31
631msgid "Connect to Wi‑Fi"
675msgid "Connect to Wi‑Fi"
632−msgstr "اتصل بالإنترنت"
676+msgstr "اتصل بالواي فاي"
633
677
634−#: qml/Wizard/Pages/30-wifi.qml:139
678+#: qml/Wizard/Pages/30-wifi.qml:132
635msgid "Connected"
679msgid "Connected"
636−msgstr "متصل"
680+msgstr ""
637
681
638−#: qml/Wizard/Pages/30-wifi.qml:172
682+#: qml/Wizard/Pages/30-wifi.qml:165
639msgid "Available Wi-Fi networks"
683msgid "Available Wi-Fi networks"
640−msgstr "شبكات الواي فاي المتاحة"
684+msgstr ""
641
685
642−#: qml/Wizard/Pages/30-wifi.qml:173
686+#: qml/Wizard/Pages/30-wifi.qml:166
643msgid "No available Wi-Fi networks"
687msgid "No available Wi-Fi networks"
644−msgstr "لا توجد شبكات واي فاي"
688+msgstr ""
689+
690+#: qml/Wizard/Pages/40-location.qml:27
691+msgid "Location Services"
692+msgstr ""
693+
694+#: qml/Wizard/Pages/40-location.qml:83
695+msgid ""
696+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
697+"(recommended)"
698+msgstr ""
699+
700+#: qml/Wizard/Pages/40-location.qml:105
701+#, qt-format
702+msgid "By selecting this option you agree to the Nokia HERE %1."
703+msgstr ""
704+
705+#: qml/Wizard/Pages/40-location.qml:106
706+msgctxt "part of: Nokia HERE terms and conditions"
707+msgid "terms and conditions"
708+msgstr ""
709+
710+#: qml/Wizard/Pages/40-location.qml:160
711+msgid "GPS only"
712+msgstr ""
713+
714+#: qml/Wizard/Pages/40-location.qml:214
715+msgid "Don't use my location"
716+msgstr ""
717+
718+#: qml/Wizard/Pages/40-location.qml:260
719+msgid "You can change it later in System Settings."
720+msgstr ""
645
721
646#: qml/Wizard/Pages/50-timezone.qml:30
722#: qml/Wizard/Pages/50-timezone.qml:30
647msgid "Time Zone"
723msgid "Time Zone"
648−msgstr "المنطقة الزمنية"
724+msgstr ""
649
725
650−#: qml/Wizard/Pages/50-timezone.qml:183
726+#: qml/Wizard/Pages/50-timezone.qml:182
651msgid "Enter your city"
727msgid "Enter your city"
652−msgstr "أدخل مدينتك"
728+msgstr ""
653
729
654#: qml/Wizard/Pages/60-account.qml:24
730#: qml/Wizard/Pages/60-account.qml:24
655msgid "Personalize Your Device"
731msgid "Personalize Your Device"
656−msgstr "خصص جهازك"
732+msgstr ""
657
733
658−#: qml/Wizard/Pages/60-account.qml:54
734+#: qml/Wizard/Pages/60-account.qml:48
659msgid "Preferred Name"
735msgid "Preferred Name"
660−msgstr "اسم مستحسن"
736+msgstr ""
661
737
662#: qml/Wizard/Pages/70-passwd-type.qml:40
738#: qml/Wizard/Pages/70-passwd-type.qml:40
663msgid "Lock Screen"
739msgid "Lock Screen"
664−msgstr "قفل الشاشة"
740+msgstr ""
665
741
666−#: qml/Wizard/Pages/70-passwd-type.qml:103
742+#: qml/Wizard/Pages/70-passwd-type.qml:102
667msgctxt "Label: Type of security method"
743msgctxt "Label: Type of security method"
668msgid "Create new password"
744msgid "Create new password"
669−msgstr "أنشئ كلمة سر جديدة"
745+msgstr ""
670
746
671−#: qml/Wizard/Pages/70-passwd-type.qml:105
747+#: qml/Wizard/Pages/70-passwd-type.qml:104
672msgctxt "Label: Type of security method"
748msgctxt "Label: Type of security method"
673msgid "Create passcode (numbers only)"
749msgid "Create passcode (numbers only)"
674−msgstr "أنشئ رمز مرور (أرقام فقط)"
750+msgstr ""
675
751
676−#: qml/Wizard/Pages/70-passwd-type.qml:107
752+#: qml/Wizard/Pages/70-passwd-type.qml:106
677msgctxt "Label: Type of security method"
753msgctxt "Label: Type of security method"
678msgid "No lock code"
754msgid "No lock code"
679−msgstr "لا يوجد رمز إيصاد"
755+msgstr ""
756+
757+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
758+msgid "Privacy Policy"
759+msgstr ""
760+
761+#: qml/Wizard/Pages/75-report-check.qml:26
762+msgid "Help Us Improve"
763+msgstr ""
680
764
765+#: qml/Wizard/Pages/75-report-check.qml:59
766+msgid "Improve system performance by sending us crashes and error reports."
767+msgstr ""
768+
769+#: qml/Wizard/Pages/75-report-check.qml:60
770+msgid "Privacy policy"
771+msgstr ""
772+
681−#: qml/Wizard/Pages/79-system-update.qml:28
773+#: qml/Wizard/Pages/77-system-update.qml:28
682msgid "Update Device"
774msgid "Update Device"
683−msgstr "حدث الجهاز"
775+msgstr ""
684
776
685−#: qml/Wizard/Pages/79-system-update.qml:55
777+#: qml/Wizard/Pages/77-system-update.qml:55
686msgid ""
778msgid ""
687"There is a system update available and ready to install. Afterwards, the "
779"There is a system update available and ready to install. Afterwards, the "
688"device will automatically restart."
780"device will automatically restart."
689−msgstr "يتوفر تحديث للنظام وهو جاهز للتثبيت، سيُعاد تشغيل الجهاز تلقائيا."
781+msgstr ""
690
782
691−#: qml/Wizard/Pages/79-system-update.qml:76
783+#: qml/Wizard/Pages/77-system-update.qml:76
692msgctxt "string identifying name of the update"
784msgctxt "string identifying name of the update"
693−msgid "Ubuntu Touch system"
785+msgid "Ubuntu system"
694−msgstr "نظام أبونتو تاتش"
786+msgstr ""
695
787
696−#: qml/Wizard/Pages/79-system-update.qml:83
788+#: qml/Wizard/Pages/77-system-update.qml:83
697#, qt-format
789#, qt-format
698msgctxt "version of the system update"
790msgctxt "version of the system update"
699msgid "Version %1"
791msgid "Version %1"
700−msgstr "الإصدار %1"
792+msgstr ""
701
793
702−#: qml/Wizard/Pages/79-system-update.qml:95
794+#: qml/Wizard/Pages/77-system-update.qml:102
703msgid "This could take a few minutes..."
795msgid "This could take a few minutes..."
704−msgstr "قد يحتاج بضع دقائق..."
796+msgstr ""
705
797
706−#: qml/Wizard/Pages/79-system-update.qml:109
798+#: qml/Wizard/Pages/77-system-update.qml:116
707msgid "Install and restart now"
799msgid "Install and restart now"
708−msgstr "ثبت وأعد التشغيل الآن"
800+msgstr ""
709−
710−#: qml/Wizard/Pages/80-finished.qml:91
711−msgid "Welcome Back"
712−msgstr "مرحبا بعودتك"
713
801
714−#: qml/Wizard/Pages/80-finished.qml:91
802+#: qml/Wizard/Pages/80-finished.qml:89
715msgid "Welcome to Ubuntu"
803msgid "Welcome to Ubuntu"
716−msgstr "مرحبا بك في أبونتو"
804+msgstr ""
717
805
718−#: qml/Wizard/Pages/80-finished.qml:106
806+#: qml/Wizard/Pages/80-finished.qml:104
719msgid "You are ready to use your device now"
807msgid "You are ready to use your device now"
720−msgstr "أنت مستعد لاستخدام جهازك"
808+msgstr ""
721−
722−#: qml/Wizard/Pages/80-finished.qml:126
723−msgid "Continue"
724−msgstr "تابع"
725
809
726−#: qml/Wizard/Pages/80-finished.qml:126
810+#: qml/Wizard/Pages/80-finished.qml:124
727msgid "Get Started"
811msgid "Get Started"
728−msgstr "ابدأ"
812+msgstr ""
813+
814+#: qml/Wizard/Pages/here-terms.qml:25
815+msgid "Terms & Conditions"
816+msgstr "الشروط والأحكام"
817+
818+#: qml/Wizard/Pages/here-terms.qml:69
819+msgid "Your device uses positioning technologies provided by HERE."
820+msgstr ""
821+
822+#: qml/Wizard/Pages/here-terms.qml:81
823+msgid ""
824+"To provide you with positioning services and to improve their quality, HERE "
825+"collects information about nearby cell towers and Wi-Fi hotspots around your "
826+"current location whenever your position is being found."
827+msgstr ""
828+
829+#: qml/Wizard/Pages/here-terms.qml:93
830+msgid ""
831+"The information collected is used to analyze the service and to improve the "
832+"use of service, but not to identify you personally."
833+msgstr ""
834+
835+#: qml/Wizard/Pages/here-terms.qml:106
836+#, qt-format
837+msgid "By continuing, you agree to the HERE platform %1 and %2."
838+msgstr ""
839+
840+#: qml/Wizard/Pages/here-terms.qml:107
841+msgid "Service Terms"
842+msgstr ""
729
843
730#: qml/Wizard/Pages/passcode-confirm.qml:43
844#: qml/Wizard/Pages/passcode-confirm.qml:43
731−#: qml/Wizard/Pages/passcode-desktop.qml:104
845+#: qml/Wizard/Pages/passcode-desktop.qml:97
732msgid "Confirm passcode"
846msgid "Confirm passcode"
733−msgstr "تأكيد كلمة السر"
847+msgstr "تأكيد الرمز السري"
734
848
735#: qml/Wizard/Pages/passcode-confirm.qml:45
849#: qml/Wizard/Pages/passcode-confirm.qml:45
736msgid "Incorrect passcode."
850msgid "Incorrect passcode."
737−msgstr "الرمز السري غير صحيح."
851+msgstr ""
738
852
739#: qml/Wizard/Pages/passcode-confirm.qml:45
853#: qml/Wizard/Pages/passcode-confirm.qml:45
740msgctxt "Enter the passcode again"
854msgctxt "Enter the passcode again"
741msgid "Please re-enter."
855msgid "Please re-enter."
742−msgstr "رجاء أعد الإدخال."
856+msgstr ""
743
857
744#: qml/Wizard/Pages/passcode-desktop.qml:31
858#: qml/Wizard/Pages/passcode-desktop.qml:31
745msgid "Lock Screen Passcode"
859msgid "Lock Screen Passcode"
746−msgstr "الرمز السري لقفل الشاشة"
860+msgstr ""
747
861
748−#: qml/Wizard/Pages/passcode-desktop.qml:68
862+#: qml/Wizard/Pages/passcode-desktop.qml:61
749msgid "Enter 4 numbers to setup your passcode"
863msgid "Enter 4 numbers to setup your passcode"
750−msgstr "أدخل 4 أرقام لإعداد الرمز السري"
864+msgstr ""
751
865
752−#: qml/Wizard/Pages/passcode-desktop.qml:84
866+#: qml/Wizard/Pages/passcode-desktop.qml:77
753#: qml/Wizard/Pages/passcode-set.qml:54
867#: qml/Wizard/Pages/passcode-set.qml:54
754msgid "Choose passcode"
868msgid "Choose passcode"
755−msgstr "اختر كلمة السر"
869+msgstr ""
756
870
757−#: qml/Wizard/Pages/passcode-desktop.qml:139
871+#: qml/Wizard/Pages/passcode-desktop.qml:127
758msgid "Passcode too short"
872msgid "Passcode too short"
759−msgstr "الرمز السري قصير جدا"
873+msgstr ""
760
874
761−#: qml/Wizard/Pages/passcode-desktop.qml:141
875+#: qml/Wizard/Pages/passcode-desktop.qml:129
762msgid "Passcodes match"
876msgid "Passcodes match"
763−msgstr "الرمزان السريان متطابقة"
877+msgstr ""
764
878
765−#: qml/Wizard/Pages/passcode-desktop.qml:143
879+#: qml/Wizard/Pages/passcode-desktop.qml:131
766msgid "Passcodes do not match"
880msgid "Passcodes do not match"
767−msgstr "الرمزان السريان لا يتطبقان"
881+msgstr ""
768
882
769#: qml/Wizard/Pages/passcode-set.qml:62
883#: qml/Wizard/Pages/passcode-set.qml:62
770msgid "Passcode must be 4 characters long"
884msgid "Passcode must be 4 characters long"
771−msgstr "يجب أن يكون الرمز السري 4 محارف"
885+msgstr ""
772
886
773#: qml/Wizard/Pages/password-set.qml:31
887#: qml/Wizard/Pages/password-set.qml:31
774msgid "Lock Screen Password"
888msgid "Lock Screen Password"
775−msgstr "كلمة سر قفل الشاشة"
889+msgstr ""
776
890
777−#: qml/Wizard/Pages/password-set.qml:68
891+#: qml/Wizard/Pages/password-set.qml:62
778msgid "Enter at least 8 characters"
892msgid "Enter at least 8 characters"
779−msgstr "أدخل 8 محارف على الأقل"
893+msgstr ""
780
894
781−#: qml/Wizard/Pages/password-set.qml:80
895+#: qml/Wizard/Pages/password-set.qml:74
782msgid "Choose password"
896msgid "Choose password"
783−msgstr "اختر كلمة السر"
897+msgstr ""
784
898
785−#: qml/Wizard/Pages/password-set.qml:110
899+#: qml/Wizard/Pages/password-set.qml:104
786msgid "Confirm password"
900msgid "Confirm password"
787−msgstr "أكد كلمة السر"
901+msgstr ""
788
902
789#: qml/Wizard/Pages/sim.qml:27
903#: qml/Wizard/Pages/sim.qml:27
790msgid "No SIM card installed"
904msgid "No SIM card installed"
791−msgstr "لم تدخل بطاقة SIM"
905+msgstr ""
792
906
793#: qml/Wizard/Pages/sim.qml:54
907#: qml/Wizard/Pages/sim.qml:54
794msgid "SIM card added"
908msgid "SIM card added"
795−msgstr "أُدخلت بطاقة SIM"
909+msgstr ""
796
910
797#: qml/Wizard/Pages/sim.qml:55
911#: qml/Wizard/Pages/sim.qml:55
798msgid "You must restart the device to access the mobile network."
912msgid "You must restart the device to access the mobile network."
799−msgstr "يجب عليك إعادة تشغيل الجهاز لتتمكن من دخول شبكة الجوال."
913+msgstr ""
800
914
801#: qml/Wizard/Pages/sim.qml:59
915#: qml/Wizard/Pages/sim.qml:59
802msgid "Restart"
916msgid "Restart"
803−msgstr "أعد التشغيل"
917+msgstr ""
804
918
805#: qml/Wizard/Pages/sim.qml:78
919#: qml/Wizard/Pages/sim.qml:78
806msgid "You won’t be able to make calls or use text messaging without a SIM."
920msgid "You won’t be able to make calls or use text messaging without a SIM."
807−msgstr "لن تتمكن من إجراء المكالمات أو إرسال الرسائل القصيرة بدون بطاقة SIM."
921+msgstr ""
808
922
809#: qml/Wizard/Pages/sim.qml:90
923#: qml/Wizard/Pages/sim.qml:90
810msgid "To proceed with no SIM tap Skip."
924msgid "To proceed with no SIM tap Skip."
811−msgstr "للاستمرار بدون بطاقة SIM اضغط تخطى."
925+msgstr ""
812
926
813#: qml/Wizard/PasswordMeter.qml:87
927#: qml/Wizard/PasswordMeter.qml:87
814msgid "Password too short"
928msgid "Password too short"
815−msgstr "كلمة السر قصيرة جداً"
929+msgstr ""
816
930
817#: qml/Wizard/PasswordMeter.qml:89
931#: qml/Wizard/PasswordMeter.qml:89
818msgid "Passwords match"
932msgid "Passwords match"
819−msgstr "كلمتا المرور متطابقتان"
933+msgstr ""
820
934
821#: qml/Wizard/PasswordMeter.qml:91
935#: qml/Wizard/PasswordMeter.qml:91
822msgid "Passwords do not match"
936msgid "Passwords do not match"
823−msgstr "كلمتا المرور غير متطابقتين"
937+msgstr ""
824
938
825#: qml/Wizard/PasswordMeter.qml:95
939#: qml/Wizard/PasswordMeter.qml:95
826msgid "Strong password"
940msgid "Strong password"
827−msgstr "كلمة سر قوية"
941+msgstr ""
828
942
829#: qml/Wizard/PasswordMeter.qml:97
943#: qml/Wizard/PasswordMeter.qml:97
830msgid "Fair password"
944msgid "Fair password"
831−msgstr "كلمة سر متوسطة"
945+msgstr ""
832
946
833#: qml/Wizard/PasswordMeter.qml:99
947#: qml/Wizard/PasswordMeter.qml:99
834msgid "Weak password"
948msgid "Weak password"
835−msgstr "كلمة سر ضعيفة"
949+msgstr ""
836
950
837#: qml/Wizard/PasswordMeter.qml:101
951#: qml/Wizard/PasswordMeter.qml:101
838msgid "Very weak password"
952msgid "Very weak password"
839−msgstr "كلمة السر ضعيفة جداً"
953+msgstr ""
840−
841−#~ msgid "Unity 8"
842−#~ msgstr "يونتي 8"
843−
844−#~ msgid "Super (Tap)"
845−#~ msgstr "Super (نقر)"
846−
847−#~ msgctxt "Button: Open the Ubuntu Store"
848−#~ msgid "Store"
849−#~ msgstr "المتجر"
850−
851−#~ msgctxt "Button: Start a search in the current dash scope"
852−#~ msgid "Search"
853−#~ msgstr "بحث"
854−
855−#~ msgctxt "Button: Show the current dash scope settings"
856−#~ msgid "Settings"
857−#~ msgstr "الإعدادات"
858−
859−#~ msgid "Remove from Favorites"
860−#~ msgstr "حذف من المفضلات"
861−
862−#~ msgid "Add to Favorites"
863−#~ msgstr "إضافة إلى المفضلات"
864−
865−#~ msgctxt "Label: Hint for dash search line edit"
866−#~ msgid "Search"
867−#~ msgstr "بحث"
868−
869−#~ msgid "More..."
870−#~ msgstr "المزيد..."
871−
872−#~ msgid "Less..."
873−#~ msgstr "أقل..."
874−
875−#~ msgid "Send"
876−#~ msgstr "أرسل"
877−
878−#~ msgid "Rate this"
879−#~ msgstr "قيّم ذلك"
880−
881−#~ msgid "Add a review"
882−#~ msgstr "أضف تعليق"
883−
884−#~ msgid "Enable location data"
885−#~ msgstr "تفعيل بيانات الموقع"
886−
887−#~ msgid "Manage"
888−#~ msgstr "إدارة"
889−
890−#~ msgid "Home"
891−#~ msgstr "الرئيسية"
892−
893−#~ msgid "Also installed"
894−#~ msgstr "أيضا تم تثبيت"
895−
896−#~ msgid "Privacy Policy"
897−#~ msgstr "سياسة الخصوصية"
898−
899−#~ msgid "Help Us Improve"
900−#~ msgstr "ساعدنا على التحسن"
901−
902−#~ msgid "Improve system performance by sending us crashes and error reports."
903−#~ msgstr "تحسين أداء النظام عير إرسال تقارير التوقف والأخطاء"
904−
905−#~ msgid "Privacy policy"
906−#~ msgstr "سياسة الخصوصية"
907−
908−#~ msgid "Update Apps"
909−#~ msgstr "تحديث التطبيقات"
910−
911−#~ msgid "This device is not connected to the internet."
912−#~ msgstr "الجهاز غير متصل باﻹنترنت"
913−
914−#, fuzzy
915−#~ msgid "Please wait..."
916−#~ msgstr "يجري التحميل. برجاء الانتظار..."
917−
918−#~ msgid "Update"
919−#~ msgstr "تحديث"
920−
921−#~ msgid "Download"
922−#~ msgstr "تنزيل"
923−
924−#~ msgid "Resume"
925−#~ msgstr "استئناف"
926−
927−#~ msgid "Pause"
928−#~ msgstr "إيقاف"
929−
930−#~ msgid "Install…"
931−#~ msgstr "تثبيت …"
932−
933−#~ msgid "Install"
934−#~ msgstr "تثبيت"
935−
936−#~ msgid "Open"
937−#~ msgstr "فتح"
938−
939−#~ msgid "Installing"
940−#~ msgstr "جاري التثبيت"
941−
942−#~ msgid "Paused"
943−#~ msgstr "تم اﻹيقاف"
944−
945−#~ msgid "Waiting to download"
946−#~ msgstr "انتظار التنزيل"
947−
948−#~ msgid "%1 of %2"
949−#~ msgstr "%1 من 2%"
950−
951−#, fuzzy
952−#~ msgid "Downloaded"
953−#~ msgstr "التنزيل"
954−
955−#, fuzzy
956−#~ msgid "Installed"
957−#~ msgstr "أيضا تم تثبيت"
958−
959−#~ msgid "Updated %1"
960−#~ msgstr "تحديث 1%"
961−
962−#~ msgid "Update failed"
963−#~ msgstr "فشل التحديث"
964−
965−#~ msgid "Terms & Conditions"
966−#~ msgstr "الشروط والأحكام"
967
954
968#~ msgid "Confirm"
955#~ msgid "Confirm"
969#~ msgstr "التأكيد"
956#~ msgstr "التأكيد"
@@ -971,9 +958,21 @@ msgstr "كلمة السر ضعيفة جداً"
971#~ msgid "Type or say a command"
958#~ msgid "Type or say a command"
972#~ msgstr "اكتب أو قُل أمرا"
959#~ msgstr "اكتب أو قُل أمرا"
973
960
961+#~ msgid "Loading. Please Wait..."
962+#~ msgstr "يجري التحميل. برجاء الانتظار..."
963+
974#~ msgid "Speak Now..."
964#~ msgid "Speak Now..."
975#~ msgstr "تكلم الآن..."
965#~ msgstr "تكلم الآن..."
976
966
967+#~ msgid "Speaking..."
968+#~ msgstr "تتكلم الآن..."
969+
970+#~ msgid "Search"
971+#~ msgstr "ابحث"
972+
973+#~ msgid "Try swiping from the top edge to access the indicators"
974+#~ msgstr "اسحب اصبعك من الحافة العلوية للوصول إلى المؤشرات"
975+
977#~ msgid "Top edge"
976#~ msgid "Top edge"
978#~ msgstr "الحافة العلوية"
977#~ msgstr "الحافة العلوية"
979
978
@@ -1009,8 +1008,8 @@ msgstr "كلمة السر ضعيفة جداً"
1009#~ "You have now mastered the edge gestures and can start using the "
1008#~ "You have now mastered the edge gestures and can start using the "
1010#~ "phone<br><br>Tap on the screen to start"
1009#~ "phone<br><br>Tap on the screen to start"
1011#~ msgstr ""
1010#~ msgstr ""
1012−#~ "أنت الآن بارع في إيماءات الحواف ويمكنك البدء باستخدام هاتفك<br><br>انقر "
1011+#~ "أنت الآن بارع في إيماءات الحواف ويمكنك البدء باستخدام هاتفك<br><br>انقر على "
1013−#~ "على الشاشة للبدء"
1012+#~ "الشاشة للبدء"
1014
1013
1015#~ msgid "%a %l:%M %p"
1014#~ msgid "%a %l:%M %p"
1016#~ msgstr "%a %l:%M %p"
1015#~ msgstr "%a %l:%M %p"
@@ -1063,18 +1062,26 @@ msgstr "كلمة السر ضعيفة جداً"
1063#~ msgid "Tap to unlock"
1062#~ msgid "Tap to unlock"
1064#~ msgstr "انقر لفك القفل"
1063#~ msgstr "انقر لفك القفل"
1065
1064
1065+#, qt-format
1066#~ msgid "Enter %1"
1066#~ msgid "Enter %1"
1067#~ msgstr "أدخِل %1"
1067#~ msgstr "أدخِل %1"
1068
1068
1069#~ msgid "Sorry, incorrect passcode."
1069#~ msgid "Sorry, incorrect passcode."
1070#~ msgstr "عذرًا، رمز سرّي خاطيء."
1070#~ msgstr "عذرًا، رمز سرّي خاطيء."
1071
1071
1072+#~ msgid "Enter passphrase"
1073+#~ msgstr "أدخِل العبارة السرية"
1074+
1075+#~ msgid "Enter passcode"
1076+#~ msgstr "أدخِل الرمز السرّي"
1077+
1072#~ msgid "Sorry, incorrect passphrase."
1078#~ msgid "Sorry, incorrect passphrase."
1073#~ msgstr "عذرًا، عبارة سرّية خاطئة."
1079#~ msgstr "عذرًا، عبارة سرّية خاطئة."
1074
1080
1075#~ msgid "This will be your last attempt."
1081#~ msgid "This will be your last attempt."
1076#~ msgstr "هذه ستكون المحاولة الأخيرة لك."
1082#~ msgstr "هذه ستكون المحاولة الأخيرة لك."
1077
1083
1084+#, qt-format
1078#~ msgid "Sorry, incorrect %1"
1085#~ msgid "Sorry, incorrect %1"
1079#~ msgstr "نأسف، %1 غير صحيحية"
1086#~ msgstr "نأسف، %1 غير صحيحية"
1080
1087
@@ -1145,6 +1152,9 @@ msgstr "كلمة السر ضعيفة جداً"
1145#~ msgid "Let’s get started."
1152#~ msgid "Let’s get started."
1146#~ msgstr "هيا بنا نبدأ."
1153#~ msgstr "هيا بنا نبدأ."
1147
1154
1155+#~ msgid "Continue"
1156+#~ msgstr "متابعة"
1157+
1148#~ msgid "Choose your passcode"
1158#~ msgid "Choose your passcode"
1149#~ msgstr "اختر الرمز السري خاصتك"
1159#~ msgstr "اختر الرمز السري خاصتك"
1150
1160
@@ -1241,15 +1251,15 @@ msgstr "كلمة السر ضعيفة جداً"
1241#~ msgstr "فتح قفل بطاقة SIM"
1251#~ msgstr "فتح قفل بطاقة SIM"
1242
1252
1243#~ msgid ""
1253#~ msgid ""
1244−#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms "
1254+#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
1245−#~ "and conditions</a>."
1255+#~ "conditions</a>."
1246#~ msgstr ""
1256#~ msgstr ""
1247−#~ "باختيارك لهذا الخيار فإنك توافق على <a href='#'>الشروط والأحكام</a> "
1257+#~ "باختيارك لهذا الخيار فإنك توافق على <a href='#'>الشروط والأحكام</a> الخاصة "
1248−#~ "الخاصة بـ Nokia HERE."
1258+#~ "بـ Nokia HERE."
1249
1259
1250#~ msgid ""
1260#~ msgid ""
1251−#~ "If passcode is entered incorrectly, your phone will conduct a factory "
1261+#~ "If passcode is entered incorrectly, your phone will conduct a factory reset "
1252−#~ "reset and all personal data will be deleted."
1262+#~ "and all personal data will be deleted."
1253#~ msgstr ""
1263#~ msgstr ""
1254#~ "إذا تم إدخال العبارة السرية بشكل خاطئ، فسوف يتم إعادة الهاتف لحالة ضبط "
1264#~ "إذا تم إدخال العبارة السرية بشكل خاطئ، فسوف يتم إعادة الهاتف لحالة ضبط "
1255#~ "المصنع وسيتم حذف كافة البيانات الشخصية."
1265#~ "المصنع وسيتم حذف كافة البيانات الشخصية."
po/ast.po+484−542
@@ -6,143 +6,108 @@
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9−"Report-Msgid-Bugs-To: \n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2021-01-29 11:42-0600\n"
10+"POT-Creation-Date: 2017-01-10 14:48+0000\n"
11−"PO-Revision-Date: 2019-10-30 03:35+0000\n"
11+"PO-Revision-Date: 2016-12-16 02:13+0000\n"
12"Last-Translator: enolp <enolp@softastur.org>\n"
12"Last-Translator: enolp <enolp@softastur.org>\n"
13−"Language-Team: Asturian <https://translate.ubports.com/projects/unity8/"
13+"Language-Team: Asturian <ast@li.org>\n"
14−"unity8/ast/>\n"
15−"Language: ast\n"
16"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
19"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Generator: Weblate 3.8\n"
21−"X-Launchpad-Export-Date: 2016-11-23 06:34+0000\n"
18+"X-Launchpad-Export-Date: 2017-01-16 05:47+0000\n"
19+"X-Generator: Launchpad (build 18302)\n"
22
20
23−#: plugins/LightDM/Greeter.cpp:199
21+#: plugins/LightDM/Greeter.cpp:123
24msgid "Password: "
22msgid "Password: "
25msgstr "Contraseña: "
23msgstr "Contraseña: "
26
24
27−#: plugins/LightDM/Greeter.cpp:214
28−msgid "Username"
29−msgstr ""
30−
31−#: plugins/LightDM/Greeter.cpp:258
32−msgid "Failed to authenticate"
33−msgstr ""
34−
35−#: plugins/LightDM/Greeter.cpp:260
36−msgid "Invalid password, please try again"
37−msgstr ""
38−
39−#: plugins/LightDM/Greeter.cpp:270
40−msgid "Log In"
41−msgstr ""
42−
43−#: plugins/LightDM/Greeter.cpp:270
44−msgid "Retry"
45−msgstr ""
46−
47−#: plugins/LightDM/UsersModel.cpp:157
48−msgid "Login"
49−msgstr ""
50−
51−#: plugins/LightDM/UsersModel.cpp:165
52−msgid "Guest Session"
53−msgstr ""
54−
55−#: plugins/Unity/Launcher/launcheritem.cpp:48
25+#: plugins/Unity/Launcher/launcheritem.cpp:50
56#: plugins/Unity/Launcher/launcheritem.cpp:122
26#: plugins/Unity/Launcher/launcheritem.cpp:122
57msgid "Pin shortcut"
27msgid "Pin shortcut"
58−msgstr "Fixar l'atayu"
28+msgstr "Anclar atayu"
59
29
60−#: plugins/Unity/Launcher/launcheritem.cpp:54
30+#: plugins/Unity/Launcher/launcheritem.cpp:55
61msgid "Quit"
31msgid "Quit"
62msgstr "Colar"
32msgstr "Colar"
63
33
64#: plugins/Unity/Launcher/launcheritem.cpp:122
34#: plugins/Unity/Launcher/launcheritem.cpp:122
65msgid "Unpin shortcut"
35msgid "Unpin shortcut"
66−msgstr "Quitar l'atayu"
36+msgstr "Desanclar atayu"
67
37
68−#: qml/Components/Dialogs.qml:176
38+#: qml/Components/Dialogs.qml:149
69msgctxt "Title: Lock/Log out dialog"
39msgctxt "Title: Lock/Log out dialog"
70msgid "Log out"
40msgid "Log out"
71−msgstr "Zarru de la sesión"
41+msgstr "Zarrar sesión"
72
42
73−#: qml/Components/Dialogs.qml:177
43+#: qml/Components/Dialogs.qml:150
74msgid "Are you sure you want to log out?"
44msgid "Are you sure you want to log out?"
75msgstr "¿De xuru que quies zarrar la sesión?"
45msgstr "¿De xuru que quies zarrar la sesión?"
76
46
77−#: qml/Components/Dialogs.qml:180
47+#: qml/Components/Dialogs.qml:152
78msgctxt "Button: Lock the system"
48msgctxt "Button: Lock the system"
79msgid "Lock"
49msgid "Lock"
80msgstr "Bloquiar"
50msgstr "Bloquiar"
81
51
82−#: qml/Components/Dialogs.qml:191
52+#: qml/Components/Dialogs.qml:160
83msgctxt "Button: Log out from the system"
53msgctxt "Button: Log out from the system"
84msgid "Log Out"
54msgid "Log Out"
85msgstr "Zarrar sesión"
55msgstr "Zarrar sesión"
86
56
87−#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
57+#: qml/Components/Dialogs.qml:167 qml/Components/Dialogs.qml:225
58+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:232
88−#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
59+#: qml/Wizard/Pages/passcode-confirm.qml:32
89#: qml/Wizard/Pages/passcode-set.qml:32
60#: qml/Wizard/Pages/passcode-set.qml:32
90msgid "Cancel"
61msgid "Cancel"
91msgstr "Encaboxar"
62msgstr "Encaboxar"
92
63
93−#: qml/Components/Dialogs.qml:211
64+#: qml/Components/Dialogs.qml:179
94msgctxt "Title: Reboot dialog"
65msgctxt "Title: Reboot dialog"
95msgid "Reboot"
66msgid "Reboot"
96msgstr "Reaniciu"
67msgstr "Reaniciu"
97
68
98−#: qml/Components/Dialogs.qml:212
69+#: qml/Components/Dialogs.qml:180
99msgid "Are you sure you want to reboot?"
70msgid "Are you sure you want to reboot?"
100msgstr "¿De xuru que quies reaniciar?"
71msgstr "¿De xuru que quies reaniciar?"
101
72
102−#: qml/Components/Dialogs.qml:215
73+#: qml/Components/Dialogs.qml:182
103msgid "No"
74msgid "No"
104msgstr "Non"
75msgstr "Non"
105
76
106−#: qml/Components/Dialogs.qml:223
77+#: qml/Components/Dialogs.qml:189
107msgid "Yes"
78msgid "Yes"
108msgstr "Sí"
79msgstr "Sí"
109
80
110−#: qml/Components/Dialogs.qml:243
81+#: qml/Components/Dialogs.qml:204
111msgctxt "Title: Power off/Restart dialog"
82msgctxt "Title: Power off/Restart dialog"
112msgid "Power"
83msgid "Power"
113−msgstr "Enerxía"
84+msgstr "Apagáu"
114
85
115−#: qml/Components/Dialogs.qml:244
86+#: qml/Components/Dialogs.qml:205
116msgid ""
87msgid ""
117"Are you sure you would like\n"
88"Are you sure you would like\n"
118"to power off?"
89"to power off?"
119msgstr ""
90msgstr ""
120−"¿De xuru que quies\n"
91+"¿De xuru que te prestaría\n"
121"apagar?"
92"apagar?"
122
93
123−#: qml/Components/Dialogs.qml:248
94+#: qml/Components/Dialogs.qml:208
124msgctxt "Button: Power off the system"
95msgctxt "Button: Power off the system"
125msgid "Power off"
96msgid "Power off"
126msgstr "Apagar"
97msgstr "Apagar"
127
98
128−#: qml/Components/Dialogs.qml:263
99+#: qml/Components/Dialogs.qml:217
129msgctxt "Button: Restart the system"
100msgctxt "Button: Restart the system"
130msgid "Restart"
101msgid "Restart"
131msgstr "Reaniciar"
102msgstr "Reaniciar"
132
103
133−#: qml/Components/Dialogs.qml:276
134−#, fuzzy
135−#| msgid "Takes a screenshot."
136−msgid "Screenshot"
137−msgstr "Fai una captura de pantalla."
138−
139#: qml/Components/KeyboardShortcutsOverlay.qml:41
104#: qml/Components/KeyboardShortcutsOverlay.qml:41
140msgid "Keyboard Shortcuts"
105msgid "Keyboard Shortcuts"
141−msgstr "Atayos del tecláu"
106+msgstr "Atayos de tecláu"
142
107
143#: qml/Components/KeyboardShortcutsOverlay.qml:55
108#: qml/Components/KeyboardShortcutsOverlay.qml:55
144−msgid "Lomiri"
109+msgid "Unity 8"
145−msgstr ""
110+msgstr "Unity 8"
146
111
147#: qml/Components/KeyboardShortcutsOverlay.qml:62
112#: qml/Components/KeyboardShortcutsOverlay.qml:62
148msgid "PrtScr"
113msgid "PrtScr"
@@ -150,177 +115,171 @@ msgstr "ImprPant"
150
115
151#: qml/Components/KeyboardShortcutsOverlay.qml:67
116#: qml/Components/KeyboardShortcutsOverlay.qml:67
152msgid "Takes a screenshot."
117msgid "Takes a screenshot."
153−msgstr "Fai una captura de pantalla."
118+msgstr "Saca una imaxe de la pantalla."
154
119
155#: qml/Components/KeyboardShortcutsOverlay.qml:75
120#: qml/Components/KeyboardShortcutsOverlay.qml:75
156msgid "Alt + PrtScr"
121msgid "Alt + PrtScr"
157msgstr "Alt + ImprPant"
122msgstr "Alt + ImprPant"
158
123
159#: qml/Components/KeyboardShortcutsOverlay.qml:80
124#: qml/Components/KeyboardShortcutsOverlay.qml:80
160−#, fuzzy
161−#| msgid "Takes a screenshot of a window."
125+msgid "Takes a screenshot of a window."
162−msgid "Takes a screenshot of the current window."
163−msgstr "Fai una captura d'una ventana."
126+msgstr "Saca una imaxe d'una ventana."
164
127
165#: qml/Components/KeyboardShortcutsOverlay.qml:88
128#: qml/Components/KeyboardShortcutsOverlay.qml:88
166msgid "Super + Space"
129msgid "Super + Space"
167−msgstr "Súper + Espaciu"
130+msgstr "Super + Espaciu"
168
131
169#: qml/Components/KeyboardShortcutsOverlay.qml:93
132#: qml/Components/KeyboardShortcutsOverlay.qml:93
170msgid "Switches to next keyboard layout."
133msgid "Switches to next keyboard layout."
171−msgstr "Cambia a la distribución siguiente del tecláu."
134+msgstr "Salta al siguiente diseñu de tecláu."
172
135
173#: qml/Components/KeyboardShortcutsOverlay.qml:101
136#: qml/Components/KeyboardShortcutsOverlay.qml:101
174msgid "Super + Shift + Space"
137msgid "Super + Shift + Space"
175−msgstr "Súper + Mayús + Espaciu"
138+msgstr "Super +Mayús + Espaciu"
176
139
177#: qml/Components/KeyboardShortcutsOverlay.qml:106
140#: qml/Components/KeyboardShortcutsOverlay.qml:106
178msgid "Switches to previous keyboard layout."
141msgid "Switches to previous keyboard layout."
179−msgstr "Cambia a la distribución anterior del tecláu."
142+msgstr "Salta al diseñu de tecláu anterior."
180
143
181−#: qml/Components/KeyboardShortcutsOverlay.qml:114
144+#: qml/Components/KeyboardShortcutsOverlay.qml:118
182−#, fuzzy
183−#| msgid "Ctrl + Super + D"
184−msgid "Ctrl + Alt + T"
185−msgstr "Ctrl + Súper + D"
186−
187−#: qml/Components/KeyboardShortcutsOverlay.qml:119
188−msgid "Starts the Terminal application."
189−msgstr ""
190−
191−#: qml/Components/KeyboardShortcutsOverlay.qml:131
192msgid "Launcher"
145msgid "Launcher"
193msgstr "Llanzador"
146msgstr "Llanzador"
194
147
195−#: qml/Components/KeyboardShortcutsOverlay.qml:138
148+#: qml/Components/KeyboardShortcutsOverlay.qml:125
196msgid "Super (Hold)"
149msgid "Super (Hold)"
197−msgstr ""
150+msgstr "Super (Caltener)"
198
151
199−#: qml/Components/KeyboardShortcutsOverlay.qml:143
152+#: qml/Components/KeyboardShortcutsOverlay.qml:130
200msgid "Opens the launcher, displays shortcuts."
153msgid "Opens the launcher, displays shortcuts."
201−msgstr "Abre'l llanzador, amuesa los atayos."
154+msgstr "Abre'l llanzador, amuesa atayos."
202
155
203−#: qml/Components/KeyboardShortcutsOverlay.qml:151
156+#: qml/Components/KeyboardShortcutsOverlay.qml:138
204msgid "Alt + F1"
157msgid "Alt + F1"
205msgstr "Alt + F1"
158msgstr "Alt + F1"
206
159
207−#: qml/Components/KeyboardShortcutsOverlay.qml:156
160+#: qml/Components/KeyboardShortcutsOverlay.qml:143
208msgid "Opens launcher keyboard navigation mode."
161msgid "Opens launcher keyboard navigation mode."
209−msgstr ""
162+msgstr "Abre'l mou de navegación con tecláu del llanzador."
210
163
211−#: qml/Components/KeyboardShortcutsOverlay.qml:164
164+#: qml/Components/KeyboardShortcutsOverlay.qml:151
212msgid "Super + Tab"
165msgid "Super + Tab"
213−msgstr "Súper + Tabulador"
166+msgstr "Super + Tab"
214
167
215−#: qml/Components/KeyboardShortcutsOverlay.qml:169
168+#: qml/Components/KeyboardShortcutsOverlay.qml:156
216msgid "Switches applications via the launcher."
169msgid "Switches applications via the launcher."
217−msgstr ""
170+msgstr "Cambia d'aplicaciones col llanzador."
218
171
219−#: qml/Components/KeyboardShortcutsOverlay.qml:177
172+#: qml/Components/KeyboardShortcutsOverlay.qml:164
220−#, fuzzy
221−#| msgid "Super + 0 to 9"
173+msgid "Super + 0 to 9"
222−msgid "Super + 1 to 0"
223−msgstr "Súper + 0 a 9"
174+msgstr "Super + 0 a 9"
224
175
225−#: qml/Components/KeyboardShortcutsOverlay.qml:182
176+#: qml/Components/KeyboardShortcutsOverlay.qml:169
226msgid "Same as clicking on a launcher icon."
177msgid "Same as clicking on a launcher icon."
227−msgstr "Igual que calcar nun iconu del llanzador."
178+msgstr "Igual que facer click nel iconu del llanzador."
228
179
229−#: qml/Components/KeyboardShortcutsOverlay.qml:190
180+#: qml/Components/KeyboardShortcutsOverlay.qml:177
230−#, fuzzy
231−#| msgid "Super + W"
232msgid "Super + A"
181msgid "Super + A"
233−msgstr "Súper + W"
182+msgstr ""
234
183
235−#: qml/Components/KeyboardShortcutsOverlay.qml:195
184+#: qml/Components/KeyboardShortcutsOverlay.qml:182
236−#, fuzzy
237−#| msgid "Open the launcher"
238msgid "Opens the Application Drawer."
185msgid "Opens the Application Drawer."
239−msgstr "Abrir el llanzador"
186+msgstr "Abre'l caxón d'aplicaciones."
187+
188+#: qml/Components/KeyboardShortcutsOverlay.qml:194
189+msgid "Scopes"
190+msgstr "Ámbitos"
191+
192+#: qml/Components/KeyboardShortcutsOverlay.qml:201
193+msgid "Super (Tap)"
194+msgstr "Super (Tocar)"
240
195
241−#: qml/Components/KeyboardShortcutsOverlay.qml:235
196+#: qml/Components/KeyboardShortcutsOverlay.qml:206
197+msgid "Opens the Scopes home."
198+msgstr "Abre'l principiu d'Ámbitos"
199+
200+#: qml/Components/KeyboardShortcutsOverlay.qml:222
242msgid "Switching"
201msgid "Switching"
243−msgstr "Cambéu"
202+msgstr "Conmutación"
244
203
245−#: qml/Components/KeyboardShortcutsOverlay.qml:242
204+#: qml/Components/KeyboardShortcutsOverlay.qml:229
246msgid "Alt + Tab"
205msgid "Alt + Tab"
247−msgstr "Alt + Tabulador"
206+msgstr "Alt + Tab"
248
207
249−#: qml/Components/KeyboardShortcutsOverlay.qml:247
208+#: qml/Components/KeyboardShortcutsOverlay.qml:234
250msgid "Switches between applications."
209msgid "Switches between applications."
251−msgstr ""
210+msgstr "Conmuta ente aplicaciones."
252
211
253−#: qml/Components/KeyboardShortcutsOverlay.qml:255
212+#: qml/Components/KeyboardShortcutsOverlay.qml:242
254msgid "Super + W"
213msgid "Super + W"
255−msgstr "Súper + W"
214+msgstr "Super + W"
256
215
257−#: qml/Components/KeyboardShortcutsOverlay.qml:260
216+#: qml/Components/KeyboardShortcutsOverlay.qml:247
258msgid "Opens the desktop spread."
217msgid "Opens the desktop spread."
259−msgstr ""
218+msgstr "Abre esparder l'escritoriu."
260
219
261−#: qml/Components/KeyboardShortcutsOverlay.qml:268
220+#: qml/Components/KeyboardShortcutsOverlay.qml:255
262msgid "Cursor Left or Right"
221msgid "Cursor Left or Right"
263−msgstr ""
222+msgstr "Flecha izq. o dre."
264
223
265−#: qml/Components/KeyboardShortcutsOverlay.qml:273
224+#: qml/Components/KeyboardShortcutsOverlay.qml:260
266msgid "Moves the focus."
225msgid "Moves the focus."
267−msgstr "Mueve'l focu."
226+msgstr "Mueve'l focu"
268
227
269−#: qml/Components/KeyboardShortcutsOverlay.qml:285
228+#: qml/Components/KeyboardShortcutsOverlay.qml:272
270msgid "Windows"
229msgid "Windows"
271−msgstr ""
230+msgstr "Ventanes"
272
231
273−#: qml/Components/KeyboardShortcutsOverlay.qml:292
232+#: qml/Components/KeyboardShortcutsOverlay.qml:279
274msgid "Ctrl + Super + D"
233msgid "Ctrl + Super + D"
275−msgstr "Ctrl + Súper + D"
234+msgstr "Ctrl + Super + D"
276
235
277−#: qml/Components/KeyboardShortcutsOverlay.qml:297
236+#: qml/Components/KeyboardShortcutsOverlay.qml:284
278msgid "Minimizes all windows."
237msgid "Minimizes all windows."
279−msgstr "Minimiza toles ventanes."
238+msgstr "Amenorga toles ventanes."
280
239
281−#: qml/Components/KeyboardShortcutsOverlay.qml:305
240+#: qml/Components/KeyboardShortcutsOverlay.qml:292
282msgid "Ctrl + Super + Up"
241msgid "Ctrl + Super + Up"
283−msgstr "Ctrl + Súper + Arriba"
242+msgstr "Ctrl + Super + Arriba"
284
243
285−#: qml/Components/KeyboardShortcutsOverlay.qml:310
244+#: qml/Components/KeyboardShortcutsOverlay.qml:297
286msgid "Maximizes the current window."
245msgid "Maximizes the current window."
287msgstr "Maximiza la ventana actual."
246msgstr "Maximiza la ventana actual."
288
247
289−#: qml/Components/KeyboardShortcutsOverlay.qml:318
248+#: qml/Components/KeyboardShortcutsOverlay.qml:305
290msgid "Ctrl + Super + Down"
249msgid "Ctrl + Super + Down"
291−msgstr "Ctrl + Súper + Abaxo"
250+msgstr "Ctrl + Super + Abaxo"
292
251
293−#: qml/Components/KeyboardShortcutsOverlay.qml:323
252+#: qml/Components/KeyboardShortcutsOverlay.qml:310
294msgid "Minimizes or restores the current window."
253msgid "Minimizes or restores the current window."
295−msgstr "Minimiza o restaura la ventana actual."
254+msgstr "Amenorga o restaura la ventana actual."
296
255
297−#: qml/Components/KeyboardShortcutsOverlay.qml:331
256+#: qml/Components/KeyboardShortcutsOverlay.qml:318
298msgid "Ctrl + Super + Left or Right"
257msgid "Ctrl + Super + Left or Right"
299−msgstr "Ctrl + Súper + Esquierda o Drecha"
258+msgstr "Ctrl + Super + Izquierda o Drecha"
300
259
301−#: qml/Components/KeyboardShortcutsOverlay.qml:336
260+#: qml/Components/KeyboardShortcutsOverlay.qml:323
302msgid "Semi-maximizes the current window."
261msgid "Semi-maximizes the current window."
303−msgstr ""
262+msgstr "Semi-maximiza la ventana actual."
304
263
305−#: qml/Components/KeyboardShortcutsOverlay.qml:344
264+#: qml/Components/KeyboardShortcutsOverlay.qml:331
306msgid "Alt + F4"
265msgid "Alt + F4"
307msgstr "Alt + F4"
266msgstr "Alt + F4"
308
267
309−#: qml/Components/KeyboardShortcutsOverlay.qml:349
268+#: qml/Components/KeyboardShortcutsOverlay.qml:336
310msgid "Closes the current window."
269msgid "Closes the current window."
311−msgstr "Zarra toles ventanes actuales."
270+msgstr "Zarra la ventana actual."
312
271
313−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:235
272+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:252
314msgid "Return to Call"
273msgid "Return to Call"
315−msgstr ""
274+msgstr "Tornar a la llamada"
316
275
317#: qml/Components/Lockscreen.qml:212
276#: qml/Components/Lockscreen.qml:212
318msgid "Emergency Call"
277msgid "Emergency Call"
319msgstr "Llamada d'emerxencia"
278msgstr "Llamada d'emerxencia"
320
279
321−#: qml/Components/Lockscreen.qml:245
280+#: qml/Components/Lockscreen.qml:244
322msgid "OK"
281msgid "OK"
323−msgstr ""
282+msgstr "Aceutar"
324
283
325#: qml/Components/MediaServices/VideoPlayerControls.qml:44
284#: qml/Components/MediaServices/VideoPlayerControls.qml:44
326#, qt-format
285#, qt-format
@@ -332,61 +291,156 @@ msgstr "%1:%2:%3"
332msgid "%1:%2"
291msgid "%1:%2"
333msgstr "%1:%2"
292msgstr "%1:%2"
334
293
335−#: qml/Components/ModeSwitchWarningDialog.qml:33
294+#: qml/Components/ModeSwitchWarningDialog.qml:32
336msgid "Apps may have unsaved data:"
295msgid "Apps may have unsaved data:"
337−msgstr "Aplicaciones con datos ensin guardar:"
296+msgstr "Apps que pueden tener datos sin guardar:"
338
297
339−#: qml/Components/ModeSwitchWarningDialog.qml:60
298+#: qml/Components/ModeSwitchWarningDialog.qml:57
340msgctxt ""
299msgctxt ""
341"Re-dock means connect the device again to an external screen/mouse/keyboard"
300"Re-dock means connect the device again to an external screen/mouse/keyboard"
342msgid "Re-dock, save your work and close these apps to continue."
301msgid "Re-dock, save your work and close these apps to continue."
343−msgstr ""
302+msgstr "Reconeuta, guarda'l trabayu y zarra eses apps pa siguir."
344
303
345−#: qml/Components/ModeSwitchWarningDialog.qml:67
304+#: qml/Components/ModeSwitchWarningDialog.qml:63
346msgid "Or force close now (unsaved data will be lost)."
305msgid "Or force close now (unsaved data will be lost)."
347−msgstr ""
306+msgstr "O fuerza salir agora (perderás tolos datos sin guardar)."
348
307
349−#: qml/Components/ModeSwitchWarningDialog.qml:80
308+#: qml/Components/ModeSwitchWarningDialog.qml:75
350msgid "OK, I will reconnect"
309msgid "OK, I will reconnect"
351−msgstr ""
310+msgstr "D'alcuerdu, reconeutaré"
352
311
353−#: qml/Components/ModeSwitchWarningDialog.qml:81
312+#: qml/Components/ModeSwitchWarningDialog.qml:76
354msgid "Reconnect now!"
313msgid "Reconnect now!"
355−msgstr ""
314+msgstr "Reconeutar agora."
356
315
357−#: qml/Components/ModeSwitchWarningDialog.qml:94
316+#: qml/Components/ModeSwitchWarningDialog.qml:88
358msgid "Close all"
317msgid "Close all"
359msgstr "Zarrar too"
318msgstr "Zarrar too"
360
319
361#: qml/Components/SharingPicker.qml:54
320#: qml/Components/SharingPicker.qml:54
362msgid "Preview Share Item"
321msgid "Preview Share Item"
363−msgstr ""
322+msgstr "Entever l'elementu compartíu"
364
323
365#: qml/Components/VirtualTouchPad.qml:317
324#: qml/Components/VirtualTouchPad.qml:317
366msgid ""
325msgid ""
367"Your device is now connected to an external display. Use this screen as a "
326"Your device is now connected to an external display. Use this screen as a "
368"touch pad to interact with the pointer."
327"touch pad to interact with the pointer."
369msgstr ""
328msgstr ""
370−"Agora'l preséu ta coneutáu a una pantalla esterna. Usa esta pantalla como "
329+"El preséu agora ta coneutáu con una pantalla esterna. Usa esta pantalla como "
371−"panel táutil pa interactuar col punteru."
330+"touch pad pa interactuar col punteru."
372
331
373#: qml/Components/VirtualTouchPad.qml:327
332#: qml/Components/VirtualTouchPad.qml:327
374−#, fuzzy
375−#| msgid "Tap to return to call..."
376msgid "Tap left button to click."
333msgid "Tap left button to click."
377−msgstr "Toca pa volver a la llamada…"
334+msgstr "Calca nel botón esquierdu pa facer clic."
378
335
379#: qml/Components/VirtualTouchPad.qml:339
336#: qml/Components/VirtualTouchPad.qml:339
380msgid "Tap right button to right click."
337msgid "Tap right button to right click."
381−msgstr ""
338+msgstr "Calca nel botón drechu pa facer clic."
382
339
383#: qml/Components/VirtualTouchPad.qml:351
340#: qml/Components/VirtualTouchPad.qml:351
384msgid "Swipe with two fingers to scroll."
341msgid "Swipe with two fingers to scroll."
385−msgstr ""
342+msgstr "Esliza con dos deos pa desplazate."
386
343
387#: qml/Components/VirtualTouchPad.qml:396
344#: qml/Components/VirtualTouchPad.qml:396
388msgid "Find more settings in the system settings."
345msgid "Find more settings in the system settings."
389−msgstr ""
346+msgstr "Alcuentra más axustes nos Axustes del Sistema."
347+
348+#: qml/Dash/DashPageHeader.qml:361
349+msgctxt "Button: Open the Ubuntu Store"
350+msgid "Store"
351+msgstr "Tienda"
352+
353+#: qml/Dash/DashPageHeader.qml:368
354+msgctxt "Button: Start a search in the current dash scope"
355+msgid "Search"
356+msgstr "Guetar"
357+
358+#: qml/Dash/DashPageHeader.qml:378
359+msgctxt "Button: Show the current dash scope settings"
360+msgid "Settings"
361+msgstr "Axustes"
362+
363+#: qml/Dash/DashPageHeader.qml:385
364+msgid "Remove from Favorites"
365+msgstr "Desaniciar de favoritos"
366+
367+#: qml/Dash/DashPageHeader.qml:385
368+msgid "Add to Favorites"
369+msgstr "Amestar a favoritos"
370+
371+#: qml/Dash/FiltersPopover.qml:61
372+msgid "Refine your results"
373+msgstr "Refina los resultaos"
374+
375+#: qml/Dash/FiltersPopover.qml:70
376+msgid "Reset"
377+msgstr "Reafitar"
378+
379+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
380+msgid "Show less"
381+msgstr "Ver menos"
382+
383+#: qml/Dash/GenericScopeView.qml:547
384+msgid "Show all"
385+msgstr "Ver too"
386+
387+#: qml/Dash/GenericScopeView.qml:578
388+msgctxt "Label: Hint for dash search line edit"
389+msgid "Search"
390+msgstr "Guetar"
391+
392+#: qml/Dash/PageHeaderExtraPanel.qml:67
393+msgid "Recent Searches"
394+msgstr "Guetes recién"
395+
396+#: qml/Dash/PageHeaderExtraPanel.qml:78
397+msgid "Clear All"
398+msgstr "Llimpiar too"
399+
400+#: qml/Dash/Previews/PreviewActionCombo.qml:36
401+msgid "More..."
402+msgstr "Más…"
403+
404+#: qml/Dash/Previews/PreviewActionCombo.qml:36
405+msgid "Less..."
406+msgstr "Menos…"
407+
408+#: qml/Dash/Previews/PreviewCommentInput.qml:83
409+#: qml/Dash/Previews/PreviewRatingInput.qml:202
410+msgid "Send"
411+msgstr "Unviar"
412+
413+#: qml/Dash/Previews/PreviewRatingInput.qml:109
414+msgid "Rate this"
415+msgstr "Valorar esto"
416+
417+#: qml/Dash/Previews/PreviewRatingInput.qml:184
418+msgid "Add a review"
419+msgstr "Amestar una reseña"
420+
421+#: qml/Dash/PullToRefreshScopeStyle.qml:56
422+msgid "Pull to refresh…"
423+msgstr "Tira p'anovar..."
424+
425+#: qml/Dash/PullToRefreshScopeStyle.qml:61
426+msgid "Release to refresh…"
427+msgstr "Sueltar p'anovar..."
428+
429+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
430+msgid "Enable location data"
431+msgstr "Habilitar datos d'allugamientu"
432+
433+#: qml/Dash/ScopesList.qml:146
434+msgid "Manage"
435+msgstr "Xestionar"
436+
437+#: qml/Dash/ScopesList.qml:187
438+msgid "Home"
439+msgstr "Aniciu"
440+
441+#: qml/Dash/ScopesList.qml:188
442+msgid "Also installed"
443+msgstr "Tamién instalaos"
390
444
391#: qml/Greeter/CoverPage.qml:127
445#: qml/Greeter/CoverPage.qml:127
392msgid "Unlock"
446msgid "Unlock"
@@ -398,75 +452,68 @@ msgstr "Preséu bloquiáu"
398
452
399#: qml/Greeter/DelayedLockscreen.qml:58
453#: qml/Greeter/DelayedLockscreen.qml:58
400msgid "You have been locked out due to too many failed passphrase attempts."
454msgid "You have been locked out due to too many failed passphrase attempts."
401−msgstr ""
455+msgstr "Quedasti bloquiáu polos escesivos intentos fallíos de fras de pasu."
402−"Bloquióse'l preséu dempués d'introducir mal el códigu numbéricu milenta "
403−"vegaes."
404
456
405#: qml/Greeter/DelayedLockscreen.qml:59
457#: qml/Greeter/DelayedLockscreen.qml:59
406msgid "You have been locked out due to too many failed passcode attempts."
458msgid "You have been locked out due to too many failed passcode attempts."
407msgstr ""
459msgstr ""
408−"Bloquióse'l preséu dempués d'introducir mal la contraseña milenta vegaes."
460+"Quedasti bloquiáu polos escesivos intentos fallíos de códigu de pasu."
409
461
410#: qml/Greeter/DelayedLockscreen.qml:68
462#: qml/Greeter/DelayedLockscreen.qml:68
411#, qt-format
463#, qt-format
412msgid "Please wait %1 minute and then try again…"
464msgid "Please wait %1 minute and then try again…"
413msgid_plural "Please wait %1 minutes and then try again…"
465msgid_plural "Please wait %1 minutes and then try again…"
414−msgstr[0] "Espera %1 minutu y volvi tentalo darréu…"
466+msgstr[0] "Por favor, espera %1 minutu y vuelvi a intentalo…"
415−msgstr[1] "Espera %1 minutos y volvi tentalo darréu…"
467+msgstr[1] "Por favor, espera %1 minutos y vuelvi a intentalo…"
416
468
417−#: qml/Greeter/Greeter.qml:550
469+#: qml/Greeter/Greeter.qml:592
418msgid "Try again"
470msgid "Try again"
419−msgstr ""
471+msgstr "Tentar otra vuelta"
420−
421−#: qml/Greeter/Greeter.qml:551
422−#, fuzzy
423−#| msgid "Enter passphrase"
424−msgid "Enter passphrase to unlock"
425−msgstr "Introduz la fras de pasu"
426−
427−#: qml/Greeter/Greeter.qml:552
428−#, fuzzy
429−#| msgid "Enter passcode"
430−msgid "Enter passcode to unlock"
431−msgstr "Introduz el códigu de pasu"
432
472
433−#: qml/Greeter/NarrowView.qml:235
473+#: qml/Greeter/LoginList.qml:70
434−msgid "Emergency"
435−msgstr "Emerxencia"
436−
437−#: qml/Greeter/PromptList.qml:126
438msgid "Passphrase"
474msgid "Passphrase"
439msgstr "Fras de pasu"
475msgstr "Fras de pasu"
440
476
441−#: qml/Greeter/PromptList.qml:126
477+#: qml/Greeter/LoginList.qml:71
442msgid "Passcode"
478msgid "Passcode"
443−msgstr "Códigu numbéricu"
479+msgstr "Códigu de pasu"
480+
481+#: qml/Greeter/LoginList.qml:98
482+msgid "Retry"
483+msgstr "Reintentar"
484+
485+#: qml/Greeter/LoginList.qml:99
486+msgid "Log In"
487+msgstr "Aniciar sesión"
488+
489+#: qml/Greeter/NarrowView.qml:252
490+msgid "Emergency"
491+msgstr "Emerxencia"
444
492
445−#: qml/Greeter/SessionsList.qml:124
493+#: qml/Greeter/SessionsList.qml:122
446msgid "Select desktop environment"
494msgid "Select desktop environment"
447−msgstr ""
495+msgstr "Esbillar entornu d'escritoriu"
448
496
449−#: qml/Launcher/Drawer.qml:250
497+#: qml/Launcher/Drawer.qml:80
450−#, fuzzy
451−#| msgid "Search"
452msgid "Search…"
498msgid "Search…"
453−msgstr "Guetar"
499+msgstr "Guetar..."
454
500
455−#: qml/Launcher/PullToRefreshScopeStyle.qml:56
501+#: qml/Launcher/Drawer.qml:101
502+msgctxt "Apps sorted alphabetically"
456−msgid "Pull to refresh…"
503+msgid "A-Z"
457−msgstr "Tira pa refrescar…"
504+msgstr "A-Z"
458
505
459−#: qml/Launcher/PullToRefreshScopeStyle.qml:61
506+#: qml/Launcher/MoreAppsHeader.qml:32
460−msgid "Release to refresh…"
507+msgid "More apps in the store"
461−msgstr "Suelta pa refrescar…"
508+msgstr "Más aplicaciones na tienda"
462
509
463#: qml/Notifications/NotificationMenuItemFactory.qml:124
510#: qml/Notifications/NotificationMenuItemFactory.qml:124
464msgid "Show password"
511msgid "Show password"
465−msgstr "Amosar la contraseña"
512+msgstr "Amosar contraseña"
466
513
467#: qml/Panel/ActiveCallHint.qml:79
514#: qml/Panel/ActiveCallHint.qml:79
468msgid "Tap to return to call..."
515msgid "Tap to return to call..."
469−msgstr "Toca pa volver a la llamada…"
516+msgstr "Toca pa tornar a la llamada..."
470
517
471#: qml/Panel/ActiveCallHint.qml:92
518#: qml/Panel/ActiveCallHint.qml:92
472msgid "Conference"
519msgid "Conference"
@@ -474,7 +521,7 @@ msgstr "Conferencia"
474
521
475#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:869
522#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:869
476msgid "Nothing is playing"
523msgid "Nothing is playing"
477−msgstr "Nada en reproducción"
524+msgstr "Nun ta reproduciéndose nada"
478
525
479#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:997
526#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:997
480#, qt-format
527#, qt-format
@@ -505,11 +552,11 @@ msgstr "0 segundos"
505#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1011
552#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1011
506#, qt-format
553#, qt-format
507msgid "%1 remaining"
554msgid "%1 remaining"
508−msgstr "%1 restante(s)"
555+msgstr "Queden %1"
509
556
510#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1017
557#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1017
511msgid "In queue…"
558msgid "In queue…"
512−msgstr "Na cola…"
559+msgstr "Na cola..."
513
560
514#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1021
561#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1021
515msgid "Downloading"
562msgid "Downloading"
@@ -517,11 +564,11 @@ msgstr "Baxando"
517
564
518#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1023
565#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1023
519msgid "Paused, tap to resume"
566msgid "Paused, tap to resume"
520−msgstr "Posóse, toca pa siguir"
567+msgstr "Posáu, toca pa reanudar"
521
568
522#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1025
569#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1025
523msgid "Canceled"
570msgid "Canceled"
524−msgstr "Encaboxóse"
571+msgstr "Encaboxáu"
525
572
526#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
573#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1027
527msgid "Finished"
574msgid "Finished"
@@ -529,7 +576,7 @@ msgstr "Finó"
529
576
530#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
577#: qml/Panel/Indicators/IndicatorMenuItemFactory.qml:1029
531msgid "Failed, tap to retry"
578msgid "Failed, tap to retry"
532−msgstr "Falló, toca pa retentar"
579+msgstr "Falló, toca pa reintentar"
533
580
534#: qml/Panel/Indicators/MessageMenuItemFactory.qml:151
581#: qml/Panel/Indicators/MessageMenuItemFactory.qml:151
535#: qml/Panel/Indicators/MessageMenuItemFactory.qml:210
582#: qml/Panel/Indicators/MessageMenuItemFactory.qml:210
@@ -540,88 +587,61 @@ msgstr "Unviar"
540#: qml/Panel/Indicators/MessageMenuItemFactory.qml:152
587#: qml/Panel/Indicators/MessageMenuItemFactory.qml:152
541msgctxt "Label: Hint in message indicator line edit"
588msgctxt "Label: Hint in message indicator line edit"
542msgid "Reply"
589msgid "Reply"
543−msgstr ""
590+msgstr "Responder"
544
591
545#: qml/Panel/Indicators/MessageMenuItemFactory.qml:209
592#: qml/Panel/Indicators/MessageMenuItemFactory.qml:209
546msgctxt "Button: Call back on phone"
593msgctxt "Button: Call back on phone"
547msgid "Call back"
594msgid "Call back"
548−msgstr "Rellamar"
595+msgstr "Devolver llamada"
549−
550−#: qml/Panel/PanelMenuPage.qml:92
551−#, fuzzy
552−#| msgctxt "Button: Go back one page in the Wizard"
553−#| msgid "Back"
554−msgid "Back"
555−msgstr "Atrás"
556
596
557#: qml/Stage/SideStage.qml:76
597#: qml/Stage/SideStage.qml:76
558msgid "Drag using 3 fingers any application from one window to the other"
598msgid "Drag using 3 fingers any application from one window to the other"
559−msgstr "Arrastra con tres deos cualquier aplicación dende una ventana a otra"
599+msgstr "Abasnar cualquier aplicación d'una ventana a otra usando 3 deos"
560−
561−#: qml/Stage/Stage.qml:671
562−msgid "No running apps"
563−msgstr ""
564
600
565#: qml/Tutorial/TutorialLeftLong.qml:49
601#: qml/Tutorial/TutorialLeftLong.qml:49
566−#, fuzzy
567−#| msgid "Long swipe from the left edge to open the Today scope"
602+msgid "Long swipe from the left edge to open the Today scope"
568−msgid "Long swipe from the left edge to open the Application Drawer"
569−msgstr "Eslizamientu llargu dende'l berbesu esquierdu p'abrir l'ámbitu Güei"
603+msgstr "Eslizamientu llargu dende'l berbesu izquierdu pa ver el scope Güei"
570
604
571#: qml/Tutorial/TutorialLeft.qml:47
605#: qml/Tutorial/TutorialLeft.qml:47
572msgid "Short swipe from the left edge to open the launcher"
606msgid "Short swipe from the left edge to open the launcher"
573−msgstr "Esliza dende'l berbesu esquierdu p'abrir el llanzador"
607+msgstr "Barríu curtiu dende'l berbesu izquierdu p'abrir el llanzador"
574
608
575−#: qml/Tutorial/TutorialRight.qml:54
609+#: qml/Tutorial/TutorialRight.qml:55
576msgid "Push your mouse against the right edge to view your open apps"
610msgid "Push your mouse against the right edge to view your open apps"
577−msgstr "Lleva'l mur al berbesu drechu pa ver les aplicaciones abiertes"
611+msgstr "Emburria'l mur escontra'l berbesu drechu pa ver les apps abiertes"
578
612
579−#: qml/Tutorial/TutorialRight.qml:55
613+#: qml/Tutorial/TutorialRight.qml:56
580msgid "Swipe from the right edge to view your open apps"
614msgid "Swipe from the right edge to view your open apps"
581−msgstr "Esliza dende'l berbesu drechu pa ver les aplicaciones abiertes"
615+msgstr "Barríu dende'l berbesu drechu pa ver les apps abiertes"
582
616
583#: qml/Tutorial/TutorialTop.qml:53
617#: qml/Tutorial/TutorialTop.qml:53
584msgid "Swipe from the top edge to access notifications and quick settings"
618msgid "Swipe from the top edge to access notifications and quick settings"
585−msgstr "Esliza dende'l berbesu cimeru p'acceder a los avisos y axustes rápidos"
619+msgstr ""
620+"Barríu dende'l berbesu superior pa tener accesu a los avisos y configuración "
621+"nel intre"
586
622
587−#: qml/Wizard/Page.qml:59
623+#: qml/Wizard/Page.qml:54
588msgctxt "Button: Go back one page in the Wizard"
624msgctxt "Button: Go back one page in the Wizard"
589msgid "Back"
625msgid "Back"
590−msgstr "Atrás"
626+msgstr "Atrás"
591
627
592−#: qml/Wizard/Pages/10-welcome.qml:29
628+#: qml/Wizard/Pages/10-welcome.qml:28
593msgid "Language"
629msgid "Language"
594msgstr "Llingua"
630msgstr "Llingua"
595
631
596−#: qml/Wizard/Pages/10-welcome.qml:176
632+#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
597−#: qml/Wizard/Pages/10-welcome-update.qml:126
633+#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
598−#: qml/Wizard/Pages/11-changelog.qml:74 qml/Wizard/Pages/20-keyboard.qml:152
599−#: qml/Wizard/Pages/30-wifi.qml:214 qml/Wizard/Pages/50-timezone.qml:272
634+#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
600−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/70-passwd-type.qml:146
635+#: qml/Wizard/Pages/70-passwd-type.qml:145
636+#: qml/Wizard/Pages/75-report-check.qml:84
601−#: qml/Wizard/Pages/passcode-desktop.qml:154
637+#: qml/Wizard/Pages/passcode-desktop.qml:142
602−#: qml/Wizard/Pages/password-set.qml:153
638+#: qml/Wizard/Pages/password-set.qml:142
603msgid "Next"
639msgid "Next"
604msgstr "Siguiente"
640msgstr "Siguiente"
605
641
606−#: qml/Wizard/Pages/10-welcome-update.qml:91
607−msgid "Welcome to "
608−msgstr ""
609−
610−#: qml/Wizard/Pages/10-welcome-update.qml:106
611−msgid "We will make sure your device is ready to use "
612−msgstr "Vamos aseguranos de que'l preséu ta preparáu pa usase "
613−
614−#: qml/Wizard/Pages/11-changelog.qml:28
615−msgid "What's new"
616−msgstr "Qué hai nuevo"
617−
618−#: qml/Wizard/Pages/11-changelog.qml:74
619−msgid "Loading..."
620−msgstr "Cargando…"
621−
622#: qml/Wizard/Pages/20-keyboard.qml:31
642#: qml/Wizard/Pages/20-keyboard.qml:31
623msgid "Select Keyboard"
643msgid "Select Keyboard"
624−msgstr ""
644+msgstr "Escoyer tecláu"
625
645
626#: qml/Wizard/Pages/20-keyboard.qml:71
646#: qml/Wizard/Pages/20-keyboard.qml:71
627msgid "Keyboard language"
647msgid "Keyboard language"
@@ -631,203 +651,279 @@ msgstr "Llingua del tecláu"
631msgid "Keyboard layout"
651msgid "Keyboard layout"
632msgstr "Distribución del tecláu"
652msgstr "Distribución del tecláu"
633
653
634−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
654+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
635−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
655+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
636#: qml/Wizard/Pages/sim.qml:101
656#: qml/Wizard/Pages/sim.qml:101
637msgid "Skip"
657msgid "Skip"
638msgstr "Saltar"
658msgstr "Saltar"
639
659
640#: qml/Wizard/Pages/30-wifi.qml:31
660#: qml/Wizard/Pages/30-wifi.qml:31
641msgid "Connect to Wi‑Fi"
661msgid "Connect to Wi‑Fi"
642−msgstr "Conexón a una Wi-Fi"
662+msgstr "Coneutase al WiFi"
643
663
644−#: qml/Wizard/Pages/30-wifi.qml:139
664+#: qml/Wizard/Pages/30-wifi.qml:132
645msgid "Connected"
665msgid "Connected"
646−msgstr "Coneutóse"
666+msgstr "Coneutáu"
647
667
648−#: qml/Wizard/Pages/30-wifi.qml:172
668+#: qml/Wizard/Pages/30-wifi.qml:165
649msgid "Available Wi-Fi networks"
669msgid "Available Wi-Fi networks"
650msgstr "Redes Wi-Fi disponibles"
670msgstr "Redes Wi-Fi disponibles"
651
671
652−#: qml/Wizard/Pages/30-wifi.qml:173
672+#: qml/Wizard/Pages/30-wifi.qml:166
653msgid "No available Wi-Fi networks"
673msgid "No available Wi-Fi networks"
654msgstr "Nun hai redes Wi-Fi disponibles"
674msgstr "Nun hai redes Wi-Fi disponibles"
655
675
676+#: qml/Wizard/Pages/40-location.qml:27
677+msgid "Location Services"
678+msgstr "Servicios d'allugamientu"
679+
680+#: qml/Wizard/Pages/40-location.qml:83
681+msgid ""
682+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
683+"(recommended)"
684+msgstr ""
685+"Usar GPS, puntos Wi-Fi y redes móviles de mou anónimu pa detectar "
686+"l'allugamientu (recomendao)"
687+
688+#: qml/Wizard/Pages/40-location.qml:105
689+#, qt-format
690+msgid "By selecting this option you agree to the Nokia HERE %1."
691+msgstr "Seleicionando esta opción aceutes los %1 de Nokia HERE."
692+
693+#: qml/Wizard/Pages/40-location.qml:106
694+msgctxt "part of: Nokia HERE terms and conditions"
695+msgid "terms and conditions"
696+msgstr "términos y condiciones"
697+
698+#: qml/Wizard/Pages/40-location.qml:160
699+msgid "GPS only"
700+msgstr "Sólo GPS"
701+
702+#: qml/Wizard/Pages/40-location.qml:214
703+msgid "Don't use my location"
704+msgstr "Nun usar l'allugamientu"
705+
706+#: qml/Wizard/Pages/40-location.qml:260
707+msgid "You can change it later in System Settings."
708+msgstr "Pues camudalo sero na Configuración del Sistema."
709+
656#: qml/Wizard/Pages/50-timezone.qml:30
710#: qml/Wizard/Pages/50-timezone.qml:30
657msgid "Time Zone"
711msgid "Time Zone"
658−msgstr "Fusu horariu"
712+msgstr "Estaya horaria"
659
713
660−#: qml/Wizard/Pages/50-timezone.qml:183
714+#: qml/Wizard/Pages/50-timezone.qml:182
661msgid "Enter your city"
715msgid "Enter your city"
662−msgstr "Introduz la to ciudá"
716+msgstr "Escribe la ciudá"
663
717
664#: qml/Wizard/Pages/60-account.qml:24
718#: qml/Wizard/Pages/60-account.qml:24
665msgid "Personalize Your Device"
719msgid "Personalize Your Device"
666−msgstr "Personalización del preséu"
720+msgstr "Personaliza'l preséu"
667
721
668−#: qml/Wizard/Pages/60-account.qml:54
722+#: qml/Wizard/Pages/60-account.qml:48
669msgid "Preferred Name"
723msgid "Preferred Name"
670msgstr "Nome preferíu"
724msgstr "Nome preferíu"
671
725
672#: qml/Wizard/Pages/70-passwd-type.qml:40
726#: qml/Wizard/Pages/70-passwd-type.qml:40
673msgid "Lock Screen"
727msgid "Lock Screen"
674−msgstr "Pantalla de bloquéu"
728+msgstr "Bloquiar pantalla"
675
729
676−#: qml/Wizard/Pages/70-passwd-type.qml:103
730+#: qml/Wizard/Pages/70-passwd-type.qml:102
677msgctxt "Label: Type of security method"
731msgctxt "Label: Type of security method"
678msgid "Create new password"
732msgid "Create new password"
679−msgstr "Crear una contraseña"
733+msgstr "Crear contraseña nueva"
680
734
681−#: qml/Wizard/Pages/70-passwd-type.qml:105
735+#: qml/Wizard/Pages/70-passwd-type.qml:104
682msgctxt "Label: Type of security method"
736msgctxt "Label: Type of security method"
683msgid "Create passcode (numbers only)"
737msgid "Create passcode (numbers only)"
684−msgstr "Crear un códigu numbéricu"
738+msgstr "Crear códigu d'accesu (sólo númberos)"
685
739
686−#: qml/Wizard/Pages/70-passwd-type.qml:107
740+#: qml/Wizard/Pages/70-passwd-type.qml:106
687msgctxt "Label: Type of security method"
741msgctxt "Label: Type of security method"
688msgid "No lock code"
742msgid "No lock code"
689−msgstr "Nada"
743+msgstr "Ensin códigu de bloquéu"
690
744
691−#: qml/Wizard/Pages/79-system-update.qml:28
745+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
692−msgid "Update Device"
746+msgid "Privacy Policy"
747+msgstr "Política d'intimidá"
748+
749+#: qml/Wizard/Pages/75-report-check.qml:26
750+msgid "Help Us Improve"
751+msgstr "Ayúdanos a meyorar"
752+
753+#: qml/Wizard/Pages/75-report-check.qml:59
754+msgid "Improve system performance by sending us crashes and error reports."
693msgstr ""
755msgstr ""
756+"Ameyora'l rindimientu del sistema unviándonos los informes d'errores y "
757+"cuelgues."
694
758
759+#: qml/Wizard/Pages/75-report-check.qml:60
760+msgid "Privacy policy"
761+msgstr "Política d'intimidá"
762+
763+#: qml/Wizard/Pages/77-system-update.qml:28
764+msgid "Update Device"
765+msgstr "Anovar preséu"
766+
695−#: qml/Wizard/Pages/79-system-update.qml:55
767+#: qml/Wizard/Pages/77-system-update.qml:55
696msgid ""
768msgid ""
697"There is a system update available and ready to install. Afterwards, the "
769"There is a system update available and ready to install. Afterwards, the "
698"device will automatically restart."
770"device will automatically restart."
699msgstr ""
771msgstr ""
700−"Hai un anovamientu del sistema disponible y preparáu pa instalase. Dempués, "
772+"Hai un anovamientu del sistema disponible y preparáu pa instalar. Darréu, el "
701−"el preséu va reaniciase automáticamente."
773+"preséu reaniciará de mou automáticu."
702
774
703−#: qml/Wizard/Pages/79-system-update.qml:76
775+#: qml/Wizard/Pages/77-system-update.qml:76
704−#, fuzzy
705−#| msgctxt "string identifying name of the update"
706−#| msgid "Ubuntu system"
707msgctxt "string identifying name of the update"
776msgctxt "string identifying name of the update"
708−msgid "Ubuntu Touch system"
777+msgid "Ubuntu system"
709msgstr "Sistema Ubuntu"
778msgstr "Sistema Ubuntu"
710
779
711−#: qml/Wizard/Pages/79-system-update.qml:83
780+#: qml/Wizard/Pages/77-system-update.qml:83
712#, qt-format
781#, qt-format
713msgctxt "version of the system update"
782msgctxt "version of the system update"
714msgid "Version %1"
783msgid "Version %1"
715msgstr "Versión %1"
784msgstr "Versión %1"
716
785
717−#: qml/Wizard/Pages/79-system-update.qml:95
786+#: qml/Wizard/Pages/77-system-update.qml:102
718msgid "This could take a few minutes..."
787msgid "This could take a few minutes..."
719−msgstr "Esto podría tardar unos minutos…"
788+msgstr "Esto podría tardar dellos minutos..."
720
789
721−#: qml/Wizard/Pages/79-system-update.qml:109
790+#: qml/Wizard/Pages/77-system-update.qml:116
722msgid "Install and restart now"
791msgid "Install and restart now"
723−msgstr ""
792+msgstr "Instalar y reaniciar agora"
724
793
725−#: qml/Wizard/Pages/80-finished.qml:91
794+#: qml/Wizard/Pages/80-finished.qml:89
726−msgid "Welcome Back"
727−msgstr "Volvi afayate"
728−
729−#: qml/Wizard/Pages/80-finished.qml:91
730msgid "Welcome to Ubuntu"
795msgid "Welcome to Ubuntu"
731−msgstr "Afáyate n'Ubuntu"
796+msgstr "Bienveníu/a a Ubuntu"
732
797
733−#: qml/Wizard/Pages/80-finished.qml:106
798+#: qml/Wizard/Pages/80-finished.qml:104
734msgid "You are ready to use your device now"
799msgid "You are ready to use your device now"
735−msgstr "Agora tas preparáu pa usar el preséu"
800+msgstr "Ya tas preparáu pa usar el preséu"
736−
737−#: qml/Wizard/Pages/80-finished.qml:126
738−msgid "Continue"
739−msgstr "Siguir"
740
801
741−#: qml/Wizard/Pages/80-finished.qml:126
802+#: qml/Wizard/Pages/80-finished.qml:124
742msgid "Get Started"
803msgid "Get Started"
743−msgstr "Entamar"
804+msgstr "Primeros pasos"
805+
806+#: qml/Wizard/Pages/here-terms.qml:25
807+msgid "Terms & Conditions"
808+msgstr "Términos y condiciones"
809+
810+#: qml/Wizard/Pages/here-terms.qml:69
811+msgid "Your device uses positioning technologies provided by HERE."
812+msgstr "El preséu usa teunoloxíes de posición qu'ufre HERE."
813+
814+#: qml/Wizard/Pages/here-terms.qml:81
815+msgid ""
816+"To provide you with positioning services and to improve their quality, HERE "
817+"collects information about nearby cell towers and Wi-Fi hotspots around your "
818+"current location whenever your position is being found."
819+msgstr ""
820+"Pa ufrir los servicios de posición y ameyorar la so calidá, HERE collecha "
821+"información de les antenes celulares y puntos d'accesu Wi-Fi cercanos al to "
822+"allugamientu actual siempre que se conoza la to posición."
823+
824+#: qml/Wizard/Pages/here-terms.qml:93
825+msgid ""
826+"The information collected is used to analyze the service and to improve the "
827+"use of service, but not to identify you personally."
828+msgstr ""
829+"La información collechada úsase p'analizar el serviciu y ameyorar l'usu del "
830+"serviciu, non pa identificate personalmente."
831+
832+#: qml/Wizard/Pages/here-terms.qml:106
833+#, qt-format
834+msgid "By continuing, you agree to the HERE platform %1 and %2."
835+msgstr "Al siguir, aceutes %1 y %2 de la plataforma HERE."
836+
837+#: qml/Wizard/Pages/here-terms.qml:107
838+msgid "Service Terms"
839+msgstr "Términos del serviciu"
744
840
745#: qml/Wizard/Pages/passcode-confirm.qml:43
841#: qml/Wizard/Pages/passcode-confirm.qml:43
746−#: qml/Wizard/Pages/passcode-desktop.qml:104
842+#: qml/Wizard/Pages/passcode-desktop.qml:97
747msgid "Confirm passcode"
843msgid "Confirm passcode"
748−msgstr "Confirmación"
844+msgstr "Confirmar códigu de pasu"
749
845
750#: qml/Wizard/Pages/passcode-confirm.qml:45
846#: qml/Wizard/Pages/passcode-confirm.qml:45
751msgid "Incorrect passcode."
847msgid "Incorrect passcode."
752−msgstr "El códigu numbéricu ye incorreutu."
848+msgstr "Códigu de pasu incorreutu."
753
849
754#: qml/Wizard/Pages/passcode-confirm.qml:45
850#: qml/Wizard/Pages/passcode-confirm.qml:45
755msgctxt "Enter the passcode again"
851msgctxt "Enter the passcode again"
756msgid "Please re-enter."
852msgid "Please re-enter."
757−msgstr "Volvi introducilu."
853+msgstr "Vuelve a escribilu."
758
854
759#: qml/Wizard/Pages/passcode-desktop.qml:31
855#: qml/Wizard/Pages/passcode-desktop.qml:31
760msgid "Lock Screen Passcode"
856msgid "Lock Screen Passcode"
761−msgstr "Códigu numbéricu de la pantalla de bloquéu"
857+msgstr "Códigu de pasu de bloquéu de pantalla"
762
858
763−#: qml/Wizard/Pages/passcode-desktop.qml:68
859+#: qml/Wizard/Pages/passcode-desktop.qml:61
764msgid "Enter 4 numbers to setup your passcode"
860msgid "Enter 4 numbers to setup your passcode"
765−msgstr "Introduz 4 númberos pa configurar el códigu numbéricu"
861+msgstr "Escribi 4 númberos pa configurar el códigu de pasu"
766
862
767−#: qml/Wizard/Pages/passcode-desktop.qml:84
863+#: qml/Wizard/Pages/passcode-desktop.qml:77
768#: qml/Wizard/Pages/passcode-set.qml:54
864#: qml/Wizard/Pages/passcode-set.qml:54
769msgid "Choose passcode"
865msgid "Choose passcode"
770−msgstr "Códigu numbéricu"
866+msgstr "Escueyi'l códigu de pasu"
771
867
772−#: qml/Wizard/Pages/passcode-desktop.qml:139
868+#: qml/Wizard/Pages/passcode-desktop.qml:127
773msgid "Passcode too short"
869msgid "Passcode too short"
774−msgstr "El códigu numbéricu ye percurtiu"
870+msgstr "Códigu de pasu curtiu enforma"
775
871
776−#: qml/Wizard/Pages/passcode-desktop.qml:141
872+#: qml/Wizard/Pages/passcode-desktop.qml:129
777msgid "Passcodes match"
873msgid "Passcodes match"
778−msgstr "Los códigos numbéricos concasen"
874+msgstr "Los códigos de pasu casen"
779
875
780−#: qml/Wizard/Pages/passcode-desktop.qml:143
876+#: qml/Wizard/Pages/passcode-desktop.qml:131
781msgid "Passcodes do not match"
877msgid "Passcodes do not match"
782−msgstr "Los códigos numbéricos nun concasen"
878+msgstr "Los códigos de pasu nun casen"
783
879
784#: qml/Wizard/Pages/passcode-set.qml:62
880#: qml/Wizard/Pages/passcode-set.qml:62
785msgid "Passcode must be 4 characters long"
881msgid "Passcode must be 4 characters long"
786−msgstr "El códigu numbéricu a ser de 4 caráuteres"
882+msgstr "El códigu de pasu tien de tener 4 caráuteres de llargo"
787
883
788#: qml/Wizard/Pages/password-set.qml:31
884#: qml/Wizard/Pages/password-set.qml:31
789msgid "Lock Screen Password"
885msgid "Lock Screen Password"
790−msgstr "Contraseña de la pantalla de bloquéu"
886+msgstr "Contraseña del Bloquéu de pantalla"
791
887
792−#: qml/Wizard/Pages/password-set.qml:68
888+#: qml/Wizard/Pages/password-set.qml:62
793msgid "Enter at least 8 characters"
889msgid "Enter at least 8 characters"
794−msgstr "Introduz 8 caráuteres polo menos"
890+msgstr "Escribe polo menos 8 caráuteres"
795
891
796−#: qml/Wizard/Pages/password-set.qml:80
892+#: qml/Wizard/Pages/password-set.qml:74
797msgid "Choose password"
893msgid "Choose password"
798−msgstr "Contraseña"
894+msgstr "Escueye la contraseña"
799
895
800−#: qml/Wizard/Pages/password-set.qml:110
896+#: qml/Wizard/Pages/password-set.qml:104
801msgid "Confirm password"
897msgid "Confirm password"
802−msgstr "Confirmación"
898+msgstr "Confirmar contraseña"
803
899
804#: qml/Wizard/Pages/sim.qml:27
900#: qml/Wizard/Pages/sim.qml:27
805msgid "No SIM card installed"
901msgid "No SIM card installed"
806−msgstr "Nun s'instaló denguna tarxeta SIM"
902+msgstr "Nun ta instalada nenguna tarxeta SIM"
807
903
808#: qml/Wizard/Pages/sim.qml:54
904#: qml/Wizard/Pages/sim.qml:54
809msgid "SIM card added"
905msgid "SIM card added"
810−msgstr ""
906+msgstr "Amestóse tarxeta SIM"
811
907
812#: qml/Wizard/Pages/sim.qml:55
908#: qml/Wizard/Pages/sim.qml:55
813msgid "You must restart the device to access the mobile network."
909msgid "You must restart the device to access the mobile network."
814−msgstr "Has reaniciar el preséu p'acceder a la rede móvil."
910+msgstr "Tienes de reaniciar el preséu pa tener accesu a la rede móvil."
815
911
816#: qml/Wizard/Pages/sim.qml:59
912#: qml/Wizard/Pages/sim.qml:59
817msgid "Restart"
913msgid "Restart"
818−msgstr ""
914+msgstr "Reaniciar"
819
915
820#: qml/Wizard/Pages/sim.qml:78
916#: qml/Wizard/Pages/sim.qml:78
821msgid "You won’t be able to make calls or use text messaging without a SIM."
917msgid "You won’t be able to make calls or use text messaging without a SIM."
822−msgstr "Nun vas ser a facer llamaes o unviar SMS ensin una SIM."
918+msgstr "Nun podrás facer llamaes nin usar mensaxería de testu sin una SIM."
823
919
824#: qml/Wizard/Pages/sim.qml:90
920#: qml/Wizard/Pages/sim.qml:90
825msgid "To proceed with no SIM tap Skip."
921msgid "To proceed with no SIM tap Skip."
826−msgstr "Pa siguir ensin una tarxeta SIM toca Saltar."
922+msgstr "Pa siguir ensin SIM toca Saltar."
827
923
828#: qml/Wizard/PasswordMeter.qml:87
924#: qml/Wizard/PasswordMeter.qml:87
829msgid "Password too short"
925msgid "Password too short"
830−msgstr "La contraseña ye percurtia"
926+msgstr "Contraseña curtia enforma"
831
927
832#: qml/Wizard/PasswordMeter.qml:89
928#: qml/Wizard/PasswordMeter.qml:89
833msgid "Passwords match"
929msgid "Passwords match"
@@ -839,11 +935,11 @@ msgstr "Les contraseñes nun concasen"
839
935
840#: qml/Wizard/PasswordMeter.qml:95
936#: qml/Wizard/PasswordMeter.qml:95
841msgid "Strong password"
937msgid "Strong password"
842−msgstr "Contraseña perbona"
938+msgstr "Contraseña fuerte"
843
939
844#: qml/Wizard/PasswordMeter.qml:97
940#: qml/Wizard/PasswordMeter.qml:97
845msgid "Fair password"
941msgid "Fair password"
846−msgstr "Contraseña bona"
942+msgstr "Contraseña aceutable"
847
943
848#: qml/Wizard/PasswordMeter.qml:99
944#: qml/Wizard/PasswordMeter.qml:99
849msgid "Weak password"
945msgid "Weak password"
@@ -851,185 +947,7 @@ msgstr "Contraseña feble"
851
947
852#: qml/Wizard/PasswordMeter.qml:101
948#: qml/Wizard/PasswordMeter.qml:101
853msgid "Very weak password"
949msgid "Very weak password"
854−msgstr "Contraseña perfeble"
950+msgstr "Contraseña feble enforma"
855−
856−#~ msgid "Unity 8"
857−#~ msgstr "Unity 8"
858−
859−#~ msgid "Scopes"
860−#~ msgstr "Ámbitos"
861−
862−#~ msgid "Super (Tap)"
863−#~ msgstr "Súper (Toque)"
864−
865−#~ msgid "Opens the Scopes home."
866−#~ msgstr "Abre l'aniciu d'Ámbitos."
867−
868−#~ msgctxt "Button: Open the Ubuntu Store"
869−#~ msgid "Store"
870−#~ msgstr "Tienda"
871−
872−#~ msgctxt "Button: Start a search in the current dash scope"
873−#~ msgid "Search"
874−#~ msgstr "Guetar"
875−
876−#~ msgctxt "Button: Show the current dash scope settings"
877−#~ msgid "Settings"
878−#~ msgstr "Axustes"
879−
880−#~ msgid "Show less"
881−#~ msgstr "Amosar menos"
882−
883−#~ msgid "Show all"
884−#~ msgstr "Amosar too"
885−
886−#~ msgid "Recent Searches"
887−#~ msgstr "Guetes d'apocayá"
888−
889−#~ msgid "Clear All"
890−#~ msgstr "Llimpiar too"
891−
892−#~ msgid "More..."
893−#~ msgstr "Más…"
894−
895−#~ msgid "Less..."
896−#~ msgstr "Menos…"
897−
898−#~ msgid "Manage"
899−#~ msgstr "Xestión"
900−
901−#~ msgid "Home"
902−#~ msgstr "Aniciu"
903−
904−#~ msgid "Also installed"
905−#~ msgstr "Tamién s'instaló"
906−
907−#~ msgid "Privacy Policy"
908−#~ msgstr "Política de privacidá"
909−
910−#~ msgid "Help Us Improve"
911−#~ msgstr "Ayúdanos a ameyorar"
912−
913−#~ msgid "Improve system performance by sending us crashes and error reports."
914−#~ msgstr ""
915−#~ "Ameyora'l rindimientu del sistema unviándonos informes de casques y "
916−#~ "fallos."
917−
918−#~ msgid "Privacy policy"
919−#~ msgstr "Política de privacidá"
920−
921−#~ msgid "This device is not connected to the internet."
922−#~ msgstr "El preséu nun ta coneutáu a internet."
923−
924−#~ msgid "Software is up to date"
925−#~ msgstr "El software ta anováu"
926−
927−#~ msgid "The update server is not responding."
928−#~ msgstr "El sirvidor d'anovamientos nun ta respondiendo."
929−
930−#~ msgid "Please wait..."
931−#~ msgstr "Espera…"
932−
933−#~ msgid "Installation failed"
934−#~ msgstr "Falló la instalación"
935−
936−#~ msgid "Checking for updates…"
937−#~ msgstr "Comprobando anovamientos…"
938−
939−#~ msgid "%1 update available"
940−#~ msgid_plural "%1 updates available"
941−#~ msgstr[0] "%1 anovamientu disponible"
942−#~ msgstr[1] "%1 anovamientos disponibles"
943−
944−#~ msgid "Update all…"
945−#~ msgstr "Anovar too…"
946−
947−#~ msgid "Update all"
948−#~ msgstr "Anovar too"
949−
950−#~ msgid "Resume"
951−#~ msgstr "Siguir"
952−
953−#~ msgid "Install…"
954−#~ msgstr "Instalar…"
955−
956−#~ msgid "Open"
957−#~ msgstr "Abrir"
958−
959−#~ msgid "Installing"
960−#~ msgstr "Instalando"
961−
962−#~ msgid "Paused"
963−#~ msgstr "Posóse"
964−
965−#~ msgid "Waiting to download"
966−#~ msgstr "Esperando pola descarga"
967−
968−#~ msgid "%1 of %2"
969−#~ msgstr "%1 de %2"
970−
971−#~ msgid "Downloaded"
972−#~ msgstr "Baxó"
973−
974−#~ msgid "Installed"
975−#~ msgstr "Instalóse"
976−
977−#~ msgid "Updated %1"
978−#~ msgstr "Anovóse %1"
979−
980−#~ msgid "Location Services"
981−#~ msgstr "Servicios d'allugamientu"
982−
983−#~ msgid ""
984−#~ "Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
985−#~ "(recommended)"
986−#~ msgstr ""
987−#~ "Usar GPS, puntos Wi-Fi y redes móviles de mou anónimu pa detectar "
988−#~ "l'allugamientu (recomendao)"
989−
990−#~ msgid "By selecting this option you agree to the Nokia HERE %1."
991−#~ msgstr "Seleicionando esta opción aceutes los %1 de Nokia HERE."
992−
993−#~ msgctxt "part of: Nokia HERE terms and conditions"
994−#~ msgid "terms and conditions"
995−#~ msgstr "términos y condiciones"
996−
997−#~ msgid "GPS only"
998−#~ msgstr "Sólo GPS"
999−
1000−#~ msgid "Don't use my location"
1001−#~ msgstr "Nun usar l'allugamientu"
1002−
1003−#~ msgid "You can change it later in System Settings."
1004−#~ msgstr "Pues camudalo sero na Configuración del Sistema."
1005−
1006−#~ msgid "Terms & Conditions"
1007−#~ msgstr "Términos y condiciones"
1008−
1009−#~ msgid "Your device uses positioning technologies provided by HERE."
1010−#~ msgstr "El preséu usa teunoloxíes de posición qu'ufre HERE."
1011−
1012−#~ msgid ""
1013−#~ "To provide you with positioning services and to improve their quality, "
1014−#~ "HERE collects information about nearby cell towers and Wi-Fi hotspots "
1015−#~ "around your current location whenever your position is being found."
1016−#~ msgstr ""
1017−#~ "Pa ufrir los servicios de posición y ameyorar la so calidá, HERE collecha "
1018−#~ "información de les antenes celulares y puntos d'accesu Wi-Fi cercanos al "
1019−#~ "to allugamientu actual siempre que se conoza la to posición."
1020−
1021−#~ msgid ""
1022−#~ "The information collected is used to analyze the service and to improve "
1023−#~ "the use of service, but not to identify you personally."
1024−#~ msgstr ""
1025−#~ "La información collechada úsase p'analizar el serviciu y ameyorar l'usu "
1026−#~ "del serviciu, non pa identificate personalmente."
1027−
1028−#~ msgid "By continuing, you agree to the HERE platform %1 and %2."
1029−#~ msgstr "Al siguir, aceutes %1 y %2 de la plataforma HERE."
1030−
1031−#~ msgid "Service Terms"
1032−#~ msgstr "Términos del serviciu"
1033
951
1034#~ msgid "Skip intro"
952#~ msgid "Skip intro"
1035#~ msgstr "Omitir la intro"
953#~ msgstr "Omitir la intro"
@@ -1057,8 +975,8 @@ msgstr "Contraseña perfeble"
1057
975
1058#~ msgid "Swipe from the left to reveal the launcher for quick access to apps"
976#~ msgid "Swipe from the left to reveal the launcher for quick access to apps"
1059#~ msgstr ""
977#~ msgstr ""
1060−#~ "Esliza'l deu dende la esquierda p'amosar el llanzador y acceder "
978+#~ "Esliza'l deu dende la esquierda p'amosar el llanzador y acceder rápidamente "
1061−#~ "rápidamente a les aplicaciones"
979+#~ "a les aplicaciones"
1062
980
1063#~ msgid "Well done"
981#~ msgid "Well done"
1064#~ msgstr "Bien fecho"
982#~ msgstr "Bien fecho"
@@ -1066,12 +984,21 @@ msgstr "Contraseña perfeble"
1066#~ msgid "Confirm"
984#~ msgid "Confirm"
1067#~ msgstr "Confirmar"
985#~ msgstr "Confirmar"
1068
986
987+#~ msgid "Speaking..."
988+#~ msgstr "Falando…"
989+
990+#~ msgid "Loading. Please Wait..."
991+#~ msgstr "Cargando, espera…"
992+
1069#~ msgid "Type or say a command"
993#~ msgid "Type or say a command"
1070#~ msgstr "Escribi o di una orde"
994#~ msgstr "Escribi o di una orde"
1071
995
1072#~ msgid "Speak Now..."
996#~ msgid "Speak Now..."
1073#~ msgstr "Fala agora…"
997#~ msgstr "Fala agora…"
1074
998
999+#~ msgid "Search"
1000+#~ msgstr "Guetar"
1001+
1075#~ msgid "See less"
1002#~ msgid "See less"
1076#~ msgstr "Ver menos"
1003#~ msgstr "Ver menos"
1077
1004
@@ -1118,6 +1045,7 @@ msgstr "Contraseña perfeble"
1118#~ msgid "Store"
1045#~ msgid "Store"
1119#~ msgstr "Tienda"
1046#~ msgstr "Tienda"
1120
1047
1048+#, qt-format
1121#~ msgid "Sorry, incorrect %1"
1049#~ msgid "Sorry, incorrect %1"
1122#~ msgstr "Sentímoslo, %1 incorreutu"
1050#~ msgstr "Sentímoslo, %1 incorreutu"
1123
1051
@@ -1133,6 +1061,9 @@ msgstr "Contraseña perfeble"
1133#~ msgid "Manage Scopes"
1061#~ msgid "Manage Scopes"
1134#~ msgstr "Xestionar ámbitos"
1062#~ msgstr "Xestionar ámbitos"
1135
1063
1064+#~ msgid "Continue"
1065+#~ msgstr "Siguir"
1066+
1136#~ msgid "Without it, you won’t be able to make calls or use text messaging."
1067#~ msgid "Without it, you won’t be able to make calls or use text messaging."
1137#~ msgstr "Ensin ella, nun vas poder facer llamaes nin unviar mensaxes."
1068#~ msgstr "Ensin ella, nun vas poder facer llamaes nin unviar mensaxes."
1138
1069
@@ -1164,12 +1095,17 @@ msgstr "Contraseña perfeble"
1164#~ msgid "Not at all"
1095#~ msgid "Not at all"
1165#~ msgstr "De nengún mou"
1096#~ msgstr "De nengún mou"
1166
1097
1098+#, qt-format
1167#~ msgid "〈 %1"
1099#~ msgid "〈 %1"
1168#~ msgstr "〈 %1"
1100#~ msgstr "〈 %1"
1169
1101
1102+#, qt-format
1170#~ msgid "%1 〉"
1103#~ msgid "%1 〉"
1171#~ msgstr "%1 〉"
1104#~ msgstr "%1 〉"
1172
1105
1106+#~ msgid "Open the launcher"
1107+#~ msgstr "Abrir el llanzador"
1108+
1173#~ msgid "Tap here to continue."
1109#~ msgid "Tap here to continue."
1174#~ msgstr "Toca equí pa siguir."
1110#~ msgstr "Toca equí pa siguir."
1175
1111
@@ -1210,28 +1146,35 @@ msgstr "Contraseña perfeble"
1210#~ msgid "Sorry, incorrect passphrase."
1146#~ msgid "Sorry, incorrect passphrase."
1211#~ msgstr "Perdón, fras de pasu incorreuta"
1147#~ msgstr "Perdón, fras de pasu incorreuta"
1212
1148
1149+#, qt-format
1213#~ msgid "Enter %1"
1150#~ msgid "Enter %1"
1214#~ msgstr "Introduz %1"
1151#~ msgstr "Introduz %1"
1215
1152
1216#~ msgid "Sorry, incorrect passcode."
1153#~ msgid "Sorry, incorrect passcode."
1217#~ msgstr "Perdón, códigu de pasu incorreutu."
1154#~ msgstr "Perdón, códigu de pasu incorreutu."
1218
1155
1156+#~ msgid "Enter passcode"
1157+#~ msgstr "Introduz el códigu de pasu"
1158+
1159+#~ msgid "Enter passphrase"
1160+#~ msgstr "Introduz la fras de pasu"
1161+
1219#~ msgid "Please re-enter"
1162#~ msgid "Please re-enter"
1220#~ msgstr "Por favor, reintroduzla"
1163#~ msgstr "Por favor, reintroduzla"
1221
1164
1222#~ msgid ""
1165#~ msgid ""
1223−#~ "If passcode is entered incorrectly, your phone will conduct a factory "
1166+#~ "If passcode is entered incorrectly, your phone will conduct a factory reset "
1224−#~ "reset and all personal data will be deleted."
1167+#~ "and all personal data will be deleted."
1225#~ msgstr ""
1168#~ msgstr ""
1226−#~ "Si s'inxerta'l códigu de pasu incorreutamente, el to teléfonu va "
1169+#~ "Si s'inxerta'l códigu de pasu incorreutamente, el to teléfonu va reafitase y "
1227−#~ "reafitase y van desaniciase tolos datos personales."
1170+#~ "van desaniciase tolos datos personales."
1228
1171
1229#~ msgid ""
1172#~ msgid ""
1230#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
1173#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
1231#~ "reset and all personal data will be deleted."
1174#~ "reset and all personal data will be deleted."
1232#~ msgstr ""
1175#~ msgstr ""
1233−#~ "Si s'inxerta la fras de pasu incorreutamente, el to teléfonu va reafitase "
1176+#~ "Si s'inxerta la fras de pasu incorreutamente, el to teléfonu va reafitase y "
1234−#~ "y van desaniciase tolos datos personales."
1177+#~ "van desaniciase tolos datos personales."
1235
1178
1236#~ msgid "This will be your last attempt."
1179#~ msgid "This will be your last attempt."
1237#~ msgstr "Esti sedra'l to caberu intentu"
1180#~ msgstr "Esti sedra'l to caberu intentu"
@@ -1315,11 +1258,11 @@ msgstr "Contraseña perfeble"
1315#~ msgstr "¡Bon trabayu!"
1258#~ msgstr "¡Bon trabayu!"
1316
1259
1317#~ msgid ""
1260#~ msgid ""
1318−#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms "
1261+#~ "By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
1319−#~ "and conditions</a>."
1262+#~ "conditions</a>."
1320#~ msgstr ""
1263#~ msgstr ""
1321−#~ "Esbillando esta opción aceutes los <a href='#'>términos y condiciones</a> "
1264+#~ "Esbillando esta opción aceutes los <a href='#'>términos y condiciones</a> de "
1322−#~ "de Nokia HERE."
1265+#~ "Nokia HERE."
1323
1266
1324#~ msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
1267#~ msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
1325#~ msgstr ""
1268#~ msgstr ""
@@ -1398,8 +1341,7 @@ msgstr "Contraseña perfeble"
1398
1341
1399#~ msgid "Short or long swipe from the right edge to view your open apps"
1342#~ msgid "Short or long swipe from the right edge to view your open apps"
1400#~ msgstr ""
1343#~ msgstr ""
1401−#~ "Eslizamientu curtiu o llargu dende'l berbesu drechu pa ver les apps "
1344+#~ "Eslizamientu curtiu o llargu dende'l berbesu drechu pa ver les apps abiertes"
1402−#~ "abiertes"
1403
1345
1404#~ msgid "Swipe up to manage the app"
1346#~ msgid "Swipe up to manage the app"
1405#~ msgstr "Eslizar p'alministrar la app"
1347#~ msgstr "Eslizar p'alministrar la app"
po/az.po+327−238
@@ -6,57 +6,28 @@
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9−"Report-Msgid-Bugs-To: \n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2021-01-29 11:42-0600\n"
10+"POT-Creation-Date: 2017-01-10 14:48+0000\n"
11"PO-Revision-Date: 2014-09-03 16:39+0000\n"
11"PO-Revision-Date: 2014-09-03 16:39+0000\n"
12"Last-Translator: Nicat Məmmədov <n1c4t97@gmail.com>\n"
12"Last-Translator: Nicat Məmmədov <n1c4t97@gmail.com>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
14−"Language: az\n"
15"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
16"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2016-11-23 06:34+0000\n"
18+"X-Launchpad-Export-Date: 2017-01-16 05:47+0000\n"
20−"X-Generator: Launchpad (build 18269)\n"
19+"X-Generator: Launchpad (build 18302)\n"
21
20
22−#: plugins/LightDM/Greeter.cpp:199
21+#: plugins/LightDM/Greeter.cpp:123
23msgid "Password: "
22msgid "Password: "
24msgstr "Şifrә: "
23msgstr "Şifrә: "
25
24
26−#: plugins/LightDM/Greeter.cpp:214
27−msgid "Username"
28−msgstr ""
29−
30−#: plugins/LightDM/Greeter.cpp:258
31−msgid "Failed to authenticate"
32−msgstr ""
33−
34−#: plugins/LightDM/Greeter.cpp:260
35−msgid "Invalid password, please try again"
36−msgstr ""
37−
38−#: plugins/LightDM/Greeter.cpp:270
39−msgid "Log In"
40−msgstr ""
41−
42−#: plugins/LightDM/Greeter.cpp:270
43−msgid "Retry"
44−msgstr ""
45−
46−#: plugins/LightDM/UsersModel.cpp:157
47−msgid "Login"
48−msgstr ""
49−
50−#: plugins/LightDM/UsersModel.cpp:165
51−msgid "Guest Session"
52−msgstr ""
53−
54−#: plugins/Unity/Launcher/launcheritem.cpp:48
25+#: plugins/Unity/Launcher/launcheritem.cpp:50
55#: plugins/Unity/Launcher/launcheritem.cpp:122
26#: plugins/Unity/Launcher/launcheritem.cpp:122
56msgid "Pin shortcut"
27msgid "Pin shortcut"
57msgstr "Pin qısayolu"
28msgstr "Pin qısayolu"
58
29
59−#: plugins/Unity/Launcher/launcheritem.cpp:54
30+#: plugins/Unity/Launcher/launcheritem.cpp:55
60msgid "Quit"
31msgid "Quit"
61msgstr ""
32msgstr ""
62
33
@@ -64,79 +35,76 @@ msgstr ""
64msgid "Unpin shortcut"
35msgid "Unpin shortcut"
65msgstr "Açma qısayolu"
36msgstr "Açma qısayolu"
66
37
67−#: qml/Components/Dialogs.qml:176
38+#: qml/Components/Dialogs.qml:149
68msgctxt "Title: Lock/Log out dialog"
39msgctxt "Title: Lock/Log out dialog"
69msgid "Log out"
40msgid "Log out"
70msgstr ""
41msgstr ""
71
42
72−#: qml/Components/Dialogs.qml:177
43+#: qml/Components/Dialogs.qml:150
73msgid "Are you sure you want to log out?"
44msgid "Are you sure you want to log out?"
74msgstr "Çıxmaq istәdiyinizdәn әminsiniz?"
45msgstr "Çıxmaq istәdiyinizdәn әminsiniz?"
75
46
76−#: qml/Components/Dialogs.qml:180
47+#: qml/Components/Dialogs.qml:152
77msgctxt "Button: Lock the system"
48msgctxt "Button: Lock the system"
78msgid "Lock"
49msgid "Lock"
79msgstr ""
50msgstr ""
80
51
81−#: qml/Components/Dialogs.qml:191
52+#: qml/Components/Dialogs.qml:160
82msgctxt "Button: Log out from the system"
53msgctxt "Button: Log out from the system"
83msgid "Log Out"
54msgid "Log Out"
84msgstr ""
55msgstr ""
85
56
86−#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:284
57+#: qml/Components/Dialogs.qml:167 qml/Components/Dialogs.qml:225
58+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:232
87−#: qml/Greeter/NarrowView.qml:215 qml/Wizard/Pages/passcode-confirm.qml:32
59+#: qml/Wizard/Pages/passcode-confirm.qml:32
88#: qml/Wizard/Pages/passcode-set.qml:32
60#: qml/Wizard/Pages/passcode-set.qml:32
89msgid "Cancel"
61msgid "Cancel"
90msgstr "İmtina"
62msgstr "İmtina"
91
63
92−#: qml/Components/Dialogs.qml:211
64+#: qml/Components/Dialogs.qml:179
93msgctxt "Title: Reboot dialog"
65msgctxt "Title: Reboot dialog"
94msgid "Reboot"
66msgid "Reboot"
95msgstr ""
67msgstr ""
96
68
97−#: qml/Components/Dialogs.qml:212
69+#: qml/Components/Dialogs.qml:180
98msgid "Are you sure you want to reboot?"
70msgid "Are you sure you want to reboot?"
99msgstr "Yenidәn başlatmaq istәdiyinizә әminsiniz?"
71msgstr "Yenidәn başlatmaq istәdiyinizә әminsiniz?"
100
72
101−#: qml/Components/Dialogs.qml:215
73+#: qml/Components/Dialogs.qml:182
102msgid "No"
74msgid "No"
103msgstr "Yox"
75msgstr "Yox"
104
76
105−#: qml/Components/Dialogs.qml:223
77+#: qml/Components/Dialogs.qml:189
106msgid "Yes"
78msgid "Yes"
107msgstr "Hə"
79msgstr "Hə"
108
80
109−#: qml/Components/Dialogs.qml:243
81+#: qml/Components/Dialogs.qml:204
110msgctxt "Title: Power off/Restart dialog"
82msgctxt "Title: Power off/Restart dialog"
111msgid "Power"
83msgid "Power"
112msgstr ""
84msgstr ""
113
85
114−#: qml/Components/Dialogs.qml:244
86+#: qml/Components/Dialogs.qml:205
115msgid ""
87msgid ""
116"Are you sure you would like\n"
88"Are you sure you would like\n"
117"to power off?"
89"to power off?"
118msgstr ""
90msgstr ""
119
91
120−#: qml/Components/Dialogs.qml:248
92+#: qml/Components/Dialogs.qml:208
121msgctxt "Button: Power off the system"
93msgctxt "Button: Power off the system"
122msgid "Power off"
94msgid "Power off"
123msgstr ""
95msgstr ""
124
96
125−#: qml/Components/Dialogs.qml:263
97+#: qml/Components/Dialogs.qml:217
126msgctxt "Button: Restart the system"
98msgctxt "Button: Restart the system"
127msgid "Restart"
99msgid "Restart"
128msgstr ""
100msgstr ""
129
101
130−#: qml/Components/Dialogs.qml:276
131−msgid "Screenshot"
132−msgstr ""
133−
134#: qml/Components/KeyboardShortcutsOverlay.qml:41
102#: qml/Components/KeyboardShortcutsOverlay.qml:41
135msgid "Keyboard Shortcuts"
103msgid "Keyboard Shortcuts"
136msgstr ""
104msgstr ""
137
105
138#: qml/Components/KeyboardShortcutsOverlay.qml:55
106#: qml/Components/KeyboardShortcutsOverlay.qml:55
139−msgid "Lomiri"
107+msgid "Unity 8"
140msgstr ""
108msgstr ""
141
109
142#: qml/Components/KeyboardShortcutsOverlay.qml:62
110#: qml/Components/KeyboardShortcutsOverlay.qml:62
@@ -152,7 +120,7 @@ msgid "Alt + PrtScr"
152msgstr ""
120msgstr ""
153
121
154#: qml/Components/KeyboardShortcutsOverlay.qml:80
122#: qml/Components/KeyboardShortcutsOverlay.qml:80
155−msgid "Takes a screenshot of the current window."
123+msgid "Takes a screenshot of a window."
156msgstr ""
124msgstr ""
157
125
158#: qml/Components/KeyboardShortcutsOverlay.qml:88
126#: qml/Components/KeyboardShortcutsOverlay.qml:88
@@ -171,131 +139,135 @@ msgstr ""
171msgid "Switches to previous keyboard layout."
139msgid "Switches to previous keyboard layout."
172msgstr ""
140msgstr ""
173
141
174−#: qml/Components/KeyboardShortcutsOverlay.qml:114
142+#: qml/Components/KeyboardShortcutsOverlay.qml:118
175−msgid "Ctrl + Alt + T"
143+msgid "Launcher"
176msgstr ""
144msgstr ""
177
145
178−#: qml/Components/KeyboardShortcutsOverlay.qml:119
146+#: qml/Components/KeyboardShortcutsOverlay.qml:125
179−msgid "Starts the Terminal application."
147+msgid "Super (Hold)"
180msgstr ""
148msgstr ""
181
149
182−#: qml/Components/KeyboardShortcutsOverlay.qml:131
150+#: qml/Components/KeyboardShortcutsOverlay.qml:130
183−msgid "Launcher"
151+msgid "Opens the launcher, displays shortcuts."
184msgstr ""
152msgstr ""
185
153
186#: qml/Components/KeyboardShortcutsOverlay.qml:138
154#: qml/Components/KeyboardShortcutsOverlay.qml:138
187−msgid "Super (Hold)"
155+msgid "Alt + F1"
188msgstr ""
156msgstr ""
189
157
190#: qml/Components/KeyboardShortcutsOverlay.qml:143
158#: qml/Components/KeyboardShortcutsOverlay.qml:143
191−msgid "Opens the launcher, displays shortcuts."
159+msgid "Opens launcher keyboard navigation mode."
192msgstr ""
160msgstr ""
193
161
194#: qml/Components/KeyboardShortcutsOverlay.qml:151
162#: qml/Components/KeyboardShortcutsOverlay.qml:151
195−msgid "Alt + F1"
163+msgid "Super + Tab"
196msgstr ""
164msgstr ""
197
165
198#: qml/Components/KeyboardShortcutsOverlay.qml:156
166#: qml/Components/KeyboardShortcutsOverlay.qml:156
199−msgid "Opens launcher keyboard navigation mode."
167+msgid "Switches applications via the launcher."
200msgstr ""
168msgstr ""
201
169
202#: qml/Components/KeyboardShortcutsOverlay.qml:164
170#: qml/Components/KeyboardShortcutsOverlay.qml:164
203−msgid "Super + Tab"
171+msgid "Super + 0 to 9"
204msgstr ""
172msgstr ""
205
173
206#: qml/Components/KeyboardShortcutsOverlay.qml:169
174#: qml/Components/KeyboardShortcutsOverlay.qml:169
207−msgid "Switches applications via the launcher."
175+msgid "Same as clicking on a launcher icon."
208msgstr ""
176msgstr ""
209
177
210#: qml/Components/KeyboardShortcutsOverlay.qml:177
178#: qml/Components/KeyboardShortcutsOverlay.qml:177
211−msgid "Super + 1 to 0"
179+msgid "Super + A"
212msgstr ""
180msgstr ""
213
181
214#: qml/Components/KeyboardShortcutsOverlay.qml:182
182#: qml/Components/KeyboardShortcutsOverlay.qml:182
215−msgid "Same as clicking on a launcher icon."
183+msgid "Opens the Application Drawer."
216msgstr ""
184msgstr ""
217
185
218−#: qml/Components/KeyboardShortcutsOverlay.qml:190
186+#: qml/Components/KeyboardShortcutsOverlay.qml:194
219−msgid "Super + A"
187+msgid "Scopes"
220msgstr ""
188msgstr ""
221
189
222−#: qml/Components/KeyboardShortcutsOverlay.qml:195
190+#: qml/Components/KeyboardShortcutsOverlay.qml:201
223−msgid "Opens the Application Drawer."
191+msgid "Super (Tap)"
224msgstr ""
192msgstr ""
225
193
226−#: qml/Components/KeyboardShortcutsOverlay.qml:235
194+#: qml/Components/KeyboardShortcutsOverlay.qml:206
195+msgid "Opens the Scopes home."
196+msgstr ""
197+
198+#: qml/Components/KeyboardShortcutsOverlay.qml:222
227msgid "Switching"
199msgid "Switching"
228msgstr ""
200msgstr ""
229
201
230−#: qml/Components/KeyboardShortcutsOverlay.qml:242
202+#: qml/Components/KeyboardShortcutsOverlay.qml:229
231msgid "Alt + Tab"
203msgid "Alt + Tab"
232msgstr ""
204msgstr ""
233
205
234−#: qml/Components/KeyboardShortcutsOverlay.qml:247
206+#: qml/Components/KeyboardShortcutsOverlay.qml:234
235msgid "Switches between applications."
207msgid "Switches between applications."
236msgstr ""
208msgstr ""
237
209
238−#: qml/Components/KeyboardShortcutsOverlay.qml:255
210+#: qml/Components/KeyboardShortcutsOverlay.qml:242
239msgid "Super + W"
211msgid "Super + W"
240msgstr ""
212msgstr ""
241
213
242−#: qml/Components/KeyboardShortcutsOverlay.qml:260
214+#: qml/Components/KeyboardShortcutsOverlay.qml:247
243msgid "Opens the desktop spread."
215msgid "Opens the desktop spread."
244msgstr ""
216msgstr ""
245
217
246−#: qml/Components/KeyboardShortcutsOverlay.qml:268
218+#: qml/Components/KeyboardShortcutsOverlay.qml:255
247msgid "Cursor Left or Right"
219msgid "Cursor Left or Right"
248msgstr ""
220msgstr ""
249
221
250−#: qml/Components/KeyboardShortcutsOverlay.qml:273
222+#: qml/Components/KeyboardShortcutsOverlay.qml:260
251msgid "Moves the focus."
223msgid "Moves the focus."
252msgstr ""
224msgstr ""
253
225
254−#: qml/Components/KeyboardShortcutsOverlay.qml:285
226+#: qml/Components/KeyboardShortcutsOverlay.qml:272
255msgid "Windows"
227msgid "Windows"
256msgstr ""
228msgstr ""
257
229
258−#: qml/Components/KeyboardShortcutsOverlay.qml:292
230+#: qml/Components/KeyboardShortcutsOverlay.qml:279
259msgid "Ctrl + Super + D"
231msgid "Ctrl + Super + D"
260msgstr ""
232msgstr ""
261
233
262−#: qml/Components/KeyboardShortcutsOverlay.qml:297
234+#: qml/Components/KeyboardShortcutsOverlay.qml:284
263msgid "Minimizes all windows."
235msgid "Minimizes all windows."
264msgstr ""
236msgstr ""
265
237
266−#: qml/Components/KeyboardShortcutsOverlay.qml:305
238+#: qml/Components/KeyboardShortcutsOverlay.qml:292
267msgid "Ctrl + Super + Up"
239msgid "Ctrl + Super + Up"
268msgstr ""
240msgstr ""
269
241
270−#: qml/Components/KeyboardShortcutsOverlay.qml:310
242+#: qml/Components/KeyboardShortcutsOverlay.qml:297
271msgid "Maximizes the current window."
243msgid "Maximizes the current window."
272msgstr ""
244msgstr ""
273
245
274−#: qml/Components/KeyboardShortcutsOverlay.qml:318
246+#: qml/Components/KeyboardShortcutsOverlay.qml:305
275msgid "Ctrl + Super + Down"
247msgid "Ctrl + Super + Down"
276msgstr ""
248msgstr ""
277
249
278−#: qml/Components/KeyboardShortcutsOverlay.qml:323
250+#: qml/Components/KeyboardShortcutsOverlay.qml:310
279msgid "Minimizes or restores the current window."
251msgid "Minimizes or restores the current window."
280msgstr ""
252msgstr ""
281
253
282−#: qml/Components/KeyboardShortcutsOverlay.qml:331
254+#: qml/Components/KeyboardShortcutsOverlay.qml:318
283msgid "Ctrl + Super + Left or Right"
255msgid "Ctrl + Super + Left or Right"
284msgstr ""
256msgstr ""
285
257
286−#: qml/Components/KeyboardShortcutsOverlay.qml:336
258+#: qml/Components/KeyboardShortcutsOverlay.qml:323
287msgid "Semi-maximizes the current window."
259msgid "Semi-maximizes the current window."
288msgstr ""
260msgstr ""
289
261
290−#: qml/Components/KeyboardShortcutsOverlay.qml:344
262+#: qml/Components/KeyboardShortcutsOverlay.qml:331
291msgid "Alt + F4"
263msgid "Alt + F4"
292msgstr ""
264msgstr ""
293
265
294−#: qml/Components/KeyboardShortcutsOverlay.qml:349
266+#: qml/Components/KeyboardShortcutsOverlay.qml:336
295msgid "Closes the current window."
267msgid "Closes the current window."
296msgstr ""
268msgstr ""
297
269
298−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:235
270+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:252
299msgid "Return to Call"
271msgid "Return to Call"
300msgstr ""
272msgstr ""
301
273
@@ -303,7 +275,7 @@ msgstr ""
303msgid "Emergency Call"
275msgid "Emergency Call"
304msgstr "Zərurət zəngi"
276msgstr "Zərurət zəngi"
305
277
306−#: qml/Components/Lockscreen.qml:245
278+#: qml/Components/Lockscreen.qml:244
307msgid "OK"
279msgid "OK"
308msgstr "Oldu"
280msgstr "Oldu"
309
281
@@ -317,29 +289,29 @@ msgstr ""
317msgid "%1:%2"
289msgid "%1:%2"
318msgstr ""
290msgstr ""
319
291
320−#: qml/Components/ModeSwitchWarningDialog.qml:33
292+#: qml/Components/ModeSwitchWarningDialog.qml:32
321msgid "Apps may have unsaved data:"
293msgid "Apps may have unsaved data:"
322msgstr ""
294msgstr ""
323
295
324−#: qml/Components/ModeSwitchWarningDialog.qml:60
296+#: qml/Components/ModeSwitchWarningDialog.qml:57
325msgctxt ""
297msgctxt ""
326"Re-dock means connect the device again to an external screen/mouse/keyboard"
298"Re-dock means connect the device again to an external screen/mouse/keyboard"
327msgid "Re-dock, save your work and close these apps to continue."
299msgid "Re-dock, save your work and close these apps to continue."
328msgstr ""
300msgstr ""
329
301
330−#: qml/Components/ModeSwitchWarningDialog.qml:67
302+#: qml/Components/ModeSwitchWarningDialog.qml:63
331msgid "Or force close now (unsaved data will be lost)."
303msgid "Or force close now (unsaved data will be lost)."
332msgstr ""
304msgstr ""
333
305
334−#: qml/Components/ModeSwitchWarningDialog.qml:80
306+#: qml/Components/ModeSwitchWarningDialog.qml:75
335msgid "OK, I will reconnect"
307msgid "OK, I will reconnect"
336msgstr ""
308msgstr ""
337
309
338−#: qml/Components/ModeSwitchWarningDialog.qml:81
310+#: qml/Components/ModeSwitchWarningDialog.qml:76
339msgid "Reconnect now!"
311msgid "Reconnect now!"
340msgstr ""
312msgstr ""
341
313
342−#: qml/Components/ModeSwitchWarningDialog.qml:94
314+#: qml/Components/ModeSwitchWarningDialog.qml:88
343msgid "Close all"
315msgid "Close all"
344msgstr ""
316msgstr ""
345
317
@@ -354,10 +326,8 @@ msgid ""
354msgstr ""
326msgstr ""
355
327
356#: qml/Components/VirtualTouchPad.qml:327
328#: qml/Components/VirtualTouchPad.qml:327
357−#, fuzzy
358−#| msgid "Tap to return to call..."
359msgid "Tap left button to click."
329msgid "Tap left button to click."
360−msgstr "Zəngə qayıtmaq üçün toxunun..."
330+msgstr ""
361
331
362#: qml/Components/VirtualTouchPad.qml:339
332#: qml/Components/VirtualTouchPad.qml:339
363msgid "Tap right button to right click."
333msgid "Tap right button to right click."
@@ -371,6 +341,103 @@ msgstr ""
371msgid "Find more settings in the system settings."
341msgid "Find more settings in the system settings."
372msgstr ""
342msgstr ""
373
343
344+#: qml/Dash/DashPageHeader.qml:361
345+msgctxt "Button: Open the Ubuntu Store"
346+msgid "Store"
347+msgstr ""
348+
349+#: qml/Dash/DashPageHeader.qml:368
350+msgctxt "Button: Start a search in the current dash scope"
351+msgid "Search"
352+msgstr ""
353+
354+#: qml/Dash/DashPageHeader.qml:378
355+msgctxt "Button: Show the current dash scope settings"
356+msgid "Settings"
357+msgstr ""
358+
359+#: qml/Dash/DashPageHeader.qml:385
360+msgid "Remove from Favorites"
361+msgstr "Seçilmişlәrdәn çıxart"
362+
363+#: qml/Dash/DashPageHeader.qml:385
364+msgid "Add to Favorites"
365+msgstr "Seçilmişlәrә әlavә et"
366+
367+#: qml/Dash/FiltersPopover.qml:61
368+msgid "Refine your results"
369+msgstr ""
370+
371+#: qml/Dash/FiltersPopover.qml:70
372+msgid "Reset"
373+msgstr ""
374+
375+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
376+msgid "Show less"
377+msgstr ""
378+
379+#: qml/Dash/GenericScopeView.qml:547
380+msgid "Show all"
381+msgstr ""
382+
383+#: qml/Dash/GenericScopeView.qml:578
384+msgctxt "Label: Hint for dash search line edit"
385+msgid "Search"
386+msgstr ""
387+
388+#: qml/Dash/PageHeaderExtraPanel.qml:67
389+msgid "Recent Searches"
390+msgstr ""
391+
392+#: qml/Dash/PageHeaderExtraPanel.qml:78
393+msgid "Clear All"
394+msgstr ""
395+
396+#: qml/Dash/Previews/PreviewActionCombo.qml:36
397+msgid "More..."
398+msgstr "Daha çox..."
399+
400+#: qml/Dash/Previews/PreviewActionCombo.qml:36
401+msgid "Less..."
402+msgstr "Az..."
403+
404+#: qml/Dash/Previews/PreviewCommentInput.qml:83
405+#: qml/Dash/Previews/PreviewRatingInput.qml:202
406+msgid "Send"
407+msgstr "Göndər"
408+
409+#: qml/Dash/Previews/PreviewRatingInput.qml:109
410+msgid "Rate this"
411+msgstr "Qiymәtlәndir"
412+
413+#: qml/Dash/Previews/PreviewRatingInput.qml:184
414+msgid "Add a review"
415+msgstr "Rəy yaz"
416+
417+#: qml/Dash/PullToRefreshScopeStyle.qml:56
418+msgid "Pull to refresh…"
419+msgstr ""
420+
421+#: qml/Dash/PullToRefreshScopeStyle.qml:61
422+msgid "Release to refresh…"
423+msgstr ""
424+
425+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
426+msgid "Enable location data"
427+msgstr ""
428+
429+#: qml/Dash/ScopesList.qml:146
430+msgid "Manage"
431+msgstr ""
432+
433+#: qml/Dash/ScopesList.qml:187
434+msgid "Home"
435+msgstr ""
436+
437+#: qml/Dash/ScopesList.qml:188
438+msgid "Also installed"
439+msgstr ""
440+
374#: qml/Greeter/CoverPage.qml:127
441#: qml/Greeter/CoverPage.qml:127
375msgid "Unlock"
442msgid "Unlock"
376msgstr ""
443msgstr ""
@@ -394,46 +461,45 @@ msgid_plural "Please wait %1 minutes and then try again…"
394msgstr[0] ""
461msgstr[0] ""
395msgstr[1] ""
462msgstr[1] ""
396
463
397−#: qml/Greeter/Greeter.qml:550
464+#: qml/Greeter/Greeter.qml:592
398msgid "Try again"
465msgid "Try again"
399msgstr ""
466msgstr ""
400
467
401−#: qml/Greeter/Greeter.qml:551
468+#: qml/Greeter/LoginList.qml:70
402−msgid "Enter passphrase to unlock"
469+msgid "Passphrase"
403msgstr ""
470msgstr ""
404
471
405−#: qml/Greeter/Greeter.qml:552
472+#: qml/Greeter/LoginList.qml:71
406−msgid "Enter passcode to unlock"
473+msgid "Passcode"
407msgstr ""
474msgstr ""
408
475
409−#: qml/Greeter/NarrowView.qml:235
476+#: qml/Greeter/LoginList.qml:98
410−msgid "Emergency"
477+msgid "Retry"
411msgstr ""
478msgstr ""
412
479
413−#: qml/Greeter/PromptList.qml:126
480+#: qml/Greeter/LoginList.qml:99
414−msgid "Passphrase"
481+msgid "Log In"
415msgstr ""
482msgstr ""
416
483
417−#: qml/Greeter/PromptList.qml:126
484+#: qml/Greeter/NarrowView.qml:252
418−msgid "Passcode"
485+msgid "Emergency"
419msgstr ""
486msgstr ""
420
487
421−#: qml/Greeter/SessionsList.qml:124
488+#: qml/Greeter/SessionsList.qml:122
422msgid "Select desktop environment"
489msgid "Select desktop environment"
423msgstr ""
490msgstr ""
424
491
425−#: qml/Launcher/Drawer.qml:250
492+#: qml/Launcher/Drawer.qml:80
426−#, fuzzy
427−#| msgid "Search"
428msgid "Search…"
493msgid "Search…"
429−msgstr "Axtar"
494+msgstr ""
430
495
431−#: qml/Launcher/PullToRefreshScopeStyle.qml:56
496+#: qml/Launcher/Drawer.qml:101
497+msgctxt "Apps sorted alphabetically"
432−msgid "Pull to refresh…"
498+msgid "A-Z"
433msgstr ""
499msgstr ""
434
500
435−#: qml/Launcher/PullToRefreshScopeStyle.qml:61
501+#: qml/Launcher/MoreAppsHeader.qml:32
436−msgid "Release to refresh…"
502+msgid "More apps in the store"
437msgstr ""
503msgstr ""
438
504
439#: qml/Notifications/NotificationMenuItemFactory.qml:124
505#: qml/Notifications/NotificationMenuItemFactory.qml:124
@@ -523,33 +589,23 @@ msgctxt "Button: Call back on phone"
523msgid "Call back"
589msgid "Call back"
524msgstr ""
590msgstr ""
525
591
526−#: qml/Panel/PanelMenuPage.qml:92
527−msgid "Back"
528−msgstr ""
529−
530#: qml/Stage/SideStage.qml:76
592#: qml/Stage/SideStage.qml:76
531msgid "Drag using 3 fingers any application from one window to the other"
593msgid "Drag using 3 fingers any application from one window to the other"
532msgstr ""
594msgstr ""
533
595
534−#: qml/Stage/Stage.qml:671
535−msgid "No running apps"
536−msgstr ""
537−
538#: qml/Tutorial/TutorialLeftLong.qml:49
596#: qml/Tutorial/TutorialLeftLong.qml:49
539−#, fuzzy
540−#| msgid "Try swiping from the top edge to access the indicators"
541−msgid "Long swipe from the left edge to open the Application Drawer"
597+msgid "Long swipe from the left edge to open the Today scope"
542−msgstr "Göstəriciləri görmәk üçün yuxarı küncdən sürüşdürün"
598+msgstr ""
543
599
544#: qml/Tutorial/TutorialLeft.qml:47
600#: qml/Tutorial/TutorialLeft.qml:47
545msgid "Short swipe from the left edge to open the launcher"
601msgid "Short swipe from the left edge to open the launcher"
546msgstr ""
602msgstr ""
547
603
548−#: qml/Tutorial/TutorialRight.qml:54
604+#: qml/Tutorial/TutorialRight.qml:55
549msgid "Push your mouse against the right edge to view your open apps"
605msgid "Push your mouse against the right edge to view your open apps"
550msgstr ""
606msgstr ""
551
607
552−#: qml/Tutorial/TutorialRight.qml:55
608+#: qml/Tutorial/TutorialRight.qml:56
553msgid "Swipe from the right edge to view your open apps"
609msgid "Swipe from the right edge to view your open apps"
554msgstr ""
610msgstr ""
555
611
@@ -557,42 +613,25 @@ msgstr ""
557msgid "Swipe from the top edge to access notifications and quick settings"
613msgid "Swipe from the top edge to access notifications and quick settings"
558msgstr ""
614msgstr ""
559
615
560−#: qml/Wizard/Page.qml:59
616+#: qml/Wizard/Page.qml:54
561msgctxt "Button: Go back one page in the Wizard"
617msgctxt "Button: Go back one page in the Wizard"
562msgid "Back"
618msgid "Back"
563msgstr ""
619msgstr ""
564
620
565−#: qml/Wizard/Pages/10-welcome.qml:29
621+#: qml/Wizard/Pages/10-welcome.qml:28
566msgid "Language"
622msgid "Language"
567msgstr ""
623msgstr ""
568
624
569−#: qml/Wizard/Pages/10-welcome.qml:176
625+#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
570−#: qml/Wizard/Pages/10-welcome-update.qml:126
626+#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
571−#: qml/Wizard/Pages/11-changelog.qml:74 qml/Wizard/Pages/20-keyboard.qml:152
572−#: qml/Wizard/Pages/30-wifi.qml:214 qml/Wizard/Pages/50-timezone.qml:272
627+#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
573−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/70-passwd-type.qml:146
628+#: qml/Wizard/Pages/70-passwd-type.qml:145
629+#: qml/Wizard/Pages/75-report-check.qml:84
574−#: qml/Wizard/Pages/passcode-desktop.qml:154
630+#: qml/Wizard/Pages/passcode-desktop.qml:142
575−#: qml/Wizard/Pages/password-set.qml:153
631+#: qml/Wizard/Pages/password-set.qml:142
576msgid "Next"
632msgid "Next"
577msgstr ""
633msgstr ""
578
634
579−#: qml/Wizard/Pages/10-welcome-update.qml:91
580−msgid "Welcome to "
581−msgstr ""
582−
583−#: qml/Wizard/Pages/10-welcome-update.qml:106
584−msgid "We will make sure your device is ready to use "
585−msgstr ""
586−
587−#: qml/Wizard/Pages/11-changelog.qml:28
588−msgid "What's new"
589−msgstr ""
590−
591−#: qml/Wizard/Pages/11-changelog.qml:74
592−#, fuzzy
593−msgid "Loading..."
594−msgstr "Danışır..."
595−
596#: qml/Wizard/Pages/20-keyboard.qml:31
635#: qml/Wizard/Pages/20-keyboard.qml:31
597msgid "Select Keyboard"
636msgid "Select Keyboard"
598msgstr ""
637msgstr ""
@@ -605,8 +644,8 @@ msgstr ""
605msgid "Keyboard layout"
644msgid "Keyboard layout"
606msgstr ""
645msgstr ""
607
646
608−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:214
647+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
609−#: qml/Wizard/Pages/60-account.qml:72 qml/Wizard/Pages/79-system-update.qml:144
648+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
610#: qml/Wizard/Pages/sim.qml:101
649#: qml/Wizard/Pages/sim.qml:101
611msgid "Skip"
650msgid "Skip"
612msgstr ""
651msgstr ""
@@ -615,23 +654,55 @@ msgstr ""
615msgid "Connect to Wi‑Fi"
654msgid "Connect to Wi‑Fi"
616msgstr ""
655msgstr ""
617
656
618−#: qml/Wizard/Pages/30-wifi.qml:139
657+#: qml/Wizard/Pages/30-wifi.qml:132
619msgid "Connected"
658msgid "Connected"
620msgstr ""
659msgstr ""
621
660
622−#: qml/Wizard/Pages/30-wifi.qml:172
661+#: qml/Wizard/Pages/30-wifi.qml:165
623msgid "Available Wi-Fi networks"
662msgid "Available Wi-Fi networks"
624msgstr ""
663msgstr ""
625
664
626−#: qml/Wizard/Pages/30-wifi.qml:173
665+#: qml/Wizard/Pages/30-wifi.qml:166
627msgid "No available Wi-Fi networks"
666msgid "No available Wi-Fi networks"
628msgstr ""
667msgstr ""
629
668
669+#: qml/Wizard/Pages/40-location.qml:27
670+msgid "Location Services"
671+msgstr ""
672+
673+#: qml/Wizard/Pages/40-location.qml:83
674+msgid ""
675+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
676+"(recommended)"
677+msgstr ""
678+
679+#: qml/Wizard/Pages/40-location.qml:105
680+#, qt-format
681+msgid "By selecting this option you agree to the Nokia HERE %1."
682+msgstr ""
683+
684+#: qml/Wizard/Pages/40-location.qml:106
685+msgctxt "part of: Nokia HERE terms and conditions"
686+msgid "terms and conditions"
687+msgstr ""
688+
689+#: qml/Wizard/Pages/40-location.qml:160
690+msgid "GPS only"
691+msgstr ""
692+
693+#: qml/Wizard/Pages/40-location.qml:214
694+msgid "Don't use my location"
695+msgstr ""
696+
697+#: qml/Wizard/Pages/40-location.qml:260
698+msgid "You can change it later in System Settings."
699+msgstr ""
700+
630#: qml/Wizard/Pages/50-timezone.qml:30
701#: qml/Wizard/Pages/50-timezone.qml:30
631msgid "Time Zone"
702msgid "Time Zone"
632msgstr ""
703msgstr ""
633
704
634−#: qml/Wizard/Pages/50-timezone.qml:183
705+#: qml/Wizard/Pages/50-timezone.qml:182
635msgid "Enter your city"
706msgid "Enter your city"
636msgstr ""
707msgstr ""
637
708
@@ -639,7 +710,7 @@ msgstr ""
639msgid "Personalize Your Device"
710msgid "Personalize Your Device"
640msgstr ""
711msgstr ""
641
712
642−#: qml/Wizard/Pages/60-account.qml:54
713+#: qml/Wizard/Pages/60-account.qml:48
643msgid "Preferred Name"
714msgid "Preferred Name"
644msgstr ""
715msgstr ""
645
716
@@ -647,72 +718,110 @@ msgstr ""
647msgid "Lock Screen"
718msgid "Lock Screen"
648msgstr ""
719msgstr ""
649
720
650−#: qml/Wizard/Pages/70-passwd-type.qml:103
721+#: qml/Wizard/Pages/70-passwd-type.qml:102
651msgctxt "Label: Type of security method"
722msgctxt "Label: Type of security method"
652msgid "Create new password"
723msgid "Create new password"
653msgstr ""
724msgstr ""
654
725
655−#: qml/Wizard/Pages/70-passwd-type.qml:105
726+#: qml/Wizard/Pages/70-passwd-type.qml:104
656msgctxt "Label: Type of security method"
727msgctxt "Label: Type of security method"
657msgid "Create passcode (numbers only)"
728msgid "Create passcode (numbers only)"
658msgstr ""
729msgstr ""
659
730
660−#: qml/Wizard/Pages/70-passwd-type.qml:107
731+#: qml/Wizard/Pages/70-passwd-type.qml:106
661msgctxt "Label: Type of security method"
732msgctxt "Label: Type of security method"
662msgid "No lock code"
733msgid "No lock code"
663msgstr ""
734msgstr ""
664
735
736+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
737+msgid "Privacy Policy"
738+msgstr ""
739+
740+#: qml/Wizard/Pages/75-report-check.qml:26
741+msgid "Help Us Improve"
742+msgstr ""
743+
744+#: qml/Wizard/Pages/75-report-check.qml:59
745+msgid "Improve system performance by sending us crashes and error reports."
746+msgstr ""
747+
748+#: qml/Wizard/Pages/75-report-check.qml:60
749+msgid "Privacy policy"
750+msgstr ""
751+
665−#: qml/Wizard/Pages/79-system-update.qml:28
752+#: qml/Wizard/Pages/77-system-update.qml:28
666msgid "Update Device"
753msgid "Update Device"
667msgstr ""
754msgstr ""
668
755
669−#: qml/Wizard/Pages/79-system-update.qml:55
756+#: qml/Wizard/Pages/77-system-update.qml:55
670msgid ""
757msgid ""
671"There is a system update available and ready to install. Afterwards, the "
758"There is a system update available and ready to install. Afterwards, the "
672"device will automatically restart."
759"device will automatically restart."
673msgstr ""
760msgstr ""
674
761
675−#: qml/Wizard/Pages/79-system-update.qml:76
762+#: qml/Wizard/Pages/77-system-update.qml:76
676msgctxt "string identifying name of the update"
763msgctxt "string identifying name of the update"
677−msgid "Ubuntu Touch system"
764+msgid "Ubuntu system"
678msgstr ""
765msgstr ""
679
766
680−#: qml/Wizard/Pages/79-system-update.qml:83
767+#: qml/Wizard/Pages/77-system-update.qml:83
681#, qt-format
768#, qt-format
682msgctxt "version of the system update"
769msgctxt "version of the system update"
683msgid "Version %1"
770msgid "Version %1"
684msgstr ""
771msgstr ""
685
772
686−#: qml/Wizard/Pages/79-system-update.qml:95
773+#: qml/Wizard/Pages/77-system-update.qml:102
687msgid "This could take a few minutes..."
774msgid "This could take a few minutes..."
688msgstr ""
775msgstr ""
689
776
690−#: qml/Wizard/Pages/79-system-update.qml:109
777+#: qml/Wizard/Pages/77-system-update.qml:116
691msgid "Install and restart now"
778msgid "Install and restart now"
692msgstr ""
779msgstr ""
693
780
694−#: qml/Wizard/Pages/80-finished.qml:91
781+#: qml/Wizard/Pages/80-finished.qml:89
695−msgid "Welcome Back"
696−msgstr ""
697−
698−#: qml/Wizard/Pages/80-finished.qml:91
699msgid "Welcome to Ubuntu"
782msgid "Welcome to Ubuntu"
700msgstr ""
783msgstr ""
701
784
702−#: qml/Wizard/Pages/80-finished.qml:106
785+#: qml/Wizard/Pages/80-finished.qml:104
703msgid "You are ready to use your device now"
786msgid "You are ready to use your device now"
704msgstr ""
787msgstr ""
705
788
706−#: qml/Wizard/Pages/80-finished.qml:126
789+#: qml/Wizard/Pages/80-finished.qml:124
707−msgid "Continue"
790+msgid "Get Started"
708msgstr ""
791msgstr ""
709
792
710−#: qml/Wizard/Pages/80-finished.qml:126
793+#: qml/Wizard/Pages/here-terms.qml:25
711−msgid "Get Started"
794+msgid "Terms & Conditions"
795+msgstr ""
796+
797+#: qml/Wizard/Pages/here-terms.qml:69
798+msgid "Your device uses positioning technologies provided by HERE."
799+msgstr ""
800+
801+#: qml/Wizard/Pages/here-terms.qml:81
802+msgid ""
803+"To provide you with positioning services and to improve their quality, HERE "
804+"collects information about nearby cell towers and Wi-Fi hotspots around your "
805+"current location whenever your position is being found."
806+msgstr ""
807+
808+#: qml/Wizard/Pages/here-terms.qml:93
809+msgid ""
810+"The information collected is used to analyze the service and to improve the "
811+"use of service, but not to identify you personally."
812+msgstr ""
813+
814+#: qml/Wizard/Pages/here-terms.qml:106
815+#, qt-format
816+msgid "By continuing, you agree to the HERE platform %1 and %2."
817+msgstr ""
818+
819+#: qml/Wizard/Pages/here-terms.qml:107
820+msgid "Service Terms"
712msgstr ""
821msgstr ""
713
822
714#: qml/Wizard/Pages/passcode-confirm.qml:43
823#: qml/Wizard/Pages/passcode-confirm.qml:43
715−#: qml/Wizard/Pages/passcode-desktop.qml:104
824+#: qml/Wizard/Pages/passcode-desktop.qml:97
716msgid "Confirm passcode"
825msgid "Confirm passcode"
717msgstr ""
826msgstr ""
718
827
@@ -729,24 +838,24 @@ msgstr ""
729msgid "Lock Screen Passcode"
838msgid "Lock Screen Passcode"
730msgstr ""
839msgstr ""
731
840
732−#: qml/Wizard/Pages/passcode-desktop.qml:68
841+#: qml/Wizard/Pages/passcode-desktop.qml:61
733msgid "Enter 4 numbers to setup your passcode"
842msgid "Enter 4 numbers to setup your passcode"
734msgstr ""
843msgstr ""
735
844
736−#: qml/Wizard/Pages/passcode-desktop.qml:84
845+#: qml/Wizard/Pages/passcode-desktop.qml:77
737#: qml/Wizard/Pages/passcode-set.qml:54
846#: qml/Wizard/Pages/passcode-set.qml:54
738msgid "Choose passcode"
847msgid "Choose passcode"
739msgstr ""
848msgstr ""
740
849
741−#: qml/Wizard/Pages/passcode-desktop.qml:139
850+#: qml/Wizard/Pages/passcode-desktop.qml:127
742msgid "Passcode too short"
851msgid "Passcode too short"
743msgstr ""
852msgstr ""
744
853
745−#: qml/Wizard/Pages/passcode-desktop.qml:141
854+#: qml/Wizard/Pages/passcode-desktop.qml:129
746msgid "Passcodes match"
855msgid "Passcodes match"
747msgstr ""
856msgstr ""
748
857
749−#: qml/Wizard/Pages/passcode-desktop.qml:143
858+#: qml/Wizard/Pages/passcode-desktop.qml:131
750msgid "Passcodes do not match"
859msgid "Passcodes do not match"
751msgstr ""
860msgstr ""
752
861
@@ -758,15 +867,15 @@ msgstr ""
758msgid "Lock Screen Password"
867msgid "Lock Screen Password"
759msgstr ""
868msgstr ""
760
869
761−#: qml/Wizard/Pages/password-set.qml:68
870+#: qml/Wizard/Pages/password-set.qml:62
762msgid "Enter at least 8 characters"
871msgid "Enter at least 8 characters"
763msgstr ""
872msgstr ""
764
873
765−#: qml/Wizard/Pages/password-set.qml:80
874+#: qml/Wizard/Pages/password-set.qml:74
766msgid "Choose password"
875msgid "Choose password"
767msgstr ""
876msgstr ""
768
877
769−#: qml/Wizard/Pages/password-set.qml:110
878+#: qml/Wizard/Pages/password-set.qml:104
770msgid "Confirm password"
879msgid "Confirm password"
771msgstr ""
880msgstr ""
772
881
@@ -822,42 +931,12 @@ msgstr ""
822msgid "Very weak password"
931msgid "Very weak password"
823msgstr ""
932msgstr ""
824
933
825−#~ msgid "Remove from Favorites"
826−#~ msgstr "Seçilmişlәrdәn çıxart"
827−
828−#~ msgid "Add to Favorites"
829−#~ msgstr "Seçilmişlәrә әlavә et"
830−
831−#~ msgid "More..."
832−#~ msgstr "Daha çox..."
833−
834−#~ msgid "Less..."
835−#~ msgstr "Az..."
836−
837−#~ msgid "Send"
838−#~ msgstr "Göndər"
839−
840−#~ msgid "Rate this"
841−#~ msgstr "Qiymәtlәndir"
842−
843−#~ msgid "Add a review"
844−#~ msgstr "Rəy yaz"
845−
846−#, fuzzy
847−#~ msgid "Please wait..."
848−#~ msgstr "Yüklənir. Zəhmət olmasa, gözləyin..."
849−
850−#, fuzzy
851−#~ msgid "Download"
852−#~ msgstr "Endirilir"
853−
854−#, fuzzy
855−#~ msgid "Downloaded"
856−#~ msgstr "Endirilir"
857−
858#~ msgid "Confirm"
934#~ msgid "Confirm"
859#~ msgstr "Təsdiqlə"
935#~ msgstr "Təsdiqlə"
860
936
937+#~ msgid "Search"
938+#~ msgstr "Axtar"
939+
861#~ msgid "Top edge"
940#~ msgid "Top edge"
862#~ msgstr "Yuxarı künc"
941#~ msgstr "Yuxarı künc"
863
942
@@ -873,6 +952,12 @@ msgstr ""
873#~ msgid "Right edge"
952#~ msgid "Right edge"
874#~ msgstr "Sağ Künc"
953#~ msgstr "Sağ Künc"
875
954
955+#~ msgid "Speaking..."
956+#~ msgstr "Danışır..."
957+
958+#~ msgid "Loading. Please Wait..."
959+#~ msgstr "Yüklənir. Zəhmət olmasa, gözləyin..."
960+
876#~ msgid "Speak Now..."
961#~ msgid "Speak Now..."
877#~ msgstr "Danışın..."
962#~ msgstr "Danışın..."
878
963
@@ -908,18 +993,18 @@ msgstr ""
908#~ msgstr "Bu sizin son cəhdiniz olacaq."
993#~ msgstr "Bu sizin son cəhdiniz olacaq."
909
994
910#~ msgid ""
995#~ msgid ""
911−#~ "If passcode is entered incorrectly, your phone will conduct a factory "
996+#~ "If passcode is entered incorrectly, your phone will conduct a factory reset "
912−#~ "reset and all personal data will be deleted."
997+#~ "and all personal data will be deleted."
913#~ msgstr ""
998#~ msgstr ""
914−#~ "Əgər açar kod yanlış daxil edilibsə, onda telefonunuz fabrika "
999+#~ "Əgər açar kod yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
915−#~ "parametrlərinə geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
1000+#~ "geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
916
1001
917#~ msgid ""
1002#~ msgid ""
918#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
1003#~ "If passphrase is entered incorrectly, your phone will conduct a factory "
919#~ "reset and all personal data will be deleted."
1004#~ "reset and all personal data will be deleted."
920#~ msgstr ""
1005#~ msgstr ""
921−#~ "Əgər açar söz yanlış daxil edilibsə, onda telefonunuz fabrika "
1006+#~ "Əgər açar söz yanlış daxil edilibsə, onda telefonunuz fabrika parametrlərinə "
922−#~ "parametrlərinə geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
1007+#~ "geri qayıdacaq və bütün şəxsi məlumatlarınız silinəcək."
923
1008
924#~ msgid "Log out"
1009#~ msgid "Log out"
925#~ msgstr "Çıxış"
1010#~ msgstr "Çıxış"
@@ -933,6 +1018,9 @@ msgstr ""
933#~ msgid "Reboot"
1018#~ msgid "Reboot"
934#~ msgstr "Yenidən yüklə"
1019#~ msgstr "Yenidən yüklə"
935
1020
1021+#~ msgid "Try swiping from the top edge to access the indicators"
1022+#~ msgstr "Göstəriciləri görmәk üçün yuxarı küncdən sürüşdürün"
1023+
936#~ msgid "Skip intro"
1024#~ msgid "Skip intro"
937#~ msgstr "Tәqdimatı keç"
1025#~ msgstr "Tәqdimatı keç"
938
1026
@@ -961,6 +1049,7 @@ msgstr ""
961#~ msgid "Sorry, incorrect passphrase"
1049#~ msgid "Sorry, incorrect passphrase"
962#~ msgstr "Bağışlayın, açar söz yanlışdır"
1050#~ msgstr "Bağışlayın, açar söz yanlışdır"
963
1051
1052+#, qt-format
964#~ msgid "Sorry, incorrect %1"
1053#~ msgid "Sorry, incorrect %1"
965#~ msgstr "Bağışlayın, %1 yanlışdır"
1054#~ msgstr "Bağışlayın, %1 yanlışdır"
966
1055
po/be.po+492−443

This diff is too big to show here.

po/bg.po+322−215

This diff is too big to show here.

po/bn.po+478−418

This diff is too big to show here.

po/br.po+362−385

This diff is too big to show here.

po/bs.po+344−288

This diff is too big to show here.

po/ca.po+387−469

This diff is too big to show here.

po/ca@valencia.po+349−272

This diff is too big to show here.

po/ce.po+305−189

This diff is too big to show here.

po/ckb.po+319−209

This diff is too big to show here.

po/co.po+335−355

This diff is too big to show here.

po/cs.po+493−537

This diff is too big to show here.

po/cy.po+343−288

This diff is too big to show here.

po/da.po+418−364

This diff is too big to show here.

po/de.po+390−472

This diff is too big to show here.

po/el.po+450−445

This diff is too big to show here.

po/en_AU.po+419−524

This diff is too big to show here.

po/en_GB.po+359−420

This diff is too big to show here.

po/en_US.podeleted−814

This diff is too big to show here.

po/eo.po+331−253

This diff is too big to show here.

po/es.po+400−481

This diff is too big to show here.

po/et.po+305−189

This diff is too big to show here.

po/eu.po+352−293

This diff is too big to show here.

po/fa.po+383−489

This diff is too big to show here.

po/fi.po+372−454

This diff is too big to show here.

po/fo.po+327−263

This diff is too big to show here.

po/fr.po+430−513

This diff is too big to show here.

po/ga.po+342−281

This diff is too big to show here.

po/gd.po+375−436

This diff is too big to show here.

po/gl.po+387−470

This diff is too big to show here.

po/gu.podeleted−814

This diff is too big to show here.

po/gv.po+319−229

This diff is too big to show here.

po/he.po+473−414

This diff is too big to show here.

po/hi.po+315−203

This diff is too big to show here.

po/hr.po+401−434

This diff is too big to show here.

po/hu.po+401−479

This diff is too big to show here.

po/hy.po+414−319

This diff is too big to show here.

po/ia.po+364−427

This diff is too big to show here.

po/id.po+347−271

This diff is too big to show here.

po/is.po+342−250

This diff is too big to show here.

po/it.po+397−479

This diff is too big to show here.

po/ja.po+398−323

This diff is too big to show here.

po/kk.podeleted−841

This diff is too big to show here.

po/km.po+346−285

This diff is too big to show here.

po/kn.po+315−197

This diff is too big to show here.

po/ko.po+467−427

This diff is too big to show here.

po/ku.po+324−236

This diff is too big to show here.

po/ky.po+315−197

This diff is too big to show here.

po/lo.po+312−196

This diff is too big to show here.

po/lt.po+426−476

This diff is too big to show here.

po/lv.po+359−301

This diff is too big to show here.

po/ml.po+321−210

This diff is too big to show here.

po/mr.po+310−212

This diff is too big to show here.

po/ms.po+433−448

This diff is too big to show here.

po/my.po+320−247

This diff is too big to show here.

po/nb.po+376−456

This diff is too big to show here.

po/ne.po+306−193

This diff is too big to show here.

po/nl.po+463−542

This diff is too big to show here.

po/nn.po+305−189

This diff is too big to show here.

po/oc.po+346−381

This diff is too big to show here.

po/or.po+305−189

This diff is too big to show here.

po/pa.po+355−297

This diff is too big to show here.

po/pl.po+403−484

This diff is too big to show here.

po/pt.po+393−474

This diff is too big to show here.

po/pt_BR.po+452−408

This diff is too big to show here.

po/ro.po+363−303

This diff is too big to show here.

po/ru.po+389−477

This diff is too big to show here.

po/sc.podeleted−904

This diff is too big to show here.

po/shn.po+305−189

This diff is too big to show here.

po/si.po+324−215

This diff is too big to show here.

po/sk.po+384−467

This diff is too big to show here.

po/sl.po+363−413

This diff is too big to show here.

po/sq.po+329−279

This diff is too big to show here.

po/sr.po+367−428

This diff is too big to show here.

po/sv.po+371−451

This diff is too big to show here.

po/sw.po+336−266

This diff is too big to show here.

po/ta.po+320−209

This diff is too big to show here.

po/te.po+319−217

This diff is too big to show here.

po/th.po+324−209

This diff is too big to show here.

po/tr.po+372−485

This diff is too big to show here.

po/ug.po+360−341

This diff is too big to show here.

po/uk.po+375−433

This diff is too big to show here.

po/unity8.pot+302−185

This diff is too big to show here.

po/update-unity-pot−17

This diff is too big to show here.

po/ur.po+323−210

This diff is too big to show here.

po/uz.po+305−189

This diff is too big to show here.

po/vi.po+305−189

This diff is too big to show here.

po/wo.po+356−297

This diff is too big to show here.

po/xh.po+305−189

This diff is too big to show here.

po/zh_CN.po+384−466

This diff is too big to show here.

po/zh_HK.po+320−226

This diff is too big to show here.

po/zh_TW.po+433−475

This diff is too big to show here.

qml/ApplicationMenus/ApplicationMenuItemFactory.qml+7−7

This diff is too big to show here.

qml/ApplicationMenus/MenuBar.qml+134−343

This diff is too big to show here.

qml/ApplicationMenus/MenuItem.qml+21−17

This diff is too big to show here.

qml/ApplicationMenus/MenuNavigator.qml−23

This diff is too big to show here.

qml/ApplicationMenus/MenuPopup.qml+135−284

This diff is too big to show here.

qml/ApplicationMenus/RegisteredApplicationMenuModel.qml+1−1

This diff is too big to show here.

qml/ApplicationMenus/qmldirdeleted−1

This diff is too big to show here.

qml/CMakeLists.txt+1

This diff is too big to show here.

qml/Components/Background.qml+1−1

This diff is too big to show here.

qml/Components/BaseCarouselDelegate.qmlnew file+42

This diff is too big to show here.

qml/Components/Carousel.qmlnew file+335

This diff is too big to show here.

qml/Components/Dialogs.qml+27−90

This diff is too big to show here.

qml/Components/EdgeBarrier.qml−1

This diff is too big to show here.

qml/Components/EdgeBarrierController.qml−1

This diff is too big to show here.

qml/Components/InputMethod.qml+1−2

This diff is too big to show here.

qml/Components/ItemGrabber.qml+1−1

This diff is too big to show here.

qml/Components/KeyboardShortcutsOverlay.qml+28−17

This diff is too big to show here.

qml/Components/KeymapSwitcher.qml+7−15

This diff is too big to show here.

qml/Components/Lockscreen.qml+1−5

This diff is too big to show here.

qml/Components/ModeSwitchWarningDialog.qml+2−8

This diff is too big to show here.

qml/Components/PhysicalKeysMapper.qml+4−4

This diff is too big to show here.

qml/Components/ResponsiveGridView.qmlnew file+98

This diff is too big to show here.

qml/Components/ResponsiveVerticalJournal.qmlnew file+81

This diff is too big to show here.

qml/Components/ShellDialog.qml+12−27

This diff is too big to show here.

qml/Components/Showable.qml+12−15

This diff is too big to show here.

qml/Components/Wallpaper.qml+16−68

This diff is too big to show here.

qml/Components/WallpaperResolver.qml+6−17

This diff is too big to show here.

qml/Components/WindowControlButtons.qml+21−2

This diff is too big to show here.

qml/Dash/CardCarousel.qmlnew file+74

This diff is too big to show here.

qml/Dash/CardGrid.qmlnew file+84

This diff is too big to show here.

qml/Dash/CardHorizontalList.qmlnew file+66

This diff is too big to show here.

qml/Dash/CardTool.qmlnew file+274

This diff is too big to show here.

qml/Dash/CardVerticalJournal.qmlnew file+85

This diff is too big to show here.

qml/Dash/Dash.qmlnew file+381

This diff is too big to show here.

tests/mocks/Unity/Application/resources/KateMenu.qml → qml/Dash/DashApplication.qmlrenamed+15−17

This diff is too big to show here.

plugins/WindowManager/WindowManagerGlobal.h → qml/Dash/DashBackground.qmlrenamed+5−7

This diff is too big to show here.

qml/Dash/DashCategoryBase.qmlnew file+54

This diff is too big to show here.

qml/Dash/DashContent.qmlnew file+211

This diff is too big to show here.

qml/Dash/DashContentTabBarStyle.qmlnew file+24

This diff is too big to show here.

qml/Dash/DashNavigation.qmlnew file+199

This diff is too big to show here.

qml/Dash/DashNavigationHeader.qmlnew file+73

This diff is too big to show here.

qml/Dash/DashNavigationList.qmlnew file+118

This diff is too big to show here.

qml/Dash/DashPageHeader.qmlnew file+448

This diff is too big to show here.

qml/Dash/DashRenderer.qmlnew file+66

This diff is too big to show here.

qml/Dash/DashSectionHeader.qmlnew file+64

This diff is too big to show here.

qml/Dash/Filters/FilterExpandableWidget.qmlnew file+97

This diff is too big to show here.

qml/Dash/Filters/FilterOptionSelector.qmlnew file+97

This diff is too big to show here.

qml/Dash/Filters/FilterRangeInput.qmlnew file+136

This diff is too big to show here.

qml/Dash/Filters/FilterValueSlider.qmlnew file+87

This diff is too big to show here.

qml/Dash/Filters/FilterWidget.qmlnew file+32

This diff is too big to show here.

qml/Dash/Filters/FilterWidgetFactory.qmlnew file+89

This diff is too big to show here.

qml/Dash/FiltersPopover.qmlnew file+106

This diff is too big to show here.

qml/Dash/GenericScopeView.qmlnew file+797

This diff is too big to show here.

qml/Dash/PageHeaderExtraPanel.qmlnew file+201

This diff is too big to show here.

qml/Dash/PreviewView.qmlnew file+76

This diff is too big to show here.

qml/Dash/Previews/Preview.qmlnew file+145

This diff is too big to show here.

qml/Dash/Previews/PreviewActionButton.qmlnew file+27

This diff is too big to show here.

qml/Dash/Previews/PreviewActionCombo.qmlnew file+79

This diff is too big to show here.

qml/Dash/Previews/PreviewActions.qmlnew file+73

This diff is too big to show here.

qml/Dash/Previews/PreviewAudioPlayback.qmlnew file+152

This diff is too big to show here.

qml/Dash/Previews/PreviewComment.qmlnew file+86

This diff is too big to show here.

qml/Dash/Previews/PreviewCommentInput.qmlnew file+88

This diff is too big to show here.

qml/Dash/Previews/PreviewExpandable.qmlnew file+104

This diff is too big to show here.

qml/Dash/Previews/PreviewHeader.qmlnew file+170

This diff is too big to show here.

qml/Dash/Previews/PreviewIconActions.qmlnew file+88

This diff is too big to show here.

qml/Dash/Previews/PreviewImageGallery.qmlnew file+150

This diff is too big to show here.

qml/Dash/Previews/PreviewInlineVideo.qmlnew file+112

This diff is too big to show here.

qml/Dash/Previews/PreviewMediaToolbar.qmlnew file+57

This diff is too big to show here.

qml/Dash/Previews/PreviewOverlay.qmlnew file+166

This diff is too big to show here.

qml/Dash/Previews/PreviewProgress.qmlnew file+74

This diff is too big to show here.

qml/Dash/Previews/PreviewRatingDisplay.qmlnew file+117

This diff is too big to show here.

qml/Dash/Previews/PreviewRatingEdit.qmlnew file+83

This diff is too big to show here.

qml/Dash/Previews/PreviewRatingInput.qmlnew file+207

This diff is too big to show here.

qml/Dash/Previews/PreviewRatingSingleDisplay.qmlnew file+73

This diff is too big to show here.

qml/ApplicationMenus/ApplicationMenusLimits.qml → qml/Dash/Previews/PreviewSingleton/PreviewSingleton.qmlrenamed+3−5

This diff is too big to show here.

qml/Dash/Previews/PreviewSingleton/qmldirnew file+1

This diff is too big to show here.

qml/Dash/Previews/PreviewTable.qmlnew file+91

This diff is too big to show here.

qml/Dash/Previews/PreviewTextSummary.qmlnew file+78

This diff is too big to show here.

qml/Dash/Previews/PreviewVideoPlayback.qmlnew file+87

This diff is too big to show here.

qml/Dash/Previews/PreviewWidget.qmlnew file+60

This diff is too big to show here.

qml/Dash/Previews/PreviewWidgetFactory.qmlnew file+101

This diff is too big to show here.

qml/Dash/Previews/PreviewZoomableImage.qmlnew file+103

This diff is too big to show here.

qml/Launcher/PullToRefreshScopeStyle.qml → qml/Dash/PullToRefreshScopeStyle.qmlrenamed

The content is the same.

qml/Dash/ScopeListView.qmlnew file+28

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSetting.qmlnew file+46

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSettingBoolean.qmlnew file+63

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSettingList.qmlnew file+50

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSettingNumber.qmlnew file+21

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSettingString.qmlnew file+89

This diff is too big to show here.

qml/Dash/ScopeSettings/ScopeSettingsWidgetFactory.qmlnew file+61

This diff is too big to show here.

qml/Dash/ScopeSettingsPage.qmlnew file+72

This diff is too big to show here.

qml/Dash/ScopesList.qmlnew file+206

This diff is too big to show here.

qml/Dash/ScopesListCategory.qmlnew file+184

This diff is too big to show here.

qml/Dash/ScopesListCategoryItem.qmlnew file+113

This diff is too big to show here.

qml/Dash/graphics/dark_background.jpgnew file

Binary file not shown.

qml/Dash/graphics/header_handlearrow2@27.pngnew file

Binary file not shown.

qml/Dash/graphics/header_handlearrow@27.pngnew file

Binary file not shown.

qml/Dash/graphics/icon_clear@20.pngnew file

Binary file not shown.

qml/Dash/graphics/icon_search_active@20.pngnew file

Binary file not shown.

qml/Dash/graphics/icon_search_inactive@20.pngnew file

Binary file not shown.

qml/Dash/graphics/overview_hint@30.pngnew file

Binary file not shown.

qml/Dash/graphics/pixel.pngnew file

Binary file not shown.

qml/Dash/graphics/play_button@18.pngnew file

Binary file not shown.

qml/Dash/graphics/play_button_active@18.pngnew file

Binary file not shown.

qml/Dash/graphics/play_button_active_big@20.pngnew file

Binary file not shown.

qml/Dash/graphics/play_button_big@20.pngnew file

Binary file not shown.

qml/Dash/graphics/rectangular_dropshadow@30.pngnew file

Binary file not shown.

qml/Dash/graphics/rectangular_dropshadow@30.scinew file+5

This diff is too big to show here.

qml/Dash/graphics/tabbarchevron@27.pngnew file

Binary file not shown.

qml/Dash/graphics/tablet/icon_close_preview@20.pngnew file

Binary file not shown.

qml/Dash/graphics/tooltip_arrow@27.pngnew file

Binary file not shown.

qml/DeviceConfiguration.qml−12

This diff is too big to show here.

qml/Greeter/ButtonPrompt.qmldeleted−51

This diff is too big to show here.

qml/Greeter/Circle.qml+1−1

This diff is too big to show here.

qml/Greeter/CoverPage.qml+11−32

This diff is too big to show here.

qml/Greeter/FullLightDMImpl.qml−1

This diff is too big to show here.

qml/Greeter/Greeter.qml+73−78

This diff is too big to show here.

qml/Greeter/GreeterPrompt.qml+167−66

This diff is too big to show here.

qml/Greeter/GreeterView.qmldeleted−534

This diff is too big to show here.

qml/Greeter/IntegratedLightDMImpl.qml−1

This diff is too big to show here.

qml/Greeter/LightDMService.qml+4−4

This diff is too big to show here.

qml/Greeter/LoginAreaContainer.qml+3−3

This diff is too big to show here.

qml/Greeter/LoginList.qml+190−110

This diff is too big to show here.

qml/Greeter/NarrowView.qmlnew file+287

This diff is too big to show here.

qml/Greeter/PinPrompt.qmldeleted−184

This diff is too big to show here.

qml/Greeter/PromptList.qmldeleted−151

This diff is too big to show here.

qml/Greeter/SessionsList.qml+18−36

This diff is too big to show here.

qml/Greeter/ShimGreeter.qml−2

This diff is too big to show here.

qml/Greeter/TextPrompt.qmldeleted−198

This diff is too big to show here.

qml/Greeter/WideView.qmlnew file+218

This diff is too big to show here.

qml/Launcher/Drawer.qml+179−286

This diff is too big to show here.

qml/Launcher/DrawerGridView.qml+6−44

This diff is too big to show here.

tests/mocks/Ubuntu/SystemSettings/Update/MockSystemImage.qml → qml/Launcher/DrawerListView.qmlrenamed+13−11

This diff is too big to show here.

qml/Launcher/Launcher.qml+52−95

This diff is too big to show here.

qml/Launcher/LauncherDelegate.qml+12−9

This diff is too big to show here.

qml/Launcher/LauncherPanel.qml+22−61

This diff is too big to show here.

qml/Launcher/MoreAppsHeader.qmlnew file+46

This diff is too big to show here.

qml/Launcher/graphics/home.svgdeleted−243

This diff is too big to show here.

qml/Launcher/graphics/home@18.pngnew file

Binary file not shown.

qml/Launcher/graphics/launcher-app-focus-ring.svgnew file+12

This diff is too big to show here.

qml/Notifications/Notification.qml+3−8

This diff is too big to show here.

qml/Notifications/NotificationButton.qml+1−2

This diff is too big to show here.

qml/Notifications/SwipeToAct.qml−4

This diff is too big to show here.

qml/OrientedShell.qml+7−20

This diff is too big to show here.

qml/Panel/ActiveCallHint.qml−3

This diff is too big to show here.

qml/Components/Handle.qml → qml/Panel/Handle.qmlrenamed−1

This diff is too big to show here.

qml/Panel/Indicators/IndicatorItem.qml+2−14

This diff is too big to show here.

qml/Panel/Indicators/IndicatorMenuItemFactory.qml+3−3

This diff is too big to show here.

qml/Panel/Indicators/IndicatorsLight.qml+12−185

This diff is too big to show here.

qml/Panel/Indicators/client/IndicatorRepresentation.qml+5−18

This diff is too big to show here.

qml/Panel/MenuContent.qml+2−5

This diff is too big to show here.

qml/Panel/Panel.qml+30−103

This diff is too big to show here.

qml/Panel/PanelBar.qml+10−28

This diff is too big to show here.

qml/Panel/PanelItemRow.qml+33−41

This diff is too big to show here.

qml/Panel/PanelMenu.qml+29−61

This diff is too big to show here.

qml/Panel/PanelMenuPage.qml+3−4

This diff is too big to show here.

qml/Rotation/RotationStates.qml+3

This diff is too big to show here.

qml/ScopeTool.qmlnew file+165

This diff is too big to show here.

qml/Shell.qml+69−215

This diff is too big to show here.

qml/Stage/AbstractStage.qmlnew file+93

This diff is too big to show here.

qml/Stage/ApplicationWindow.qml+4−16

This diff is too big to show here.

qml/Stage/ChildWindow.qmldeleted−203

This diff is too big to show here.

qml/Stage/ChildWindowRepeater.qmldeleted−39

This diff is too big to show here.

qml/Stage/ChildWindowTree.qmldeleted−138

This diff is too big to show here.

qml/Stage/DecoratedWindow.qml+53−64

This diff is too big to show here.

qml/Stage/DesktopSpread.qmlnew file+576

This diff is too big to show here.

qml/Stage/DesktopSpreadDelegate.qmlnew file+126

This diff is too big to show here.

qml/Stage/MoveHandler.qml+30−43

This diff is too big to show here.

qml/Stage/PhoneStage.qmlnew file+806

This diff is too big to show here.

qml/Stage/SideStage.qml+6−10

This diff is too big to show here.

qml/Stage/Splash.qml+4−4

This diff is too big to show here.

qml/Stage/Spread/Spread.qml−11

This diff is too big to show here.

qml/Stage/SpreadDelegate.qmlnew file+424

This diff is too big to show here.

qml/Stage/SpreadMaths.qmlnew file+164

This diff is too big to show here.

qml/Stage/Stage.qml+150−404

This diff is too big to show here.

qml/Stage/StageMaths.qml+2−21

This diff is too big to show here.

qml/Stage/StagedFullscreenPolicy.qml+11−5

This diff is too big to show here.

qml/Stage/TabletStage.qmlnew file+1201

This diff is too big to show here.

qml/Stage/TransformedSpreadDelegate.qmlnew file+391

This diff is too big to show here.

qml/Stage/TransformedTabletSpreadDelegate.qmlnew file+437

This diff is too big to show here.

qml/Stage/WindowControlsOverlay.qml+24−21

This diff is too big to show here.

qml/Stage/WindowDecoration.qml+16−19

This diff is too big to show here.

qml/Stage/WindowInfoItem.qml−16

This diff is too big to show here.

qml/Stage/WindowResizeArea.qml+2−15

This diff is too big to show here.

qml/Stage/WindowStateSaver.qml+3−4

This diff is too big to show here.

qml/Stage/WindowedFullscreenPolicy.qml+12−4

This diff is too big to show here.

qml/Tutorial/Tutorial.qml−1

This diff is too big to show here.

qml/Tutorial/TutorialContent.qml+43−61

This diff is too big to show here.

qml/Tutorial/TutorialLeft.qml+1−1

This diff is too big to show here.

qml/Tutorial/TutorialLeftLong.qml+2−2

This diff is too big to show here.

qml/Tutorial/TutorialRight.qml+3−2

This diff is too big to show here.

qml/Tutorial/TutorialTop.qml+2−2

This diff is too big to show here.

qml/Wizard/Components/InputMethod.qml+9−9

This diff is too big to show here.

qml/Wizard/Page.qml−15

This diff is too big to show here.

qml/Wizard/Pages.qml+16−90

This diff is too big to show here.

qml/Wizard/Pages/10-welcome-update.qmldeleted−137

This diff is too big to show here.

qml/Wizard/Pages/10-welcome.qml−3

This diff is too big to show here.

qml/Wizard/Pages/11-changelog.qmldeleted−95

This diff is too big to show here.

qml/Wizard/Pages/30-wifi.qml+10−13

This diff is too big to show here.

qml/Wizard/Pages/40-location.qmlnew file+290

This diff is too big to show here.

qml/Wizard/Pages/50-timezone.qml+12−11

This diff is too big to show here.

qml/Wizard/Pages/60-account.qml+10−12

This diff is too big to show here.

qml/Wizard/Pages/70-passwd-type.qml−1

This diff is too big to show here.

qml/Wizard/Pages/75-report-check.qmlnew file+91

This diff is too big to show here.

qml/Wizard/Pages/79-system-update.qml → qml/Wizard/Pages/77-system-update.qmlrenamed+12−4

This diff is too big to show here.

qml/Wizard/Pages/78-firmware-update.qml.disableddeleted−246

This diff is too big to show here.

qml/Wizard/Pages/80-finished.qml+2−4

This diff is too big to show here.

qml/Wizard/Pages/here-terms.qmlnew file+126

This diff is too big to show here.

qml/Wizard/Pages/passcode-desktop.qml+5−14

This diff is too big to show here.

qml/Wizard/Pages/password-set.qml+4−12

This diff is too big to show here.

qml/Wizard/Wizard.qml+2−5

This diff is too big to show here.

src/ApplicationArguments.h−5

This diff is too big to show here.

src/CMakeLists.txt+5−7

This diff is too big to show here.

src/Dash/CMakeLists.txtnew file+29

This diff is too big to show here.

src/Dash/main.cppnew file+146

This diff is too big to show here.

src/MouseTouchAdaptor.cpp+1−28

This diff is too big to show here.

src/MouseTouchAdaptor.h−1

This diff is too big to show here.

src/Panel/CMakeLists.txtnew file+3

This diff is too big to show here.

src/Panel/Indicators/CMakeLists.txtnew file+1

This diff is too big to show here.

tools/indicatorsclient/CMakeLists.txt → src/Panel/Indicators/client/CMakeLists.txtrenamed+1−1

This diff is too big to show here.

tools/indicatorsclient/indicatorsclient.cpp → src/Panel/Indicators/client/indicatorsclient.cpprenamed

The content is the same.

tools/indicatorsclient/indicatorsclient.h → src/Panel/Indicators/client/indicatorsclient.hrenamed

The content is the same.

tools/indicatorsclient/main.cpp → src/Panel/Indicators/client/main.cpprenamed

The content is the same.

src/ShellApplication.cpp+4−19

This diff is too big to show here.

src/ShellApplication.h+3−1

This diff is too big to show here.

src/ShellView.cpp−22

This diff is too big to show here.

src/libunity8-private/CMakeLists.txt+1−1

This diff is too big to show here.

src/main.cpp+1−9

This diff is too big to show here.

tests/CMakeLists.txt+5−16

This diff is too big to show here.

tests/autopilot/unity8/dash.pynew file+247

This diff is too big to show here.

tests/autopilot/unity8/fixture_setup.py+1−1

This diff is too big to show here.

tests/autopilot/unity8/shell/fixture_setup.py+27−1

This diff is too big to show here.

tests/autopilot/unity8/shell/tests/__init__.py+1−1

This diff is too big to show here.

tests/autopilot/unity8/shell/tests/test_helpers.py+74

This diff is too big to show here.

tests/autopilot/unity8/shell/tests/test_rotation.py+3−3

This diff is too big to show here.

tests/copyright/check_copyright.sh+4−35

This diff is too big to show here.

tests/data/unity/backgrounds/20x30.pngdeleted

Binary file not shown.

tests/data/unity/backgrounds/black.pngdeleted

Binary file not shown.

tests/imports/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/AccountsService/AccountsService.cpp+39−2

This diff is too big to show here.

tests/mocks/AccountsService/AccountsService.h+26−3

This diff is too big to show here.

tests/mocks/AccountsService/CMakeLists.txt+4−4

This diff is too big to show here.

tests/mocks/Biometryd/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Biometryd/MockOperation.h+1

This diff is too big to show here.

tests/mocks/CMakeLists.txt+2−3

This diff is too big to show here.

tests/mocks/GSettings.1.0/CMakeLists.txt+2−1

This diff is too big to show here.

tests/mocks/GSettings.1.0/fake_gsettings.cpp+27−25

This diff is too big to show here.

tests/mocks/GSettings.1.0/fake_gsettings.h+9−9

This diff is too big to show here.

tests/mocks/LightDM/CMakeLists.txtnew file+1

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txtnew file+50

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockGreeter.cppnew file+51

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockGreeter.hnew file+42

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.cppnew file+66

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.hnew file+44

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockUsersModel.cppnew file+44

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/MockUsersModel.hnew file+39

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/QLightDM/Greeternew file+17

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/QLightDM/SessionsModelnew file+17

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/QLightDM/UsersModelnew file+17

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txtnew file+21

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.cppnew file+201

This diff is too big to show here.

tests/mocks/liblightdm/MockGreeter.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.hrenamed+21−8

This diff is too big to show here.

tests/mocks/liblightdm/GreeterPrivate.cpp → tests/mocks/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.cpprenamed

The content is the same.

tests/mocks/liblightdm/GreeterPrivate.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/GreeterPrivate.hrenamed

The content is the same.

tests/mocks/liblightdm/MockSessionsModel.cpp → tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpprenamed+42−40

This diff is too big to show here.

tests/mocks/liblightdm/MockSessionsModel.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.hrenamed+17−9

This diff is too big to show here.

tests/mocks/liblightdm/SessionsModelPrivate.cpp → tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpprenamed

The content is the same.

tests/mocks/liblightdm/SessionsModelPrivate.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.hrenamed

The content is the same.

tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModel.cppnew file+121

This diff is too big to show here.

tests/mocks/liblightdm/MockUsersModel.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModel.hrenamed+16−8

This diff is too big to show here.

tests/mocks/liblightdm/UsersModelPrivate.cpp → tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpprenamed

The content is the same.

tests/mocks/liblightdm/UsersModelPrivate.h → tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.hrenamed

The content is the same.

tests/mocks/LightDM/IntegratedLightDM/plugin.cppnew file+79

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/plugin.hnew file+32

This diff is too big to show here.

tests/mocks/LightDM/IntegratedLightDM/qmldirnew file+2

This diff is too big to show here.

tests/mocks/LightDMController/CMakeLists.txtdeleted−14

This diff is too big to show here.

tests/mocks/LightDMController/qmldirdeleted−2

This diff is too big to show here.

tests/mocks/Lights/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/MeeGo/QOfono/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Powerd/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/QMenuModel/CMakeLists.txt+2−1

This diff is too big to show here.

tests/mocks/QMenuModel/unitymenumodel.cpp+4−28

This diff is too big to show here.

tests/mocks/QMenuModel/unitymenumodel.h−9

This diff is too big to show here.

tests/mocks/QtMultimedia/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/SessionBroadcast/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/UInput/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Ubuntu/CMakeLists.txt+1

This diff is too big to show here.

tests/mocks/Ubuntu/Connectivity/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Ubuntu/Connectivity/networking-status.cpp+1−7

This diff is too big to show here.

tests/mocks/Ubuntu/Connectivity/networking-status.h+3−5

This diff is too big to show here.

tests/mocks/Ubuntu/DownloadDaemonListener/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Ubuntu/SystemImage/CMakeLists.txtnew file+10

This diff is too big to show here.

tests/mocks/Ubuntu/SystemImage/MockSystemImage.cppnew file+50

This diff is too big to show here.

tests/mocks/Ubuntu/SystemImage/MockSystemImage.hnew file+56

This diff is too big to show here.

tests/mocks/Ubuntu/SystemImage/plugin.cppnew file+34

This diff is too big to show here.

tests/mocks/LightDMController/plugin.h → tests/mocks/Ubuntu/SystemImage/plugin.hrenamed+6−4

This diff is too big to show here.

tests/mocks/Ubuntu/SystemImage/qmldirnew file+3

This diff is too big to show here.

tests/mocks/Ubuntu/SystemSettings/CMakeLists.txt−1

This diff is too big to show here.

tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Ubuntu/SystemSettings/Update/CMakeLists.txtdeleted−1

This diff is too big to show here.

tests/mocks/Ubuntu/SystemSettings/Update/qmldirdeleted−2

This diff is too big to show here.

tests/mocks/Ubuntu/Telephony/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/Application/ApplicationInfo.cpp+5−16

This diff is too big to show here.

tests/mocks/Unity/Application/ApplicationInfo.h+6−5

This diff is too big to show here.

tests/mocks/Unity/Application/ApplicationManager.cpp+8−29

This diff is too big to show here.

tests/mocks/Unity/Application/ApplicationManager.h+6−1

This diff is too big to show here.

tests/mocks/Unity/Application/CMakeLists.txt+2−2

This diff is too big to show here.

tests/mocks/Unity/Application/MirMock.cpp−13

This diff is too big to show here.

tests/mocks/Unity/Application/MirMock.h−4

This diff is too big to show here.

tests/mocks/Unity/Application/MirSurface.cpp−52

This diff is too big to show here.

tests/mocks/Unity/Application/MirSurface.h−16

This diff is too big to show here.

tests/mocks/Unity/Application/MirSurfaceItem.cpp+4−19

This diff is too big to show here.

tests/mocks/Unity/Application/MirSurfaceListModel.cpp+7−7

This diff is too big to show here.

tests/mocks/Unity/Application/MirSurfaceListModel.h+10−7

This diff is too big to show here.

tests/mocks/Unity/Application/SurfaceManager.cpp+13−19

This diff is too big to show here.

tests/mocks/Unity/Application/SurfaceManager.h+1−3

This diff is too big to show here.

tests/mocks/Unity/Application/VirtualKeyboard.cpp+4−5

This diff is too big to show here.

tests/mocks/Unity/Application/resources/Kate.qmldeleted−49

This diff is too big to show here.

tests/mocks/Unity/Application/resources/KateDialog.qmldeleted−48

This diff is too big to show here.

tests/mocks/Unity/Application/resources/surfaces.qrc−3

This diff is too big to show here.

tests/mocks/Unity/ApplicationMenu/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/ApplicationMenu/mockapplicationmenuregistry.cpp+2−2

This diff is too big to show here.

tests/mocks/Unity/ApplicationMenu/mockapplicationmenuregistry.h+1−1

This diff is too big to show here.

tests/mocks/Unity/CMakeLists.txt+66

This diff is too big to show here.

tests/mocks/Unity/Connectivity/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/CMakeLists.txtnew file+18

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/dashcommunicator.cppnew file+42

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/dashcommunicator.hnew file+39

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.cppnew file+46

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/dashcommunicatorservice.hnew file+41

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/plugin.cppnew file+31

This diff is too big to show here.

plugins/Lights/HfdLights.h → tests/mocks/Unity/DashCommunicator/plugin.hrenamed+9−17

This diff is too big to show here.

tests/mocks/Unity/DashCommunicator/qmldirnew file+3

This diff is too big to show here.

tests/mocks/Unity/Indicators/CMakeLists.txt+2−1

This diff is too big to show here.

tests/mocks/Unity/Indicators/IndicatorsModel.qml+12−30

This diff is too big to show here.

tests/mocks/Unity/Indicators/fakeindicatorsmodeldata.js+5−22

This diff is too big to show here.

tests/mocks/Unity/InputInfo/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/Launcher/CMakeLists.txt+3−1

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp+4−27

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockAppDrawerModel.h−11

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockLauncherItem.cpp−13

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockLauncherItem.h−3

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockLauncherModel.cpp+1−1

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockLauncherModel.h+1−1

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockQuickListModel.cpp+1−3

This diff is too big to show here.

tests/mocks/Unity/Launcher/MockQuickListModel.h−2

This diff is too big to show here.

tests/mocks/Unity/Notifications/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/Screens/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/Unity/fake_categories.cppnew file+165

This diff is too big to show here.

tests/mocks/Unity/fake_categories.hnew file+54

This diff is too big to show here.

tests/mocks/Unity/fake_expandablefilterwidget.cppnew file+53

This diff is too big to show here.

tests/mocks/Unity/fake_expandablefilterwidget.hnew file+48

This diff is too big to show here.

tests/mocks/Unity/fake_filters.cppnew file+136

This diff is too big to show here.

tests/mocks/Unity/fake_filters.hnew file+46

This diff is too big to show here.

tests/mocks/Unity/fake_navigation.cppnew file+123

This diff is too big to show here.

tests/mocks/Unity/fake_navigation.hnew file+61

This diff is too big to show here.

tests/mocks/Unity/fake_optionselectorfilter.cppnew file+70

This diff is too big to show here.

tests/mocks/Unity/fake_optionselectorfilter.hnew file+54

This diff is too big to show here.

tests/mocks/Unity/fake_optionselectoroptions.cppnew file+90

This diff is too big to show here.

tests/mocks/Unity/fake_optionselectoroptions.hnew file+49

This diff is too big to show here.

tests/mocks/Unity/fake_previewmodel.cppnew file+103

This diff is too big to show here.

tests/mocks/Unity/fake_previewmodel.hnew file+58

This diff is too big to show here.

tests/mocks/Unity/fake_previewwidgetmodel.cppnew file+97

This diff is too big to show here.

tests/mocks/Unity/fake_previewwidgetmodel.hnew file+47

This diff is too big to show here.

tests/mocks/Unity/fake_rangeinputfilter.cppnew file+167

This diff is too big to show here.

tests/mocks/Unity/fake_rangeinputfilter.hnew file+79

This diff is too big to show here.

tests/mocks/Unity/fake_resultsmodel.cppnew file+92

This diff is too big to show here.

tests/mocks/Unity/fake_resultsmodel.hnew file+52

This diff is too big to show here.

tests/mocks/Unity/fake_scope.cppnew file+372

This diff is too big to show here.

tests/mocks/Unity/fake_scope.hnew file+128

This diff is too big to show here.

tests/mocks/Unity/fake_scopes.cppnew file+286

This diff is too big to show here.

tests/mocks/Unity/fake_scopes.hnew file+83

This diff is too big to show here.

tests/mocks/Unity/fake_scopesoverview.cppnew file+340

This diff is too big to show here.

tests/mocks/Unity/fake_scopesoverview.hnew file+119

This diff is too big to show here.

tests/mocks/Unity/fake_settingsmodel.cppnew file+95

This diff is too big to show here.

tests/mocks/Unity/fake_settingsmodel.hnew file+54

This diff is too big to show here.

tests/mocks/Unity/fake_unity_plugin.cppnew file+62

This diff is too big to show here.

tests/mocks/Unity/fake_unity_plugin.hnew file+34

This diff is too big to show here.

tests/mocks/Unity/fake_valuesliderfilter.cppnew file+84

This diff is too big to show here.

tests/mocks/Unity/fake_valuesliderfilter.hnew file+55

This diff is too big to show here.

tests/mocks/Unity/fake_valueslidervalues.cppnew file+51

This diff is too big to show here.

tests/mocks/Unity/fake_valueslidervalues.hnew file+36

This diff is too big to show here.

tests/mocks/Unity/qmldirnew file+3

This diff is too big to show here.

tests/mocks/Utils/CMakeLists.txt+3−8

This diff is too big to show here.

tests/mocks/Utils/plugin.cpp+1−7

This diff is too big to show here.

tests/mocks/Wizard/CMakeLists.txt+2−2

This diff is too big to show here.

tests/mocks/Wizard/MockSystem.cpp+4−19

This diff is too big to show here.

tests/mocks/Wizard/MockSystem.h+1−11

This diff is too big to show here.

tests/mocks/Wizard/mockplugin.cpp−2

This diff is too big to show here.

tests/mocks/liblightdm/CMakeLists.txtdeleted−18

This diff is too big to show here.

tests/mocks/liblightdm/MockController.cppdeleted−192

This diff is too big to show here.

tests/mocks/liblightdm/MockController.hdeleted−106

This diff is too big to show here.

tests/mocks/liblightdm/MockGreeter.cppdeleted−316

This diff is too big to show here.

tests/mocks/liblightdm/MockUsersModel.cppdeleted−220

This diff is too big to show here.

tests/mocks/liblightdm/demo/CMakeLists.txt+1−1

This diff is too big to show here.

tests/mocks/libusermetrics/CMakeLists.txt+1−1

This diff is too big to show here.

tests/plugins/AccountsService/CMakeLists.txt+2−2

This diff is too big to show here.

tests/plugins/AccountsService/PropertiesServer.cpp+1−1

This diff is too big to show here.

tests/plugins/AccountsService/client.cpp+34−6

This diff is too big to show here.

tests/plugins/CMakeLists.txt+3−2

This diff is too big to show here.

tests/plugins/Dash/CMakeLists.txtnew file+104

This diff is too big to show here.

tests/plugins/Dash/cardcreator/1.resnew file+82

This diff is too big to show here.

tests/plugins/Dash/cardcreator/1.res.cardcreatornew file+69

This diff is too big to show here.

tests/plugins/Dash/cardcreator/1.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/10.resnew file+129

This diff is too big to show here.

tests/plugins/Dash/cardcreator/10.res.cardcreatornew file+127

This diff is too big to show here.

tests/plugins/Dash/cardcreator/10.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/11.resnew file+176

This diff is too big to show here.

tests/plugins/Dash/cardcreator/11.res.cardcreatornew file+160

This diff is too big to show here.

tests/plugins/Dash/cardcreator/11.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/12.resnew file+108

This diff is too big to show here.

tests/plugins/Dash/cardcreator/12.res.cardcreatornew file+95

This diff is too big to show here.

tests/plugins/Dash/cardcreator/12.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/2.resnew file+128

This diff is too big to show here.

tests/plugins/Dash/cardcreator/2.res.cardcreatornew file+126

This diff is too big to show here.

tests/plugins/Dash/cardcreator/2.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/3.resnew file+90

This diff is too big to show here.

tests/plugins/Dash/cardcreator/3.res.cardcreatornew file+86

This diff is too big to show here.

tests/plugins/Dash/cardcreator/3.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/4.resnew file+111

This diff is too big to show here.

tests/plugins/Dash/cardcreator/4.res.cardcreatornew file+99

This diff is too big to show here.

tests/plugins/Dash/cardcreator/4.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/5.resnew file+102

This diff is too big to show here.

tests/plugins/Dash/cardcreator/5.res.cardcreatornew file+99

This diff is too big to show here.

tests/plugins/Dash/cardcreator/5.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/6.resnew file+127

This diff is too big to show here.

tests/plugins/Dash/cardcreator/6.res.cardcreatornew file+116

This diff is too big to show here.

tests/plugins/Dash/cardcreator/6.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/7.resnew file+141

This diff is too big to show here.

tests/plugins/Dash/cardcreator/7.res.cardcreatornew file+139

This diff is too big to show here.

tests/plugins/Dash/cardcreator/7.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/8.resnew file+109

This diff is too big to show here.

tests/plugins/Dash/cardcreator/8.res.cardcreatornew file+97

This diff is too big to show here.

tests/plugins/Dash/cardcreator/8.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreator/9.resnew file+120

This diff is too big to show here.

tests/plugins/Dash/cardcreator/9.res.cardcreatornew file+109

This diff is too big to show here.

tests/plugins/Dash/cardcreator/9.tstnew file+4

This diff is too big to show here.

tests/plugins/Dash/cardcreatortest.cppnew file+126

This diff is too big to show here.

tests/plugins/Dash/cardcreatortest.qmlnew file+29

This diff is too big to show here.

tests/plugins/Dash/horizontaljournaltest.cppnew file+490

This diff is too big to show here.

tests/plugins/Dash/horizontaljournaltest.qmlnew file+44

This diff is too big to show here.

tests/plugins/Dash/horizontaljournaltry.cppnew file+91

This diff is too big to show here.

tests/plugins/Dash/horizontaljournaltry.qmlnew file+120

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cppnew file+246

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadersectiontest.cppnew file+2212

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadertest.cppnew file+2038

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadertest.qmlnew file+96

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadertestsection.qmlnew file+119

This diff is too big to show here.

tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qmlnew file+76

This diff is too big to show here.

tests/plugins/Dash/organicgridtest.cppnew file+533

This diff is too big to show here.

tests/plugins/Dash/organicgridtest.qmlnew file+44

This diff is too big to show here.

tests/plugins/Dash/organicgridtry.cppnew file+99

This diff is too big to show here.

tests/plugins/Dash/organicgridtry.qmlnew file+114

This diff is too big to show here.

tests/plugins/Dash/tst_CardAttributes.qmlnew file+57

This diff is too big to show here.

tests/plugins/Dash/tst_CroppedImageMinimumSourceSize.qmlnew file+56

This diff is too big to show here.

tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qmlnew file+140

This diff is too big to show here.

tests/plugins/Dash/tst_ScopeStyle.qmlnew file+188

This diff is too big to show here.

tests/plugins/Dash/verticaljournaltest.cppnew file+564

This diff is too big to show here.

tests/plugins/Dash/verticaljournaltest.qmlnew file+45

This diff is too big to show here.

tests/plugins/Dash/verticaljournaltry.cppnew file+91

This diff is too big to show here.

tests/plugins/Dash/verticaljournaltry.qmlnew file+121

This diff is too big to show here.

tests/plugins/GlobalShortcut/CMakeLists.txt+2−1

This diff is too big to show here.

tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt+3−1

This diff is too big to show here.

tests/plugins/ImageCache/CMakeLists.txtnew file+30

This diff is too big to show here.

tests/plugins/ImageCache/graphics/wide.jpgnew file

Binary file not shown.

tests/plugins/ImageCache/test.cppnew file+216

This diff is too big to show here.

tests/plugins/ImageCache/test.qmlnew file+23

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt+11−39

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/dbus.cpp+11−20

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/greeter.qml+7−2

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/promptsmodel.cppdeleted−175

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/sessionsmodel.cpp+13−19

This diff is too big to show here.

tests/plugins/LightDM/IntegratedLightDM/usersmodel.cpp+16−100

This diff is too big to show here.

tests/plugins/SessionBroadcast/CMakeLists.txt+2−2

This diff is too big to show here.

tests/plugins/Ubuntu/Gestures/CMakeLists.txt+2−4

This diff is too big to show here.

tests/plugins/Ubuntu/Gestures/GestureTest.cpp+1−10

This diff is too big to show here.

tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+2−11

This diff is too big to show here.

tests/plugins/Ubuntu/Gestures/tst_TouchGestureArea.cpp−30

This diff is too big to show here.

tests/plugins/Unity/CMakeLists.txt−1

This diff is too big to show here.

tests/plugins/Unity/Indicators/CMakeLists.txt+1−1

This diff is too big to show here.

tests/plugins/Unity/Launcher/CMakeLists.txt+2−39

This diff is too big to show here.

tests/plugins/Unity/Launcher/appdrawermodeltest.cppdeleted−68

This diff is too big to show here.

tests/plugins/Unity/Launcher/launchermodeltest.cpp+7−86

This diff is too big to show here.

tests/plugins/Unity/Launcher/ualwrapper.cppdeleted−58

This diff is too big to show here.

tests/plugins/Unity/Launcher/ualwrapper.hdeleted−55

This diff is too big to show here.

tests/plugins/Unity/Launcher/xdgwatcher.cppdeleted−45

This diff is too big to show here.

tests/plugins/Unity/Launcher/xdgwatcher.hdeleted−39

This diff is too big to show here.

tests/plugins/Unity/Platform/CMakeLists.txtdeleted−30

This diff is too big to show here.

tests/plugins/Unity/Platform/platformtest.cppdeleted−142

This diff is too big to show here.

tests/plugins/Unity/Session/CMakeLists.txt+3−15

This diff is too big to show here.

tests/plugins/Unity/Session/LogindServer.cpp−10

This diff is too big to show here.

tests/plugins/Unity/Session/LogindServer.h−5

This diff is too big to show here.

tests/plugins/Unity/Session/interfaces.xml−12

This diff is too big to show here.

tests/plugins/Unity/Session/preload.cdeleted−43

This diff is too big to show here.

tests/plugins/Unity/Session/sessionbackendtest.cpp+11−130

This diff is too big to show here.

tests/plugins/Utils/CMakeLists.txt+5−6

This diff is too big to show here.

tests/plugins/Utils/DeviceConfigParserTest.cpp−3

This diff is too big to show here.

tests/plugins/Utils/ModelTest.cpp+1−2

This diff is too big to show here.

tests/plugins/Utils/WindowInputMonitorTest.cpp+1−31

This diff is too big to show here.

tests/plugins/Utils/WindowStateStorageTest.cppdeleted−121

This diff is too big to show here.

tests/plugins/WindowManager/CMakeLists.txtdeleted−36

This diff is too big to show here.

tests/plugins/WindowManager/UnityApplicationMocks.hdeleted−211

This diff is too big to show here.

tests/plugins/WindowManager/tst_TopLevelWindowModel.cppdeleted−193

This diff is too big to show here.

tests/plugins/Wizard/CMakeLists.txt+2−2

This diff is too big to show here.

tests/qmltests/ApplicationMenuDataLoader.qml+6−30

This diff is too big to show here.

tests/qmltests/ApplicationMenus/tst_MenuBar.qml+9−263

This diff is too big to show here.

tests/qmltests/ApplicationMenus/tst_MenuPopup.qml+55−209

This diff is too big to show here.

tests/qmltests/CMakeLists.txt+51−5

This diff is too big to show here.

tests/qmltests/Components/CMakeLists.txt+4−8

This diff is too big to show here.

tests/qmltests/Components/tst_Carousel.qmlnew file+292

This diff is too big to show here.

tests/qmltests/Components/tst_Dialogs.qml+1

This diff is too big to show here.

tests/qmltests/Components/tst_DragHandle.cpp+2−19

This diff is too big to show here.

tests/qmltests/Components/tst_DraggingArea.qml+6−6

This diff is too big to show here.

tests/qmltests/Components/tst_Lockscreen.qml+9−11

This diff is too big to show here.

tests/qmltests/Components/tst_MediaServices.qml+4−5

This diff is too big to show here.

tests/qmltests/Components/tst_PhysicalKeysMapper.qml+6−7

This diff is too big to show here.

tests/qmltests/Components/tst_Rating.qml+1−1

This diff is too big to show here.

tests/qmltests/Components/tst_ResponsiveGridView.qmlnew file+157

This diff is too big to show here.

tests/qmltests/Components/tst_ResponsiveVerticalJournal.qmlnew file+183

This diff is too big to show here.

tests/qmltests/Components/tst_SharingPicker.qml+3−3

This diff is too big to show here.

tests/qmltests/Components/tst_Showable.qml−13

This diff is too big to show here.

tests/qmltests/Components/tst_Wallpaper.qmldeleted−118

This diff is too big to show here.

tests/qmltests/Components/tst_WallpaperResolver.qml+18−104

This diff is too big to show here.

tests/qmltests/Dash/CardHelpers.jsnew file+115

This diff is too big to show here.

tests/qmltests/Dash/Filters/tst_FilterExpandableWidget.qmlnew file+99

This diff is too big to show here.

tests/qmltests/Dash/Filters/tst_FilterOptionSelector.qmlnew file+96

This diff is too big to show here.

tests/qmltests/Dash/Filters/tst_FilterRangeInput.qmlnew file+247

This diff is too big to show here.

tests/qmltests/Dash/Filters/tst_FilterValueSlider.qmlnew file+101

This diff is too big to show here.

tests/qmltests/Dash/Filters/tst_FilterWidgetFactory.qmlnew file+59

This diff is too big to show here.

tests/qmltests/Dash/Previews/MockPreviewWidget.qmlnew file+27

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_Preview.qmlnew file+214

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewActions.qmlnew file+262

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewAudioPlayback.qmlnew file+182

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewComment.qmlnew file+84

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewCommentInput.qmlnew file+113

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewExpandable.qmlnew file+353

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewHeader.qmlnew file+183

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewIconActions.qmlnew file+136

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewImageGallery.qmlnew file+147

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewInlineVideo.qmlnew file+155

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewMediaToolbar.qmlnew file+69

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewProgress.qmlnew file+100

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewRatingDisplay.qmlnew file+123

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewRatingDisplayCreationRanges.qmlnew file+131

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qmlnew file+87

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qmlnew file+246

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewTable.qmlnew file+147

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewTextSummary.qmlnew file+87

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewVideoPlayback.qmlnew file+61

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qmlnew file+104

This diff is too big to show here.

tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qmlnew file+138

This diff is too big to show here.

tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingBoolean.qmlnew file+62

This diff is too big to show here.

tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingList.qmlnew file+84

This diff is too big to show here.

tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingNumber.qmlnew file+98

This diff is too big to show here.

tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingString.qmlnew file+88

This diff is too big to show here.

tests/qmltests/Dash/ScopeSettings/tst_ScopeSettingsWidgetFactory.qmlnew file+65

This diff is too big to show here.

tests/qmltests/Dash/artwork/avatar@12.pngnew file

Binary file not shown.

tests/qmltests/Dash/artwork/background.pngnew file

Binary file not shown.

tests/qmltests/Dash/artwork/checkers.pngnew file

Binary file not shown.

tests/qmltests/Dash/artwork/emblem.pngnew file

Binary file not shown.

tests/qmltests/Dash/artwork/music-player-design.pngnew file

Binary file not shown.

tests/qmltests/Dash/tst_Card.qmlnew file+682

This diff is too big to show here.

tests/qmltests/Dash/tst_CardBenchmark.qmlnew file+95

This diff is too big to show here.

tests/qmltests/Dash/tst_CardCarousel.qmlnew file+111

This diff is too big to show here.

tests/qmltests/Dash/tst_CardTool.qmlnew file+379

This diff is too big to show here.

tests/qmltests/Dash/tst_Dash.qmlnew file+648

This diff is too big to show here.

tests/qmltests/Dash/tst_DashContent.qmlnew file+730

This diff is too big to show here.

tests/qmltests/Dash/tst_DashPageHeader.qmlnew file+357

This diff is too big to show here.

tests/qmltests/Dash/tst_DashShell.qmlnew file+116

This diff is too big to show here.

tests/qmltests/Dash/tst_GenericScopeView.qmlnew file+706

This diff is too big to show here.

tests/qmltests/Dash/tst_PageHeader/logo-ubuntu-orange.svgnew file+60

This diff is too big to show here.

tests/qmltests/Dash/tst_PreviewView.qmlnew file+122

This diff is too big to show here.

tests/qmltests/Greeter/TestView.qml+22−16

This diff is too big to show here.

tests/qmltests/Greeter/tst_Greeter.qml+140−80

This diff is too big to show here.

tests/qmltests/Greeter/tst_GreeterView.qmldeleted−1366

This diff is too big to show here.

tests/qmltests/Greeter/tst_Infographics.qml+11−1

This diff is too big to show here.

tests/qmltests/Greeter/tst_NarrowView.qmlnew file+589

This diff is too big to show here.

tests/qmltests/Greeter/tst_WideView.qmlnew file+757

This diff is too big to show here.

tests/qmltests/Launcher/tst_Drawer.qml+13−269

This diff is too big to show here.

tests/qmltests/Launcher/tst_Launcher.qml+81−255

This diff is too big to show here.

tests/qmltests/Notifications/tst_Notifications.qml+10−16

This diff is too big to show here.

tests/qmltests/Notifications/tst_OptionToggle.qml+6−12

This diff is too big to show here.

tests/qmltests/Notifications/tst_SwipeToAct.qml+3−10

This diff is too big to show here.

tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+3−3

This diff is too big to show here.

tests/qmltests/Panel/Indicators/tst_IndicatorMenuItemFactory.qml+79−33

This diff is too big to show here.

tests/qmltests/Panel/Indicators/tst_IndicatorsLight.qml+8−168

This diff is too big to show here.

tests/qmltests/Panel/PanelUI.qmldeleted−286

This diff is too big to show here.

tests/qmltests/Panel/tst_ActiveCallHint.qml+9−14

This diff is too big to show here.

tests/qmltests/Panel/tst_MenuContent.qml+2−2

This diff is too big to show here.

tests/qmltests/Panel/tst_Panel.qml+253−149

This diff is too big to show here.

tests/qmltests/Panel/tst_PanelItemRow.qml+2−2

This diff is too big to show here.

tests/qmltests/Panel/tst_PanelMenu.qml+22−61

This diff is too big to show here.

tests/qmltests/Panel/tst_PanelMenuPage.qml+1−1

This diff is too big to show here.

tests/qmltests/Panel/tst_PanelSmallScreen.qmldeleted−133

This diff is too big to show here.

tests/qmltests/Stage/ApplicationCheckBox.qml+7−7

This diff is too big to show here.

tests/qmltests/Stage/tst_ApplicationWindow.qml+2−3

This diff is too big to show here.

tests/qmltests/Stage/tst_DesktopStage.qml+29−280

This diff is too big to show here.

tests/qmltests/Stage/tst_PhoneStage.qml+64−95

This diff is too big to show here.

tests/qmltests/Stage/tst_QMLTopLevelWindowModel.qmldeleted−191

This diff is too big to show here.

tests/qmltests/Stage/tst_SpreadDelegate.qmlnew file+423

This diff is too big to show here.

tests/qmltests/Stage/tst_SurfaceContainer.qml+8−9

This diff is too big to show here.

tests/qmltests/Stage/tst_TabletStage.qml+139−137

This diff is too big to show here.

tests/qmltests/Stage/tst_WindowDecoration.qml+3−3

This diff is too big to show here.

tests/qmltests/Stage/tst_WindowResizeArea.qml+3−14

This diff is too big to show here.

tests/qmltests/Tutorial/tst_Tutorial.qml+193−192

This diff is too big to show here.

tests/qmltests/Wizard/tst_Wizard.qml+142−100

This diff is too big to show here.

tests/qmltests/tst_OrientedShell.qml+262−405

This diff is too big to show here.

tests/qmltests/tst_Shell.qml+578−1183

This diff is too big to show here.

tests/qmltests/tst_ShellWithPin.qml+131−118

This diff is too big to show here.

tests/scripts/alert-launcher-icon.sh−16

This diff is too big to show here.

tests/scripts/get-progress.sh−16

This diff is too big to show here.

tests/scripts/list-launcher-icons.sh−16

This diff is too big to show here.

tests/scripts/set-count-visible.sh−16

This diff is too big to show here.

tests/scripts/set-count.sh−16

This diff is too big to show here.

tests/scripts/set-progress.sh−16

This diff is too big to show here.

tests/uqmlscene/CMakeLists.txt+1−1

This diff is too big to show here.

tests/utils/modules/Unity/Test/CMakeLists.txt+4−2

This diff is too big to show here.

tests/utils/modules/Unity/Test/MouseTouchEmulationCheckbox.qml+1−1

This diff is too big to show here.

tests/utils/modules/Unity/Test/StageTestCase.qml+18−14

This diff is too big to show here.

tests/utils/modules/Unity/Test/TouchEventSequenceWrapper.cpp+1−10

This diff is too big to show here.

tests/utils/modules/Unity/Test/UnityTestCase.qml+11−2

This diff is too big to show here.

tools/CMakeLists.txt+12−2

This diff is too big to show here.

tools/menutool/CMakeLists.txtdeleted−5

This diff is too big to show here.

tools/menutool/READMEdeleted−11

This diff is too big to show here.

tools/menutool/menutool.cppdeleted−62

This diff is too big to show here.

tools/menutool/menutool.qmldeleted−118

This diff is too big to show here.

tools/registry-tracker.cppnew file+146

This diff is too big to show here.

tools/registry-tracker.hnew file+49

This diff is too big to show here.

tools/scopetool.cppnew file+116

This diff is too big to show here.

tools/unlock-device−16

This diff is too big to show here.