Merge lp:~mterry/unity8/tutorial-redesign into lp:unity8
- tutorial-redesign
- Merge into trunk
Status: | Superseded | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~mterry/unity8/tutorial-redesign | ||||||||||||
Merge into: | lp:unity8 | ||||||||||||
Prerequisite: | lp:~mzanetti/unity8/catch-osk | ||||||||||||
Diff against target: |
19733 lines (+9629/-3653) 233 files modified
CMakeLists.txt (+2/-1) cmake/modules/QmlTest.cmake (+1/-1) data/com.canonical.Unity8.gschema.xml (+11/-0) data/unity8-dash.conf (+1/-0) debian/changelog (+97/-0) debian/control (+9/-7) debian/unity8-common.udev (+2/-0) debian/unity8-doc.install (+1/-0) doc/devices.conf (+30/-0) plugins/AccountsService/AccountsService.cpp (+286/-399) plugins/AccountsService/AccountsService.h (+42/-24) plugins/AccountsService/AccountsService.qmltypes (+5/-0) plugins/AccountsService/AccountsServiceDBusAdaptor.cpp (+11/-4) plugins/AccountsService/AccountsServiceDBusAdaptor.h (+5/-6) plugins/AccountsService/com.canonical.unity.AccountsService.xml (+5/-0) plugins/Dash/AudioProgressBar.qml (+1/-0) plugins/Dash/CardCreator.js (+69/-34) plugins/Dash/CardCreatorCache.qml (+3/-3) plugins/Dash/plugin.cpp (+6/-6) plugins/GlobalShortcut/globalshortcutregistry.cpp (+4/-4) plugins/IntegratedLightDM/liblightdm/CMakeLists.txt (+16/-3) plugins/IntegratedLightDM/liblightdm/UsersModel.cpp (+4/-18) plugins/IntegratedLightDM/liblightdm/UsersModel.h (+1/-1) plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+44/-10) plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h (+15/-3) plugins/ScreenGrabber/screengrabber.cpp (+0/-2) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+40/-5) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+8/-0) plugins/Ubuntu/Gestures/DirectionalDragArea_p.h (+2/-0) plugins/Unity/Indicators/indicatorsmanager.cpp (+2/-2) plugins/Unity/Indicators/rootstateparser.h (+1/-0) plugins/Unity/Launcher/desktopfilehandler.cpp (+2/-2) plugins/Unity/Launcher/launcheritem.cpp (+1/-0) plugins/Unity/Launcher/launcheritem.h (+1/-1) plugins/Unity/Launcher/launchermodel.cpp (+15/-5) plugins/Unity/Launcher/launchermodel.h (+1/-1) plugins/Utils/CMakeLists.txt (+2/-1) plugins/Utils/Utils.qmltypes (+2/-2) plugins/Utils/deviceconfigparser.cpp (+150/-0) plugins/Utils/deviceconfigparser.h (+62/-0) plugins/Utils/plugin.cpp (+4/-2) plugins/Utils/timezoneFormatter.cpp (+10/-0) plugins/Utils/timezoneFormatter.h (+1/-0) plugins/Utils/windowinputfilter.cpp (+14/-16) plugins/Utils/windowinputfilter.h (+11/-11) plugins/Wizard/CMakeLists.txt (+7/-1) plugins/Wizard/LocalePlugin.cpp (+291/-0) plugins/Wizard/LocalePlugin.h (+58/-0) plugins/Wizard/PageList.cpp (+4/-4) plugins/Wizard/Status.cpp (+143/-0) plugins/Wizard/Status.h (+60/-0) plugins/Wizard/System.cpp (+5/-4) plugins/Wizard/System.h (+3/-2) plugins/Wizard/plugin.cpp (+7/-8) plugins/Wizard/plugin.h (+1/-2) plugins/Wizard/timezonemodel.cpp (+239/-0) plugins/Wizard/timezonemodel.h (+80/-0) po/unity8.pot (+29/-27) qml/Components/EdgeBarrier.qml (+1/-1) qml/Components/Lockscreen.qml (+86/-100) qml/Components/ModeSwitchWarningDialog.qml (+1/-1) qml/Components/PassphraseLockscreen.qml (+5/-4) qml/Components/PhysicalKeysMapper.qml (+24/-0) qml/Components/PinLockscreen.qml (+22/-1) qml/Components/ShellDialog.qml (+8/-0) qml/Dash/CardCarousel.qml (+0/-1) qml/Dash/CardGrid.qml (+0/-1) qml/Dash/CardHorizontalList.qml (+0/-1) qml/Dash/CardTool.qml (+2/-26) qml/Dash/CardVerticalJournal.qml (+0/-1) qml/Dash/Dash.qml (+11/-11) qml/Dash/GenericScopeView.qml (+2/-0) qml/Dash/Previews/PreviewHeader.qml (+37/-9) qml/Dash/Previews/PreviewOverlay.qml (+1/-1) qml/Dash/Previews/PreviewSharing.qml (+17/-7) qml/Dash/ScopesListCategoryItem.qml (+8/-4) qml/DeviceConfiguration.qml (+56/-18) qml/DisabledScreenNotice.qml (+44/-20) qml/Greeter/CoverPage.qml (+13/-2) qml/Greeter/Greeter.qml (+10/-6) qml/Greeter/Infographics.qml (+2/-1) qml/Greeter/NarrowView.qml (+14/-1) qml/Launcher/Launcher.qml (+144/-12) qml/Launcher/LauncherDelegate.qml (+55/-20) qml/Launcher/LauncherPanel.qml (+122/-51) qml/Launcher/graphics/launcher-app-focus-ring.svg (+12/-0) qml/Notifications/Notification.qml (+6/-2) qml/OrientedShell.qml (+26/-1) qml/Panel/Handle.qml (+2/-2) qml/Panel/Indicators/MenuItemFactory.qml (+0/-1) qml/Panel/IndicatorsMenu.qml (+1/-3) qml/Panel/Panel.qml (+5/-1) qml/ScopeTool.qml (+0/-8) qml/Shell.qml (+77/-46) qml/Stages/AbstractStage.qml (+4/-1) qml/Stages/ApplicationWindow.qml (+0/-2) qml/Stages/DesktopSpread.qml (+64/-17) qml/Stages/DesktopSpreadDelegate.qml (+15/-1) qml/Stages/DesktopStage.qml (+34/-34) qml/Stages/PhoneStage.qml (+80/-9) qml/Stages/SpreadDelegate.qml (+20/-0) qml/Stages/TabletStage.qml (+98/-14) qml/Stages/WindowResizeArea.qml (+8/-5) qml/Tutorial/Arrow.qml (+0/-56) qml/Tutorial/InactivityTimer.qml (+62/-0) qml/Tutorial/Slider.qml (+0/-123) qml/Tutorial/Tick.qml (+0/-29) qml/Tutorial/Tutorial.qml (+43/-18) qml/Tutorial/TutorialBottom.qml (+0/-104) qml/Tutorial/TutorialBottomFinish.qml (+0/-41) qml/Tutorial/TutorialContent.qml (+250/-80) qml/Tutorial/TutorialLeft.qml (+28/-75) qml/Tutorial/TutorialLeftFinish.qml (+0/-41) qml/Tutorial/TutorialLeftLong.qml (+54/-0) qml/Tutorial/TutorialPage.qml (+66/-190) qml/Tutorial/TutorialRight.qml (+0/-223) qml/Tutorial/TutorialTop.qml (+61/-0) qml/Tutorial/graphics/arrow.svg (+19/-0) qml/Wizard/CheckableSetting.qml (+10/-2) qml/Wizard/Page.qml (+274/-58) qml/Wizard/Pages.qml (+76/-32) qml/Wizard/Pages/10-welcome.qml (+129/-56) qml/Wizard/Pages/30-wifi.qml (+119/-128) qml/Wizard/Pages/40-location.qml (+216/-75) qml/Wizard/Pages/50-timezone.qml (+275/-0) qml/Wizard/Pages/60-account.qml (+74/-0) qml/Wizard/Pages/60-reporting.qml (+0/-64) qml/Wizard/Pages/70-passwd-type.qml (+105/-79) qml/Wizard/Pages/75-report-check.qml (+91/-0) qml/Wizard/Pages/80-finished.qml (+106/-28) qml/Wizard/Pages/here-terms.qml (+80/-73) qml/Wizard/Pages/passcode-confirm.qml (+13/-30) qml/Wizard/Pages/passcode-desktop.qml (+132/-0) qml/Wizard/Pages/passcode-set.qml (+12/-28) qml/Wizard/Pages/password-set.qml (+149/-0) qml/Wizard/Pages/sim.qml (+71/-40) qml/Wizard/PasswordMeter.qml (+106/-0) qml/Wizard/StackButton.qml (+6/-11) qml/Wizard/Wizard.qml (+0/-9) qml/Wizard/WizardTextField.qml (+25/-0) src/CMakeLists.txt (+1/-1) src/CachingNetworkManagerFactory.cpp (+2/-2) src/CachingNetworkManagerFactory.h (+3/-2) src/Dash/CMakeLists.txt (+1/-1) tests/autopilot/unity8/dash.py (+1/-2) tests/autopilot/unity8/shell/emulators.py (+0/-2) tests/autopilot/unity8/shell/tests/test_helpers.py (+0/-2) tests/autopilot/unity8/shell/tests/test_tutorial.py (+0/-57) tests/autopilot/unity8/tutorial.py (+0/-73) tests/mocks/AccountsService/AccountsService.cpp (+43/-3) tests/mocks/AccountsService/AccountsService.h (+22/-5) tests/mocks/AccountsService/AccountsService.qmltypes (+5/-0) tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0) tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0) tests/mocks/IntegratedLightDM/liblightdm/UsersModel.cpp (+0/-14) tests/mocks/MeeGo/QOfono/MockOfonoSimManager.qml (+1/-0) tests/mocks/Ubuntu/Connectivity/plugin.cpp (+1/-0) tests/mocks/Ubuntu/SystemSettings/CMakeLists.txt (+2/-0) tests/mocks/Ubuntu/SystemSettings/Diagnostics/CMakeLists.txt (+1/-0) tests/mocks/Ubuntu/SystemSettings/Diagnostics/MockDiagnostics.qml (+24/-0) tests/mocks/Ubuntu/SystemSettings/Diagnostics/qmldir (+2/-0) tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/MockLanguagePlugin.qml (+2/-2) tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/MockSecurityPrivacy.cpp (+1/-1) tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txt (+1/-0) tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qml (+25/-0) tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldir (+2/-0) tests/mocks/Unity/Application/ApplicationInfo.h (+1/-1) tests/mocks/Unity/Application/MirSurface.cpp (+3/-0) tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0) tests/mocks/Utils/CMakeLists.txt (+3/-2) tests/mocks/Utils/Utils.qmltypes (+2/-2) tests/mocks/Utils/plugin.cpp (+7/-2) tests/mocks/Wizard/CMakeLists.txt (+6/-1) tests/mocks/Wizard/MockSystem.cpp (+4/-2) tests/mocks/Wizard/MockSystem.h (+2/-2) tests/mocks/Wizard/mockplugin.cpp (+7/-8) tests/plugins/AccountsService/CMakeLists.txt (+5/-0) tests/plugins/AccountsService/PropertiesServer.cpp (+17/-4) tests/plugins/AccountsService/PropertiesServer.h (+2/-1) tests/plugins/AccountsService/UscServer.cpp (+28/-0) tests/plugins/AccountsService/UscServer.h (+39/-0) tests/plugins/AccountsService/client.cpp (+100/-9) tests/plugins/AccountsService/interfaces.xml (+16/-0) tests/plugins/AccountsService/server.cpp (+12/-0) tests/plugins/Dash/cardcreator/1.res (+4/-6) tests/plugins/Dash/cardcreator/1.res.cardcreator (+119/-0) tests/plugins/Dash/cardcreator/10.res (+3/-5) tests/plugins/Dash/cardcreator/10.res.cardcreator (+137/-0) tests/plugins/Dash/cardcreator/11.res (+5/-7) tests/plugins/Dash/cardcreator/11.res.cardcreator (+210/-0) tests/plugins/Dash/cardcreator/2.res (+3/-5) tests/plugins/Dash/cardcreator/2.res.cardcreator (+136/-0) tests/plugins/Dash/cardcreator/3.res (+3/-5) tests/plugins/Dash/cardcreator/3.res.cardcreator (+137/-0) tests/plugins/Dash/cardcreator/4.res (+3/-5) tests/plugins/Dash/cardcreator/4.res.cardcreator (+109/-0) tests/plugins/Dash/cardcreator/5.res (+5/-7) tests/plugins/Dash/cardcreator/5.res.cardcreator (+156/-0) tests/plugins/Dash/cardcreator/6.res (+2/-4) tests/plugins/Dash/cardcreator/6.res.cardcreator (+126/-0) tests/plugins/Dash/cardcreator/7.res (+3/-5) tests/plugins/Dash/cardcreator/7.res.cardcreator (+149/-0) tests/plugins/Dash/cardcreator/8.res (+3/-5) tests/plugins/Dash/cardcreator/8.res.cardcreator (+107/-0) tests/plugins/Dash/cardcreator/9.res (+4/-5) tests/plugins/Dash/cardcreator/9.res.cardcreator (+119/-0) tests/plugins/Dash/cardcreatortest.cpp (+35/-25) tests/plugins/Dash/cardcreatortest.qml (+4/-4) tests/plugins/IntegratedLightDM/CMakeLists.txt (+25/-0) tests/plugins/IntegratedLightDM/integrated.cpp (+91/-0) tests/plugins/Utils/CMakeLists.txt (+7/-1) tests/plugins/Utils/DeviceConfigParserTest.cpp (+70/-0) tests/qmltests/CMakeLists.txt (+1/-0) tests/qmltests/Components/tst_Lockscreen.qml (+14/-7) tests/qmltests/Components/tst_PhysicalKeysMapper.qml (+3/-3) tests/qmltests/Dash/Previews/tst_PreviewHeader.qml (+18/-1) tests/qmltests/Dash/Previews/tst_PreviewSharing.qml (+17/-3) tests/qmltests/Dash/tst_CardTool.qml (+4/-4) tests/qmltests/Dash/tst_Dash.qml (+89/-0) tests/qmltests/Greeter/tst_Greeter.qml (+7/-1) tests/qmltests/Greeter/tst_NarrowView.qml (+9/-0) tests/qmltests/Launcher/tst_Launcher.qml (+254/-18) tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+2/-4) tests/qmltests/Stages/tst_DesktopStage.qml (+2/-1) tests/qmltests/Stages/tst_PhoneStage.qml (+19/-6) tests/qmltests/Stages/tst_SpreadDelegate.qml (+7/-0) tests/qmltests/Stages/tst_TabletStage.qml (+19/-1) tests/qmltests/Tutorial/tst_Tutorial.qml (+639/-245) tests/qmltests/Wizard/tst_Wizard.qml (+186/-215) tests/qmltests/tst_DeviceConfiguration.qml (+49/-0) tests/qmltests/tst_DisabledScreenNotice.qml (+76/-2) tests/qmltests/tst_Shell.qml (+245/-68) tests/qmltests/tst_ShellWithPin.qml (+0/-22) |
||||||||||||
To merge this branch: | bzr merge lp:~mterry/unity8/tutorial-redesign | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot | continuous-integration | Needs Fixing | |
PS Jenkins bot | continuous-integration | Pending | |
Albert Astals Cid | merges fine | Pending | |
Michael Zanetti | Pending | ||
Review via email: mp+288674@code.launchpad.net |
This proposal supersedes a proposal from 2015-09-16.
This proposal has been superseded by a proposal from 2016-03-11.
Commit message
Redesign the first-boot edge tutorial
Description of the change
Based on new design specs [1], this is whole new tutorial code.
Some of the interesting things going on here:
- New DDA feature "monitorOnly" which lets input events "fall through" (i.e. it doesn't own them) but continues to monitor them. This is how we implement the bottom edge tutorial fading out without having to communicate with the app.
- New AccountsService key to keep track of which particular edges are done, now that they are presented separately. We still use the old key for overall "done" status.
- Renamed WindowKeysFilter to WindowInputFilter. I needed a way to keep track of input inactivity. And since WindowKeysFilter was already injecting itself into the event stream and already kept track of timestamps for us (which usually isn't exposed to Qml), I just modified it a bit. I felt like the new scope should be indicated in the name, so I renamed it.
- I took out some old hacks only needed for the old tutorial.
[1] https:/
== Checklist ==
* Are there any related MPs required for this MP to build/function as expected? Please list.
Yes. A new phablet-tools branch for your desktop [2] and a new upload of dbus-property-
[2] https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
NA
* If you changed the UI, has there been a design review?
Yes. Patricia is on board with this MP. She has another screen coming (long swipe on left), but I'll do that as a separate MP.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, I'm opening this up to review, although the final design review isn't done yet and I need to add a couple more qmltests. But I'd like to get the review train started on its way.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, added more tests and cleaned up existing ones. Hopefully this is "done-ish" from a technical POV and only design-related changes will happen now (like changes to strings or alignment).
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1977
http://
Executed test runs:
ABORTED: http://
ABORTED: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1978
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Hmm... I've just flashed a device and enabled the edges-intro with phablet-config. I could see the intro for left, top and bottom edges, however, still waiting for the right edge one to appear.
====
As you renamed WindowKeyFilter, please update this comment too
qml/Shell.qml: // dummy shortcut to force creation of GlobalShortcutR
===
- readonly property real dragProgress: spreadRepeater.
+ dragProgress: spreadRepeater.
Given that it's not obvious what the dragProgress is used for, please add a comment in the stages code to indicate it. otherwise it's likely to be removed at some point because noone knows what it does.
===
+ ////
Is there a purpose to this? :)
===
+ sourceSize.height: 1080
+ sourceSize.width: 1916
erm... can you explain the values? Looks wrong to me
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Notes for myself:
* test if CPU usage drops if screen locks during animation
* test what happens if plugging external screen while in tutorial
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, I've made some changes. One, I added some more space between tutorial text lines, per design request.
Second, also per design request, I've added unique helper text on the bottom edge tutorial for each supported app. This also means that we show the tutorial for each app rather than once for any of them. Since this meant that the tutorial might not formally "finish" for quite some time, I've optimized the rest of the tutorial to use Loaders. So that we're not loading three unused background images a week after the user unboxes their phone.
As for your comments:
> Hmm... I've just flashed a device and enabled the edges-intro
> with phablet-config. I could see the intro for left, top and
> bottom edges, however, still waiting for the right edge one to appear.
As discussed on IRC, we're guessing this was user error. Unless you've seen it again?
====
> As you renamed WindowKeyFilter, please update this comment too
>
> qml/Shell.qml: // dummy shortcut to force creation of GlobalShortcutR
Done.
===
> - readonly property real dragProgress: spreadRepeater.
> + dragProgress: spreadRepeater.
> Given that it's not obvious what the dragProgress is used for,
> please add a comment in the stages code to indicate it. otherwise
> it's likely to be removed at some point because noone knows what it does.
Done.
===
> + ////
>
> Is there a purpose to this? :)
Ah, that's just a little visual separator I use between the public interface part of the object and the implementation parts. Qml doesn't use headers, and while we seem to use the placement of the QtObject component to separate the portions of code, sometimes an object doesn't warrant a QtObject, so it isn't a universal distinguisher. Plus, I like the extra visual space.
I can take it out if it will be as confusing to you as others. I know Cimi doesn't like that I do that.
===
> + sourceSize.height: 1080
> + sourceSize.width: 1916
>
> erm... can you explain the values? Looks wrong to me
Duh, I swapped height and width. Fixed.
===
> * test if CPU usage drops if screen locks during animation
Please do, but note that there isn't any animation anymore. So I expect no CPU difference.
===
> * test what happens if plugging external screen while in tutorial
Ah yes. Here's what I expect the code to do:
- Any visible tutorials that aren't marked for desktop use will fade out.
- The right edge tutorial will appear (or update itself) with desktop-specific text when you have enough apps open.
- If you finish the right edge tutorial while in desktop mode, the tutorial will be marked complete and you won't see any more coach marks. However, if you don't finish the right edge tutorial before undocking, you will continue to see all the tutorials you haven't seen yet, as normal.
How do you feel about that last behavior? It might be tricky to do something much smarter unless either (A) we know the "native" usageScenario of the device or (B) we stop marking the "whole-
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1979
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1981
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in tests/plugins/
1 conflicts encountered.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Fixed conflicts.
Albert Astals Cid (aacid) : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1982
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1982
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1983
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1984
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1985
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1986
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
+ i18n.tr("Hover your mouse on the right edge to view your open apps") :
+ i18n.tr("Short or long swipe from the right edge to view your open apps")
I know those have been given by design, but gotta point out some errors:
- In windowed mode, you need to push the mouse against the right edge and even overcome some resistance. Hovering is not enough.
- While at it, we might want to ask back on short swipe one too, but I guess that would be ok to oversimplify it in this case.
========
+ text: d.landscape ? i18n.tr("Swipe from the top right edge to open the notification bar")
+ : i18n.tr("Swipe from the top edge to open the notification bar")
this might needs a windowed mode special case too. We don't want to encourage clicking with a mouse so the indicators can also be revealed by clicking the icons. Although this is not wrong. If you have a touch screen too, you can also swipe then on a desktop.
========
+ text: i18n.tr("Swipe from the left edge to open the launcher")
same as for the right edge. With a mouse, it requires pushing towards the edge. Why not special cased here?
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Another question:
I figure it will take ages until completed goes to true. Some people might never open the calculator app which would leave us with the tutorial being enabled forever. What are the implications of that?
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
You mention the wording on the left edge drag needing to be changed for desktop mode -- but we don't show that tutorial on desktop. So I'm guessing we can leave it as is.
And you asked about the tutorial never "completing". This is a small issue. And it's why I revised TutorialContent to use loaders for each tutorial page. I don't think it's a problem, per se. But it does mean that we'll likely have the TutorialBottom page loaded most of the time. Until they load all the bottom-supported apps anyway...
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
On the right edge in windowed mode, it's not only the text, but the hoverMouseArea disappered and it's not possible to get past that step any more.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1987
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Launcher/
1 conflicts encountered.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1987
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1988
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1988
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Stages/
Text conflict in qml/Stages/
2 conflicts encountered.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1990
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1990
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1992
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1992
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1993
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1993
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1995
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1995
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1996
https:/
Executed test runs:
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Tests need fixin ↑?
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Fixed the qmluitest, and removed the autopilot test. The tutorial is harder to test via one autopilot test now that the pages have been split up and separately triggered. Plus, we cover them well in qmluitests. And there's nothing autopilot-centric to test there.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1999
https:/
Executed test runs:
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2000
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2002
https:/
Executed test runs:
UNSTABLE: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2002
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 2003. By Michael Terry
-
Merge silo 64
- 2004. By Michael Terry
-
Merge oobe
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2004
https:/
Executed test runs:
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unmerged revisions
- 2004. By Michael Terry
-
Merge oobe
- 2003. By Michael Terry
-
Merge silo 64
- 2002. By Michael Terry
-
Merge in catch-osk
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-02-12 00:12:30 +0000 |
3 | +++ CMakeLists.txt 2016-03-11 18:12:46 +0000 |
4 | @@ -58,6 +58,7 @@ |
5 | find_package(Qt5Sql 5.4 REQUIRED) |
6 | |
7 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=13) |
8 | +pkg_check_modules(GEONAMES REQUIRED geonames) |
9 | pkg_check_modules(GIO REQUIRED gio-2.0>=2.32) |
10 | pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32) |
11 | pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) |
12 | @@ -131,7 +132,7 @@ |
13 | set(STDOUT_LOGGER "-o" "-,txt") |
14 | endif() |
15 | |
16 | -execute_process(COMMAND arch OUTPUT_VARIABLE ARCH) |
17 | +execute_process(COMMAND dpkg-architecture -qDEB_HOST_ARCH OUTPUT_VARIABLE ARCH) |
18 | if (NOT ARCH MATCHES "arm*") |
19 | set(ENABLE_TOUCH_EMULATION true) |
20 | add_definitions(-DUNITY8_ENABLE_TOUCH_EMULATION) |
21 | |
22 | === modified file 'cmake/modules/QmlTest.cmake' |
23 | --- cmake/modules/QmlTest.cmake 2015-05-21 20:24:47 +0000 |
24 | +++ cmake/modules/QmlTest.cmake 2016-03-11 18:12:46 +0000 |
25 | @@ -183,7 +183,7 @@ |
26 | cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN}) |
27 | mangle_arguments() |
28 | |
29 | - bake_arguments("${QMLTEST_ARG_PREFIX}" args -qmljsdebugger=port:3768) |
30 | + bake_arguments("${QMLTEST_ARG_PREFIX}" args -qmljsdebugger=port:3768,3800) |
31 | |
32 | set(qmltry_command |
33 | $<TARGET_FILE:${TARGET}> |
34 | |
35 | === modified file 'data/com.canonical.Unity8.gschema.xml' |
36 | --- data/com.canonical.Unity8.gschema.xml 2015-11-24 17:44:18 +0000 |
37 | +++ data/com.canonical.Unity8.gschema.xml 2016-03-11 18:12:46 +0000 |
38 | @@ -27,6 +27,17 @@ |
39 | <summary>Maximum push needed to overcome edge barrier</summary> |
40 | <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description> |
41 | </key> |
42 | + <key type="b" name="autohide-launcher"> |
43 | + <default>true</default> |
44 | + <summary>Autohide the launcher</summary> |
45 | + <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description> |
46 | + </key> |
47 | + <key type="u" name="launcher-width"> |
48 | + <default>8</default> |
49 | + <range min="6" max="12"/> |
50 | + <summary>Width of the launcher in grid units.</summary> |
51 | + <description>Changes the width of the launcher in all usage modes.</description> |
52 | + </key> |
53 | </schema> |
54 | |
55 | <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8"> |
56 | |
57 | === modified file 'data/unity8-dash.conf' |
58 | --- data/unity8-dash.conf 2015-04-21 15:41:09 +0000 |
59 | +++ data/unity8-dash.conf 2016-03-11 18:12:46 +0000 |
60 | @@ -14,6 +14,7 @@ |
61 | oom score 50 |
62 | |
63 | respawn |
64 | +respawn limit unlimited |
65 | |
66 | env APP_ID=unity8-dash |
67 | |
68 | |
69 | === modified file 'debian/changelog' |
70 | --- debian/changelog 2016-03-08 20:59:35 +0000 |
71 | +++ debian/changelog 2016-03-11 18:12:46 +0000 |
72 | @@ -1,3 +1,100 @@ |
73 | +unity8 (8.13+15.04.20150914-0ubuntu1) UNRELEASED; urgency=medium |
74 | + |
75 | + * bump version to fix OOBE build |
76 | + |
77 | + -- Lukas Tinkl <ltinkl@canonical.com> Mon, 14 Sep 2015 19:19:23 +0200 |
78 | + |
79 | +unity8 (8.11+16.04.20160310.4-0ubuntu1) xenial; urgency=medium |
80 | + |
81 | + [ Albert Astals Cid ] |
82 | + * Add context for Re-dock as asked by translators (LP: #1534608) |
83 | + * Add emblem to the preview header widget (LP: #1424720) |
84 | + * Add haptics to ScopesListCategoryItem buttons |
85 | + * Audio Cards: Make some of the image loading async (LP: #1533432) |
86 | + * Do not create fallback code for the card tool fake card (LP: |
87 | + #1545865) |
88 | + * Fix resizing the dash bringing temp scopes size out of sync (LP: |
89 | + #1543130) |
90 | + * Minor fixes for unity-scope-tool |
91 | + * Resolve title alignment on card creator time instead of on runtime |
92 | + * Use fixedHeaderHeight only in the non cardtool cards |
93 | + * Use the new undeprecated connectivityqt::Connectivity |
94 | + * asynchronous is only false on the fake card in cardtool |
95 | + * clazy fixes |
96 | + |
97 | + [ Albert Astals Cid, CI Train Bot ] |
98 | + * click scope: Add the else branch so we reset the card size in all |
99 | + situations |
100 | + |
101 | + [ Andrea Cimitan ] |
102 | + * PreviewSharing widget now accepts both string and array of |
103 | + widgetData["share-data"]["uri"] (LP: #1549056) |
104 | + * Update AP tests for new single preview |
105 | + * Use Text.Wrap for body notification text (LP: #1544909) |
106 | + |
107 | + [ Andrea Cimitan, Lukáš Tinkl, Michael Zanetti, Nick Dedekind ] |
108 | + * some fixes for the new palette (LP: #1554616) |
109 | + |
110 | + [ CI Train Bot ] |
111 | + * Resync trunk. |
112 | + * Update translation template |
113 | + |
114 | + [ CI Train Bot, Daniel d'Andrada ] |
115 | + * Ensure the QML engine doesn't delete our mock MirSurfaces on its |
116 | + own. |
117 | + |
118 | + [ Daniel d'Andrada ] |
119 | + * tst_Shell: Remove unused qml items |
120 | + |
121 | + [ Josh Arenson ] |
122 | + * Allow the shell to blacklist input devices and force the OSK shown. |
123 | + (LP: #1542224) |
124 | + |
125 | + [ Lukáš Tinkl ] |
126 | + * Disallow resizing windows up, past the Panel (LP: #1544766) |
127 | + * Elide the window title not to let it overflow into the indicators |
128 | + area (LP: #1535767) |
129 | + * Enable the PIN lockscreen to be used with a HW keyboard (LP: |
130 | + #1550359) |
131 | + * Fix tiny windows when switching stages |
132 | + * Provide a range of ports to QML JS Debugger |
133 | + * Watch for launcher item icon changes (LP: #1543290) |
134 | + |
135 | + [ Michael Terry ] |
136 | + * Proxy more mouse and touchpad properties to USC (LP: #1540398) (LP: |
137 | + #1543344, #1540398) |
138 | + * Refactor the AccountsService plugin and make it slightly faster. |
139 | + * To let the user log in if a mouse is connected, hide the greeter |
140 | + cover page on a mouse click (but NOT a touch click). (LP: #1540497) |
141 | + * Watch AccountsService for changes to the user's real name. This was |
142 | + preventing us from noticing when the user set their name in the |
143 | + welcome wizard. |
144 | + |
145 | + [ Michael Zanetti ] |
146 | + * Allow alt+tabbing in staged mode too (LP: #1540502) |
147 | + * Allow invoking the staged mode spreads by mouse right edge pushes |
148 | + too (LP: #1540392) |
149 | + * Allow loading the device configuration from an external file |
150 | + * Implement Launcher's keyboard navigation and updated pip design |
151 | + * Make launcher scalable, allow it locking (LP: #1511015) |
152 | + * Properly parent launcher items in all cases (LP: #1495732) |
153 | + * Read inputMethod surface from the new property int QtMir (LP: |
154 | + #1545286) |
155 | + * Some visual updates and rotation lock for the virtual touchpad (LP: |
156 | + #1549087) |
157 | + * Visual updates for the windowed spread (LP: #1488148) |
158 | + * stabilize swipeAwayGreeter() |
159 | + |
160 | + [ Michał Sawicz ] |
161 | + * Add udev rules to make sure we have access to uinput |
162 | + * Make dash respawn indefinitely (LP: #1550056) |
163 | + * Use dpkg-architecture, not arch, to disable touch emulation |
164 | + |
165 | + [ Vesa Rautiainen ] |
166 | + * Fixing the vertical position of desktop spread item icon. |
167 | + |
168 | + -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 10 Mar 2016 22:44:16 +0000 |
169 | + |
170 | unity8 (8.11+16.04.20160308-0ubuntu1) xenial; urgency=medium |
171 | |
172 | [ Albert Astals Cid ] |
173 | |
174 | === modified file 'debian/control' |
175 | --- debian/control 2016-03-04 21:03:43 +0000 |
176 | +++ debian/control 2016-03-11 18:12:46 +0000 |
177 | @@ -8,13 +8,14 @@ |
178 | doxyqml, |
179 | # To allow cross-compiling to work, we also must append :native |
180 | # to g++ so we don't try to run armhf g++ |
181 | -# on an x86 CPU for eaxmple, when cross-compiling. |
182 | +# on an x86 CPU for example, when cross-compiling. |
183 | g++:native, |
184 | libandroid-properties-dev, |
185 | graphviz, |
186 | gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815), |
187 | - libconnectivity-qt1-dev, |
188 | + libconnectivity-qt1-dev (>= 0.7.1), |
189 | libevdev-dev, |
190 | + libgeonames-dev (>= 0.2), |
191 | libgl1-mesa-dev[!armhf] | libgl-dev[!armhf], |
192 | libgl1-mesa-dri, |
193 | libgles2-mesa-dev[armhf], |
194 | @@ -55,7 +56,7 @@ |
195 | qtdeclarative5-qtmultimedia-plugin (>= 5.4.1-1ubuntu19~overlay2), |
196 | qtdeclarative5-ubuntu-content1, |
197 | qtdeclarative5-ubuntu-settings-components (>= 0.7), |
198 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796), |
199 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845), |
200 | qtdeclarative5-ubuntu-web-plugin, |
201 | ttf-ubuntu-font-family, |
202 | Standards-Version: 3.9.4 |
203 | @@ -70,7 +71,7 @@ |
204 | Package: indicators-client |
205 | Architecture: amd64 armhf i386 |
206 | Depends: qmenumodel-qml (>= 0.2.9), |
207 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796), |
208 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845), |
209 | unity8 (= ${binary:Version}), |
210 | ${misc:Depends}, |
211 | ${shlibs:Depends}, |
212 | @@ -101,7 +102,6 @@ |
213 | qml-module-qt-labs-folderlistmodel, |
214 | qml-module-qtquick-xmllistmodel, |
215 | qml-module-qtsysteminfo, |
216 | - qtdeclarative5-gsettings1.0, |
217 | qtdeclarative5-qtmir-plugin (>= 0.4.5), |
218 | qtdeclarative5-ubuntu-telephony0.1, |
219 | qtdeclarative5-ubuntu-web-plugin, |
220 | @@ -128,7 +128,7 @@ |
221 | Depends: qml-module-qtquick-layouts, |
222 | qtdeclarative5-ubuntu-settings-components (>= 0.7), |
223 | qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl, |
224 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796), |
225 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845), |
226 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
227 | ubuntu-thumbnailer-impl-0, |
228 | unity-application-impl-13, |
229 | @@ -158,7 +158,7 @@ |
230 | python3-fixtures, |
231 | python3-gi, |
232 | qttestability-autopilot (>= 1.4), |
233 | - ubuntu-ui-toolkit-autopilot (>= 1.3.1796), |
234 | + ubuntu-ui-toolkit-autopilot (>= 1.3.1845), |
235 | unity-scope-click, |
236 | unity8 (= ${source:Version}), |
237 | unity8-fake-env (= ${source:Version}), |
238 | @@ -192,6 +192,8 @@ |
239 | libhardware2, |
240 | pay-service, |
241 | unity-schemas (>= 7.3.1+14.10.20140915), |
242 | + qtdeclarative5-gsettings1.0, |
243 | + qml-module-qtmultimedia, |
244 | ${misc:Depends}, |
245 | ${shlibs:Depends}, |
246 | Provides: unity-launcher-impl, |
247 | |
248 | === added file 'debian/unity8-common.udev' |
249 | --- debian/unity8-common.udev 1970-01-01 00:00:00 +0000 |
250 | +++ debian/unity8-common.udev 2016-03-11 18:12:46 +0000 |
251 | @@ -0,0 +1,2 @@ |
252 | +# Make local foreground session able to inject input |
253 | +KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess" |
254 | |
255 | === modified file 'debian/unity8-doc.install' |
256 | --- debian/unity8-doc.install 2014-01-30 22:32:37 +0000 |
257 | +++ debian/unity8-doc.install 2016-03-11 18:12:46 +0000 |
258 | @@ -1,1 +1,2 @@ |
259 | +doc/devices.conf usr/share/doc/unity8/ |
260 | usr/share/doc/unity8/* |
261 | |
262 | === added file 'doc/devices.conf' |
263 | --- doc/devices.conf 1970-01-01 00:00:00 +0000 |
264 | +++ doc/devices.conf 2016-03-11 18:12:46 +0000 |
265 | @@ -0,0 +1,30 @@ |
266 | +# This file can hold multiple device configs. Devices are separated by sections. |
267 | +# |
268 | +# SupportedOrientations holds a list of all enabled orientations. A standard |
269 | +# phone will usually have Portrait,Landcape,InvertedLandscape in order to |
270 | +# disable upside down usage. |
271 | +# |
272 | +# PrimaryOrientation gives the orientation the device will start up with |
273 | +# when there is no orientations sensor input available (yet) or lock to |
274 | +# when an application specifies to be locked to PrimaryOrientation. |
275 | +# |
276 | +# The other Orientation settings can be used to re-map the orientations. |
277 | +# A device might be used with different orientations than how the screen |
278 | +# is physically mounted on the hardware. |
279 | +# |
280 | +# Category can be phone, tablet, or desktop. This option determines |
281 | +# whether the side stage is shown (tablet) or not (phone). Using |
282 | +# desktop will load the shell in windowed mode. Note that the user |
283 | +# can override/change this by connecting input hardware or change |
284 | +# user settings. |
285 | +# |
286 | +# Any options not listed will default to the values of the example below. |
287 | + |
288 | +[devicename] |
289 | +SupportedOrientations=Portrait,InvertedPortrait,Landscape,InvertedLandscape |
290 | +PrimaryOrientation=PrimaryOrienation |
291 | +PortraitOrientation=Portrait |
292 | +InvertedPortraitOrientation=InvertedPortrait |
293 | +LandscapeOrientation=Landscape |
294 | +InvertedLandscapeOrientation=InvertedLandscape |
295 | +Category=phone |
296 | |
297 | === modified file 'plugins/AccountsService/AccountsService.cpp' |
298 | --- plugins/AccountsService/AccountsService.cpp 2016-01-21 21:04:00 +0000 |
299 | +++ plugins/AccountsService/AccountsService.cpp 2016-03-11 18:12:46 +0000 |
300 | @@ -1,5 +1,5 @@ |
301 | /* |
302 | - * Copyright (C) 2013 Canonical, Ltd. |
303 | + * Copyright (C) 2013, 2015 Canonical, Ltd. |
304 | * |
305 | * This program is free software; you can redistribute it and/or modify |
306 | * it under the terms of the GNU General Public License as published by |
307 | @@ -12,8 +12,6 @@ |
308 | * |
309 | * You should have received a copy of the GNU General Public License |
310 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
311 | - * |
312 | - * Author: Michael Terry <michael.terry@canonical.com> |
313 | */ |
314 | |
315 | #include "AccountsService.h" |
316 | @@ -24,17 +22,55 @@ |
317 | #include <QStringList> |
318 | #include <QDebug> |
319 | |
320 | +#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User") |
321 | +#define IFACE_LOCATION_HERE QStringLiteral("com.ubuntu.location.providers.here.AccountsService") |
322 | +#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input") |
323 | +#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy") |
324 | +#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy") |
325 | +#define IFACE_UNITY QStringLiteral("com.canonical.unity.AccountsService") |
326 | +#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private") |
327 | + |
328 | +#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile") |
329 | +#define PROP_DEMO_EDGES QStringLiteral("demo-edges") |
330 | +#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted") |
331 | +#define PROP_EMAIL QStringLiteral("Email") |
332 | +#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked") |
333 | +#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked") |
334 | +#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins") |
335 | +#define PROP_LICENSE_ACCEPTED QStringLiteral("LicenseAccepted") |
336 | +#define PROP_LICENSE_BASE_PATH QStringLiteral("LicenseBasePath") |
337 | +#define PROP_MOUSE_CURSOR_SPEED QStringLiteral("MouseCursorSpeed") |
338 | +#define PROP_MOUSE_DOUBLE_CLICK_SPEED QStringLiteral("MouseDoubleClickSpeed") |
339 | +#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton") |
340 | +#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed") |
341 | +#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint") |
342 | +#define PROP_REAL_NAME QStringLiteral("RealName") |
343 | +#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen") |
344 | +#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed") |
345 | +#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping") |
346 | +#define PROP_TOUCHPAD_DISABLE_WITH_MOUSE QStringLiteral("TouchpadDisableWithMouse") |
347 | +#define PROP_TOUCHPAD_DOUBLE_CLICK_SPEED QStringLiteral("TouchpadDoubleClickSpeed") |
348 | +#define PROP_TOUCHPAD_PRIMARY_BUTTON QStringLiteral("TouchpadPrimaryButton") |
349 | +#define PROP_TOUCHPAD_SCROLL_SPEED QStringLiteral("TouchpadScrollSpeed") |
350 | +#define PROP_TOUCHPAD_TAP_TO_CLICK QStringLiteral("TouchpadTapToClick") |
351 | +#define PROP_TOUCHPAD_TWO_FINGER_SCROLL QStringLiteral("TouchpadTwoFingerScroll") |
352 | + |
353 | + |
354 | +QVariant primaryButtonConverter(const QVariant &value) |
355 | +{ |
356 | + QString stringValue = value.toString(); |
357 | + if (stringValue == "left") { |
358 | + return QVariant::fromValue(0); |
359 | + } else if (stringValue == "right") { |
360 | + return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same |
361 | + } else { |
362 | + return QVariant::fromValue(0); // default to left |
363 | + } |
364 | +} |
365 | + |
366 | AccountsService::AccountsService(QObject* parent, const QString &user) |
367 | - : QObject(parent), |
368 | - m_service(new AccountsServiceDBusAdaptor(this)), |
369 | - m_demoEdges(false), |
370 | - m_enableLauncherWhileLocked(false), |
371 | - m_enableIndicatorsWhileLocked(false), |
372 | - m_statsWelcomeScreen(false), |
373 | - m_passwordDisplayHint(Keyboard), |
374 | - m_failedLogins(0), |
375 | - m_hereEnabled(false), |
376 | - m_hereLicensePath() // null means not set yet |
377 | + : QObject(parent) |
378 | + , m_service(new AccountsServiceDBusAdaptor(this)) |
379 | { |
380 | m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"), |
381 | QStringLiteral("/com/canonical/Unity/Input"), |
382 | @@ -44,6 +80,46 @@ |
383 | connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged); |
384 | connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged); |
385 | |
386 | + registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged")); |
387 | + registerProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, QStringLiteral("emailChanged")); |
388 | + registerProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, QStringLiteral("realNameChanged")); |
389 | + registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged")); |
390 | + registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged")); |
391 | + registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged")); |
392 | + registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged")); |
393 | + registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged")); |
394 | + registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged")); |
395 | + registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged")); |
396 | + registerProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, QStringLiteral("demoEdgesCompletedChanged")); |
397 | + registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged")); |
398 | + |
399 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED, |
400 | + m_unityInput, QStringLiteral("setMouseCursorSpeed")); |
401 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_DOUBLE_CLICK_SPEED, |
402 | + m_unityInput, QStringLiteral("setMouseDoubleClickSpeed")); |
403 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_PRIMARY_BUTTON, |
404 | + m_unityInput, QStringLiteral("setMousePrimaryButton"), |
405 | + primaryButtonConverter); |
406 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_SCROLL_SPEED, |
407 | + m_unityInput, QStringLiteral("setMouseScrollSpeed")); |
408 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED, |
409 | + m_unityInput, QStringLiteral("setTouchpadCursorSpeed")); |
410 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_SCROLL_SPEED, |
411 | + m_unityInput, QStringLiteral("setTouchpadScrollSpeed")); |
412 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WHILE_TYPING, |
413 | + m_unityInput, QStringLiteral("setTouchpadDisableWhileTyping")); |
414 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WITH_MOUSE, |
415 | + m_unityInput, QStringLiteral("setTouchpadDisableWithMouse")); |
416 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DOUBLE_CLICK_SPEED, |
417 | + m_unityInput, QStringLiteral("setTouchpadDoubleClickSpeed")); |
418 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_PRIMARY_BUTTON, |
419 | + m_unityInput, QStringLiteral("setTouchpadPrimaryButton"), |
420 | + primaryButtonConverter); |
421 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TAP_TO_CLICK, |
422 | + m_unityInput, QStringLiteral("setTouchpadTapToClick")); |
423 | + registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TWO_FINGER_SCROLL, |
424 | + m_unityInput, QStringLiteral("setTouchpadTwoFingerScroll")); |
425 | + |
426 | setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER"))); |
427 | } |
428 | |
429 | @@ -57,410 +133,236 @@ |
430 | if (user.isEmpty() || m_user == user) |
431 | return; |
432 | |
433 | + bool wasEmpty = m_user.isEmpty(); |
434 | + |
435 | m_user = user; |
436 | Q_EMIT userChanged(); |
437 | |
438 | - updateDemoEdges(false); |
439 | - updateEnableLauncherWhileLocked(false); |
440 | - updateEnableIndicatorsWhileLocked(false); |
441 | - updateBackgroundFile(false); |
442 | - updateMouseCursorSpeed(); |
443 | - updateTouchpadCursorSpeed(); |
444 | - updateStatsWelcomeScreen(false); |
445 | - updatePasswordDisplayHint(false); |
446 | - updateFailedLogins(false); |
447 | - updateHereEnabled(false); |
448 | - updateHereLicensePath(false); |
449 | + // Do the first update synchronously, as a cheap way to block rendering |
450 | + // until we have the right values on bootup. |
451 | + refresh(!wasEmpty); |
452 | } |
453 | |
454 | bool AccountsService::demoEdges() const |
455 | { |
456 | - return m_demoEdges; |
457 | + auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES); |
458 | + return value.toBool(); |
459 | } |
460 | |
461 | void AccountsService::setDemoEdges(bool demoEdges) |
462 | { |
463 | - if (m_demoEdges != demoEdges) { |
464 | - m_demoEdges = demoEdges; |
465 | - m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService"), QStringLiteral("demo-edges"), demoEdges); |
466 | - |
467 | - Q_EMIT demoEdgesChanged(); |
468 | + setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges); |
469 | +} |
470 | + |
471 | +QStringList AccountsService::demoEdgesCompleted() const |
472 | +{ |
473 | + auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED); |
474 | + return value.toStringList(); |
475 | +} |
476 | + |
477 | +void AccountsService::markDemoEdgeCompleted(const QString &edge) |
478 | +{ |
479 | + auto currentList = demoEdgesCompleted(); |
480 | + if (!currentList.contains(edge)) { |
481 | + setProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, currentList << edge); |
482 | } |
483 | } |
484 | |
485 | bool AccountsService::enableLauncherWhileLocked() const |
486 | { |
487 | - return m_enableLauncherWhileLocked; |
488 | + auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED); |
489 | + return value.toBool(); |
490 | } |
491 | |
492 | bool AccountsService::enableIndicatorsWhileLocked() const |
493 | { |
494 | - return m_enableIndicatorsWhileLocked; |
495 | + auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED); |
496 | + return value.toBool(); |
497 | } |
498 | |
499 | QString AccountsService::backgroundFile() const |
500 | { |
501 | - return m_backgroundFile; |
502 | + auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE); |
503 | + return value.toString(); |
504 | } |
505 | |
506 | bool AccountsService::statsWelcomeScreen() const |
507 | { |
508 | - return m_statsWelcomeScreen; |
509 | + auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN); |
510 | + return value.toBool(); |
511 | } |
512 | |
513 | AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const |
514 | { |
515 | - return m_passwordDisplayHint; |
516 | + auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT); |
517 | + return (PasswordDisplayHint)value.toInt(); |
518 | } |
519 | |
520 | bool AccountsService::hereEnabled() const |
521 | { |
522 | - return m_hereEnabled; |
523 | + auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED); |
524 | + return value.toBool(); |
525 | } |
526 | |
527 | void AccountsService::setHereEnabled(bool enabled) |
528 | { |
529 | - if (m_hereEnabled != enabled) { |
530 | - m_hereEnabled = enabled; |
531 | - m_service->setUserPropertyAsync(m_user, QStringLiteral("com.ubuntu.location.providers.here.AccountsService"), QStringLiteral("LicenseAccepted"), enabled); |
532 | - |
533 | - Q_EMIT hereEnabledChanged(); |
534 | - } |
535 | + setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled); |
536 | } |
537 | |
538 | QString AccountsService::hereLicensePath() const |
539 | { |
540 | - return m_hereLicensePath; |
541 | + auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH); |
542 | + QString hereLicensePath = value.toString(); |
543 | + if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath)) |
544 | + hereLicensePath = QStringLiteral(""); |
545 | + return hereLicensePath; |
546 | } |
547 | |
548 | bool AccountsService::hereLicensePathValid() const |
549 | { |
550 | - return !m_hereLicensePath.isNull(); |
551 | -} |
552 | - |
553 | -void AccountsService::updateDemoEdges(bool async) |
554 | -{ |
555 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
556 | - QStringLiteral("com.canonical.unity.AccountsService"), |
557 | - QStringLiteral("demo-edges")); |
558 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
559 | - |
560 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
561 | - this, [this](QDBusPendingCallWatcher* watcher) { |
562 | - |
563 | - QDBusPendingReply<QDBusVariant> reply = *watcher; |
564 | - watcher->deleteLater(); |
565 | - if (reply.isError()) { |
566 | - qWarning() << "Failed to get 'demo-edges' property - " << reply.error().message(); |
567 | - return; |
568 | - } |
569 | - |
570 | - auto demoEdges = reply.value().variant().toBool(); |
571 | - if (m_demoEdges != demoEdges) { |
572 | - m_demoEdges = demoEdges; |
573 | - Q_EMIT demoEdgesChanged(); |
574 | - } |
575 | - }); |
576 | - if (!async) { |
577 | - watcher->waitForFinished(); |
578 | - delete watcher; |
579 | - } |
580 | -} |
581 | - |
582 | -void AccountsService::updateEnableLauncherWhileLocked(bool async) |
583 | -{ |
584 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
585 | - QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"), |
586 | - QStringLiteral("EnableLauncherWhileLocked")); |
587 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
588 | - |
589 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
590 | - this, [this](QDBusPendingCallWatcher* watcher) { |
591 | - |
592 | - QDBusPendingReply<QVariant> reply = *watcher; |
593 | - watcher->deleteLater(); |
594 | - if (reply.isError()) { |
595 | - qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message(); |
596 | - return; |
597 | - } |
598 | - |
599 | - const bool enableLauncherWhileLocked = reply.value().toBool(); |
600 | - if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) { |
601 | - m_enableLauncherWhileLocked = enableLauncherWhileLocked; |
602 | - Q_EMIT enableLauncherWhileLockedChanged(); |
603 | - } |
604 | - }); |
605 | - if (!async) { |
606 | - watcher->waitForFinished(); |
607 | - delete watcher; |
608 | - } |
609 | -} |
610 | - |
611 | -void AccountsService::updateEnableIndicatorsWhileLocked(bool async) |
612 | -{ |
613 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
614 | - QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"), |
615 | - QStringLiteral("EnableIndicatorsWhileLocked")); |
616 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
617 | - |
618 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
619 | - this, [this](QDBusPendingCallWatcher* watcher) { |
620 | - |
621 | - QDBusPendingReply<QVariant> reply = *watcher; |
622 | - watcher->deleteLater(); |
623 | - if (reply.isError()) { |
624 | - qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message(); |
625 | - return; |
626 | - } |
627 | - |
628 | - const bool enableIndicatorsWhileLocked = reply.value().toBool(); |
629 | - if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) { |
630 | - m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked; |
631 | - Q_EMIT enableIndicatorsWhileLockedChanged(); |
632 | - } |
633 | - }); |
634 | - if (!async) { |
635 | - watcher->waitForFinished(); |
636 | - delete watcher; |
637 | - } |
638 | -} |
639 | - |
640 | -void AccountsService::updateBackgroundFile(bool async) |
641 | -{ |
642 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
643 | - QStringLiteral("org.freedesktop.Accounts.User"), |
644 | - QStringLiteral("BackgroundFile")); |
645 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
646 | - |
647 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
648 | - this, [this](QDBusPendingCallWatcher* watcher) { |
649 | - |
650 | - QDBusPendingReply<QVariant> reply = *watcher; |
651 | - watcher->deleteLater(); |
652 | - if (reply.isError()) { |
653 | - qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message(); |
654 | - return; |
655 | - } |
656 | - |
657 | - const QString backgroundFile = reply.value().toString(); |
658 | - if (m_backgroundFile != backgroundFile) { |
659 | - m_backgroundFile = backgroundFile; |
660 | - Q_EMIT backgroundFileChanged(); |
661 | - } |
662 | - }); |
663 | - if (!async) { |
664 | - watcher->waitForFinished(); |
665 | - delete watcher; |
666 | - } |
667 | -} |
668 | - |
669 | -void AccountsService::updateMouseCursorSpeed() |
670 | -{ |
671 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
672 | - QStringLiteral("com.ubuntu.AccountsService.Input"), |
673 | - QStringLiteral("MouseCursorSpeed")); |
674 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
675 | - |
676 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
677 | - this, [this](QDBusPendingCallWatcher* watcher) { |
678 | - |
679 | - QDBusPendingReply<QVariant> reply = *watcher; |
680 | - watcher->deleteLater(); |
681 | - if (reply.isError()) { |
682 | - qWarning() << "Failed to get 'MouseCursorSpeed' property - " << reply.error().message(); |
683 | - return; |
684 | - } |
685 | - |
686 | - // Merely proxy this along to USC. We don't care about keeping a copy |
687 | - // or exporting it internally. |
688 | - m_unityInput->asyncCall(QStringLiteral("setMouseCursorSpeed"), reply.value()); |
689 | - }); |
690 | -} |
691 | - |
692 | -void AccountsService::updateTouchpadCursorSpeed() |
693 | -{ |
694 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
695 | - QStringLiteral("com.ubuntu.AccountsService.Input"), |
696 | - QStringLiteral("TouchpadCursorSpeed")); |
697 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
698 | - |
699 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
700 | - this, [this](QDBusPendingCallWatcher* watcher) { |
701 | - |
702 | - QDBusPendingReply<QVariant> reply = *watcher; |
703 | - watcher->deleteLater(); |
704 | - if (reply.isError()) { |
705 | - qWarning() << "Failed to get 'TouchpadCursorSpeed' property - " << reply.error().message(); |
706 | - return; |
707 | - } |
708 | - |
709 | - // Merely proxy this along to USC. We don't care about keeping a copy |
710 | - // or exporting it internally. |
711 | - m_unityInput->asyncCall(QStringLiteral("setTouchpadCursorSpeed"), reply.value()); |
712 | - }); |
713 | -} |
714 | - |
715 | -void AccountsService::updateStatsWelcomeScreen(bool async) |
716 | -{ |
717 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
718 | - QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy"), |
719 | - QStringLiteral("StatsWelcomeScreen")); |
720 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
721 | - |
722 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
723 | - this, [this](QDBusPendingCallWatcher* watcher) { |
724 | - |
725 | - QDBusPendingReply<QVariant> reply = *watcher; |
726 | - watcher->deleteLater(); |
727 | - if (reply.isError()) { |
728 | - qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message(); |
729 | - return; |
730 | - } |
731 | - |
732 | - const bool statsWelcomeScreen = reply.value().toBool(); |
733 | - if (m_statsWelcomeScreen != statsWelcomeScreen) { |
734 | - m_statsWelcomeScreen = statsWelcomeScreen; |
735 | - Q_EMIT statsWelcomeScreenChanged(); |
736 | - } |
737 | - }); |
738 | - if (!async) { |
739 | - watcher->waitForFinished(); |
740 | - delete watcher; |
741 | - } |
742 | -} |
743 | - |
744 | -void AccountsService::updatePasswordDisplayHint(bool async) |
745 | -{ |
746 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
747 | - QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"), |
748 | - QStringLiteral("PasswordDisplayHint")); |
749 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
750 | - |
751 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
752 | - this, [this](QDBusPendingCallWatcher* watcher) { |
753 | - |
754 | - QDBusPendingReply<QVariant> reply = *watcher; |
755 | - watcher->deleteLater(); |
756 | - if (reply.isError()) { |
757 | - qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message(); |
758 | - return; |
759 | - } |
760 | - |
761 | - const PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().toInt(); |
762 | - if (m_passwordDisplayHint != passwordDisplayHint) { |
763 | - m_passwordDisplayHint = passwordDisplayHint; |
764 | - Q_EMIT passwordDisplayHintChanged(); |
765 | - } |
766 | - }); |
767 | - if (!async) { |
768 | - watcher->waitForFinished(); |
769 | - delete watcher; |
770 | - } |
771 | -} |
772 | - |
773 | -void AccountsService::updateFailedLogins(bool async) |
774 | -{ |
775 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
776 | - QStringLiteral("com.canonical.unity.AccountsService.Private"), |
777 | - QStringLiteral("FailedLogins")); |
778 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
779 | - |
780 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
781 | - this, [this](QDBusPendingCallWatcher* watcher) { |
782 | - |
783 | - QDBusPendingReply<QVariant> reply = *watcher; |
784 | - watcher->deleteLater(); |
785 | - if (reply.isError()) { |
786 | - qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message(); |
787 | - return; |
788 | - } |
789 | - |
790 | - const uint failedLogins = reply.value().toUInt(); |
791 | - if (m_failedLogins != failedLogins) { |
792 | - m_failedLogins = failedLogins; |
793 | - Q_EMIT failedLoginsChanged(); |
794 | - } |
795 | - }); |
796 | - if (!async) { |
797 | - watcher->waitForFinished(); |
798 | - delete watcher; |
799 | - } |
800 | -} |
801 | - |
802 | -void AccountsService::updateHereEnabled(bool async) |
803 | -{ |
804 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
805 | - QStringLiteral("com.ubuntu.location.providers.here.AccountsService"), |
806 | - QStringLiteral("LicenseAccepted")); |
807 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
808 | - |
809 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
810 | - this, [this](QDBusPendingCallWatcher* watcher) { |
811 | - |
812 | - QDBusPendingReply<QVariant> reply = *watcher; |
813 | - watcher->deleteLater(); |
814 | - if (reply.isError()) { |
815 | - qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message(); |
816 | - return; |
817 | - } |
818 | - |
819 | - const bool hereEnabled = reply.value().toBool(); |
820 | - if (m_hereEnabled != hereEnabled) { |
821 | - m_hereEnabled = hereEnabled; |
822 | - Q_EMIT hereEnabledChanged(); |
823 | - } |
824 | - }); |
825 | - if (!async) { |
826 | - watcher->waitForFinished(); |
827 | - delete watcher; |
828 | - } |
829 | -} |
830 | - |
831 | -void AccountsService::updateHereLicensePath(bool async) |
832 | -{ |
833 | - QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
834 | - QStringLiteral("com.ubuntu.location.providers.here.AccountsService"), |
835 | - QStringLiteral("LicenseBasePath")); |
836 | - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
837 | - |
838 | - connect(watcher, &QDBusPendingCallWatcher::finished, |
839 | - this, [this](QDBusPendingCallWatcher* watcher) { |
840 | - |
841 | - QDBusPendingReply<QVariant> reply = *watcher; |
842 | - watcher->deleteLater(); |
843 | - if (reply.isError()) { |
844 | - qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message(); |
845 | - return; |
846 | - } |
847 | - |
848 | - QString hereLicensePath = reply.value().toString(); |
849 | - if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath)) |
850 | - hereLicensePath = QLatin1String(""); |
851 | - |
852 | - if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) { |
853 | - m_hereLicensePath = hereLicensePath; |
854 | - Q_EMIT hereLicensePathChanged(); |
855 | - } |
856 | - }); |
857 | - if (!async) { |
858 | - watcher->waitForFinished(); |
859 | - delete watcher; |
860 | - } |
861 | + auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH); |
862 | + return !value.toString().isNull(); |
863 | +} |
864 | + |
865 | +QString AccountsService::realName() const |
866 | +{ |
867 | + auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME); |
868 | + return value.toString(); |
869 | +} |
870 | + |
871 | +void AccountsService::setRealName(const QString &realName) |
872 | +{ |
873 | + setProperty(IFACE_ACCOUNTS_USER, PROP_REAL_NAME, realName); |
874 | +} |
875 | + |
876 | +QString AccountsService::email() const |
877 | +{ |
878 | + auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL); |
879 | + return value.toString(); |
880 | +} |
881 | + |
882 | +void AccountsService::setEmail(const QString &email) |
883 | +{ |
884 | + setProperty(IFACE_ACCOUNTS_USER, PROP_EMAIL, email); |
885 | } |
886 | |
887 | uint AccountsService::failedLogins() const |
888 | { |
889 | - return m_failedLogins; |
890 | + return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt(); |
891 | } |
892 | |
893 | void AccountsService::setFailedLogins(uint failedLogins) |
894 | { |
895 | - if (m_failedLogins != failedLogins) { |
896 | - m_failedLogins = failedLogins; |
897 | - m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService.Private"), QStringLiteral("FailedLogins"), failedLogins); |
898 | - |
899 | - Q_EMIT failedLoginsChanged(); |
900 | - } |
901 | + setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins); |
902 | +} |
903 | + |
904 | +// ==================================================== |
905 | +// Everything below this line is generic helper methods |
906 | +// ==================================================== |
907 | + |
908 | +void AccountsService::emitChangedForProperty(const QString &interface, const QString &property) |
909 | +{ |
910 | + QString signalName = m_properties[interface][property].signal; |
911 | + QMetaObject::invokeMethod(this, signalName.toUtf8().data()); |
912 | +} |
913 | + |
914 | +QVariant AccountsService::getProperty(const QString &interface, const QString &property) const |
915 | +{ |
916 | + return m_properties[interface][property].value; |
917 | +} |
918 | + |
919 | +void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value) |
920 | +{ |
921 | + if (m_properties[interface][property].value != value) { |
922 | + m_properties[interface][property].value = value; |
923 | + m_service->setUserPropertyAsync(m_user, interface, property, value); |
924 | + emitChangedForProperty(interface, property); |
925 | + } |
926 | +} |
927 | + |
928 | +void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value) |
929 | +{ |
930 | + PropertyInfo &info = m_properties[interface][property]; |
931 | + |
932 | + if (info.proxyInterface) { |
933 | + QVariant finalValue; |
934 | + if (info.proxyConverter) { |
935 | + finalValue = info.proxyConverter(value); |
936 | + } else { |
937 | + finalValue = value; |
938 | + } |
939 | + info.proxyInterface->asyncCall(info.proxyMethod, finalValue); |
940 | + return; // don't bother saving a copy |
941 | + } |
942 | + |
943 | + if (info.value != value) { |
944 | + info.value = value; |
945 | + emitChangedForProperty(interface, property); |
946 | + } |
947 | +} |
948 | + |
949 | +void AccountsService::updateProperty(const QString &interface, const QString &property) |
950 | +{ |
951 | + QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user, |
952 | + interface, |
953 | + property); |
954 | + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
955 | + |
956 | + connect(watcher, &QDBusPendingCallWatcher::finished, |
957 | + this, [this, interface, property](QDBusPendingCallWatcher* watcher) { |
958 | + |
959 | + QDBusPendingReply<QVariant> reply = *watcher; |
960 | + watcher->deleteLater(); |
961 | + if (reply.isError()) { |
962 | + qWarning() << "Failed to get '" << property << "' property:" << reply.error().message(); |
963 | + return; |
964 | + } |
965 | + |
966 | + updateCache(interface, property, reply.value()); |
967 | + }); |
968 | +} |
969 | + |
970 | +void AccountsService::updateAllProperties(const QString &interface, bool async) |
971 | +{ |
972 | + QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user, |
973 | + interface); |
974 | + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
975 | + |
976 | + connect(watcher, &QDBusPendingCallWatcher::finished, |
977 | + this, [this, interface](QDBusPendingCallWatcher* watcher) { |
978 | + |
979 | + QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher; |
980 | + watcher->deleteLater(); |
981 | + if (reply.isError()) { |
982 | + qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message(); |
983 | + return; |
984 | + } |
985 | + |
986 | + auto valueHash = reply.value(); |
987 | + auto i = valueHash.constBegin(); |
988 | + while (i != valueHash.constEnd()) { |
989 | + updateCache(interface, i.key(), i.value()); |
990 | + ++i; |
991 | + } |
992 | + }); |
993 | + if (!async) { |
994 | + watcher->waitForFinished(); |
995 | + } |
996 | +} |
997 | + |
998 | +void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter) |
999 | +{ |
1000 | + registerProperty(interface, property, nullptr); |
1001 | + |
1002 | + m_properties[interface][property].proxyInterface = iface; |
1003 | + m_properties[interface][property].proxyMethod = method; |
1004 | + m_properties[interface][property].proxyConverter = converter; |
1005 | +} |
1006 | + |
1007 | +void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal) |
1008 | +{ |
1009 | + m_properties[interface][property] = PropertyInfo(); |
1010 | + m_properties[interface][property].signal = signal; |
1011 | } |
1012 | |
1013 | void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed) |
1014 | @@ -469,42 +371,13 @@ |
1015 | return; |
1016 | } |
1017 | |
1018 | - if (interface == QLatin1String("com.canonical.unity.AccountsService")) { |
1019 | - if (changed.contains(QStringLiteral("demo-edges"))) { |
1020 | - updateDemoEdges(); |
1021 | - } |
1022 | - } else if (interface == QLatin1String("com.canonical.unity.AccountsService.Private")) { |
1023 | - if (changed.contains(QStringLiteral("FailedLogins"))) { |
1024 | - updateFailedLogins(); |
1025 | - } |
1026 | - } else if (interface == QLatin1String("com.ubuntu.AccountsService.Input")) { |
1027 | - if (changed.contains(QStringLiteral("MouseCursorSpeed"))) { |
1028 | - updateMouseCursorSpeed(); |
1029 | - } |
1030 | - if (changed.contains(QStringLiteral("TouchpadCursorSpeed"))) { |
1031 | - updateTouchpadCursorSpeed(); |
1032 | - } |
1033 | - } else if (interface == QLatin1String("com.ubuntu.touch.AccountsService.SecurityPrivacy")) { |
1034 | - if (changed.contains(QStringLiteral("StatsWelcomeScreen"))) { |
1035 | - updateStatsWelcomeScreen(); |
1036 | - } |
1037 | - } else if (interface == QLatin1String("com.ubuntu.AccountsService.SecurityPrivacy")) { |
1038 | - if (changed.contains(QStringLiteral("PasswordDisplayHint"))) { |
1039 | - updatePasswordDisplayHint(); |
1040 | - } |
1041 | - if (changed.contains(QStringLiteral("EnableLauncherWhileLocked"))) { |
1042 | - updateEnableLauncherWhileLocked(); |
1043 | - } |
1044 | - if (changed.contains(QStringLiteral("EnableIndicatorsWhileLocked"))) { |
1045 | - updateEnableIndicatorsWhileLocked(); |
1046 | - } |
1047 | - } else if (interface == QLatin1String("com.ubuntu.location.providers.here.AccountsService")) { |
1048 | - if (changed.contains(QStringLiteral("LicenseAccepted"))) { |
1049 | - updateHereEnabled(); |
1050 | - } |
1051 | - if (changed.contains(QStringLiteral("LicenseBasePath"))) { |
1052 | - updateHereLicensePath(); |
1053 | - } |
1054 | + auto propHash = m_properties.value(interface); |
1055 | + auto i = propHash.constBegin(); |
1056 | + while (i != propHash.constEnd()) { |
1057 | + if (changed.contains(i.key())) { |
1058 | + updateProperty(interface, i.key()); |
1059 | + } |
1060 | + ++i; |
1061 | } |
1062 | } |
1063 | |
1064 | @@ -514,6 +387,20 @@ |
1065 | return; |
1066 | } |
1067 | |
1068 | - // Standard properties might have changed |
1069 | - updateBackgroundFile(); |
1070 | + // Any of the standard properties might have changed! |
1071 | + auto propHash = m_properties.value(IFACE_ACCOUNTS_USER); |
1072 | + auto i = propHash.constBegin(); |
1073 | + while (i != propHash.constEnd()) { |
1074 | + updateProperty(IFACE_ACCOUNTS_USER, i.key()); |
1075 | + ++i; |
1076 | + } |
1077 | +} |
1078 | + |
1079 | +void AccountsService::refresh(bool async) |
1080 | +{ |
1081 | + auto i = m_properties.constBegin(); |
1082 | + while (i != m_properties.constEnd()) { |
1083 | + updateAllProperties(i.key(), async); |
1084 | + ++i; |
1085 | + } |
1086 | } |
1087 | |
1088 | === modified file 'plugins/AccountsService/AccountsService.h' |
1089 | --- plugins/AccountsService/AccountsService.h 2016-01-21 21:04:00 +0000 |
1090 | +++ plugins/AccountsService/AccountsService.h 2016-03-11 18:12:46 +0000 |
1091 | @@ -1,5 +1,5 @@ |
1092 | /* |
1093 | - * Copyright (C) 2013 Canonical, Ltd. |
1094 | + * Copyright (C) 2013, 2015 Canonical, Ltd. |
1095 | * |
1096 | * This program is free software; you can redistribute it and/or modify |
1097 | * it under the terms of the GNU General Public License as published by |
1098 | @@ -12,15 +12,16 @@ |
1099 | * |
1100 | * You should have received a copy of the GNU General Public License |
1101 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1102 | - * |
1103 | - * Authors: Michael Terry <michael.terry@canonical.com> |
1104 | */ |
1105 | |
1106 | #ifndef UNITY_ACCOUNTSSERVICE_H |
1107 | #define UNITY_ACCOUNTSSERVICE_H |
1108 | |
1109 | +#include <QHash> |
1110 | #include <QObject> |
1111 | #include <QString> |
1112 | +#include <QStringList> |
1113 | +#include <QVariant> |
1114 | |
1115 | class AccountsServiceDBusAdaptor; |
1116 | class QDBusInterface; |
1117 | @@ -37,6 +38,9 @@ |
1118 | READ demoEdges |
1119 | WRITE setDemoEdges |
1120 | NOTIFY demoEdgesChanged) |
1121 | + Q_PROPERTY (QStringList demoEdgesCompleted |
1122 | + READ demoEdgesCompleted |
1123 | + NOTIFY demoEdgesCompletedChanged) |
1124 | Q_PROPERTY (bool enableLauncherWhileLocked |
1125 | READ enableLauncherWhileLocked |
1126 | NOTIFY enableLauncherWhileLockedChanged) |
1127 | @@ -66,6 +70,8 @@ |
1128 | Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that |
1129 | READ hereLicensePathValid |
1130 | NOTIFY hereLicensePathChanged) |
1131 | + Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged) |
1132 | + Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged) |
1133 | |
1134 | public: |
1135 | enum PasswordDisplayHint { |
1136 | @@ -80,6 +86,8 @@ |
1137 | void setUser(const QString &user); |
1138 | bool demoEdges() const; |
1139 | void setDemoEdges(bool demoEdges); |
1140 | + QStringList demoEdgesCompleted() const; |
1141 | + Q_INVOKABLE void markDemoEdgeCompleted(const QString &edge); |
1142 | bool enableLauncherWhileLocked() const; |
1143 | bool enableIndicatorsWhileLocked() const; |
1144 | QString backgroundFile() const; |
1145 | @@ -91,10 +99,15 @@ |
1146 | void setHereEnabled(bool enabled); |
1147 | QString hereLicensePath() const; |
1148 | bool hereLicensePathValid() const; |
1149 | + QString realName() const; |
1150 | + void setRealName(const QString &realName); |
1151 | + QString email() const; |
1152 | + void setEmail(const QString &email); |
1153 | |
1154 | Q_SIGNALS: |
1155 | void userChanged(); |
1156 | void demoEdgesChanged(); |
1157 | + void demoEdgesCompletedChanged(); |
1158 | void enableLauncherWhileLockedChanged(); |
1159 | void enableIndicatorsWhileLockedChanged(); |
1160 | void backgroundFileChanged(); |
1161 | @@ -103,36 +116,41 @@ |
1162 | void failedLoginsChanged(); |
1163 | void hereEnabledChanged(); |
1164 | void hereLicensePathChanged(); |
1165 | + void realNameChanged(); |
1166 | + void emailChanged(); |
1167 | |
1168 | private Q_SLOTS: |
1169 | void onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed); |
1170 | void onMaybeChanged(const QString &user); |
1171 | |
1172 | private: |
1173 | - void updateDemoEdges(bool async = true); |
1174 | - void updateEnableLauncherWhileLocked(bool async = true); |
1175 | - void updateEnableIndicatorsWhileLocked(bool async = true); |
1176 | - void updateBackgroundFile(bool async = true); |
1177 | - void updateMouseCursorSpeed(); |
1178 | - void updateTouchpadCursorSpeed(); |
1179 | - void updateStatsWelcomeScreen(bool async = true); |
1180 | - void updatePasswordDisplayHint(bool async = true); |
1181 | - void updateFailedLogins(bool async = true); |
1182 | - void updateHereEnabled(bool async = true); |
1183 | - void updateHereLicensePath(bool async = true); |
1184 | - |
1185 | + typedef QVariant (*ProxyConverter)(const QVariant &); |
1186 | + |
1187 | + void refresh(bool async); |
1188 | + void registerProperty(const QString &interface, const QString &property, const QString &signal); |
1189 | + void registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter = nullptr); |
1190 | + |
1191 | + void updateAllProperties(const QString &interface, bool async); |
1192 | + void updateProperty(const QString &interface, const QString &property); |
1193 | + void updateCache(const QString &interface, const QString &property, const QVariant &value); |
1194 | + |
1195 | + void setProperty(const QString &interface, const QString &property, const QVariant &value); |
1196 | + QVariant getProperty(const QString &interface, const QString &property) const; |
1197 | + |
1198 | + void emitChangedForProperty(const QString &interface, const QString &property); |
1199 | + |
1200 | + struct PropertyInfo { |
1201 | + QVariant value{}; |
1202 | + QString signal{}; |
1203 | + QDBusInterface *proxyInterface{}; |
1204 | + QString proxyMethod{}; |
1205 | + ProxyConverter proxyConverter{}; |
1206 | + }; |
1207 | + typedef QHash< QString, QHash<QString, PropertyInfo> > PropertyHash; |
1208 | + PropertyHash m_properties; |
1209 | AccountsServiceDBusAdaptor *m_service; |
1210 | QDBusInterface *m_unityInput; |
1211 | QString m_user; |
1212 | - bool m_demoEdges; |
1213 | - bool m_enableLauncherWhileLocked; |
1214 | - bool m_enableIndicatorsWhileLocked; |
1215 | - QString m_backgroundFile; |
1216 | - bool m_statsWelcomeScreen; |
1217 | - PasswordDisplayHint m_passwordDisplayHint; |
1218 | - uint m_failedLogins; |
1219 | - bool m_hereEnabled; |
1220 | - QString m_hereLicensePath; |
1221 | }; |
1222 | |
1223 | #endif |
1224 | |
1225 | === modified file 'plugins/AccountsService/AccountsService.qmltypes' |
1226 | --- plugins/AccountsService/AccountsService.qmltypes 2015-02-13 09:01:16 +0000 |
1227 | +++ plugins/AccountsService/AccountsService.qmltypes 2016-03-11 18:12:46 +0000 |
1228 | @@ -23,6 +23,7 @@ |
1229 | } |
1230 | Property { name: "user"; type: "string" } |
1231 | Property { name: "demoEdges"; type: "bool" } |
1232 | + Property { name: "demoEdgesCompleted"; type: "QStringList"; isReadonly: true } |
1233 | Property { name: "enableLauncherWhileLocked"; type: "bool"; isReadonly: true } |
1234 | Property { name: "enableIndicatorsWhileLocked"; type: "bool"; isReadonly: true } |
1235 | Property { name: "backgroundFile"; type: "string"; isReadonly: true } |
1236 | @@ -32,5 +33,9 @@ |
1237 | Property { name: "hereEnabled"; type: "bool" } |
1238 | Property { name: "hereLicensePath"; type: "string"; isReadonly: true } |
1239 | Property { name: "hereLicensePathValid"; type: "bool"; isReadonly: true } |
1240 | + Method { |
1241 | + name: "markDemoEdgeCompleted" |
1242 | + Parameter { name: "edge"; type: "string" } |
1243 | + } |
1244 | } |
1245 | } |
1246 | |
1247 | === modified file 'plugins/AccountsService/AccountsServiceDBusAdaptor.cpp' |
1248 | --- plugins/AccountsService/AccountsServiceDBusAdaptor.cpp 2015-10-26 14:05:14 +0000 |
1249 | +++ plugins/AccountsService/AccountsServiceDBusAdaptor.cpp 2016-03-11 18:12:46 +0000 |
1250 | @@ -1,5 +1,5 @@ |
1251 | /* |
1252 | - * Copyright (C) 2013 Canonical, Ltd. |
1253 | + * Copyright (C) 2013-2016 Canonical, Ltd. |
1254 | * |
1255 | * This program is free software; you can redistribute it and/or modify |
1256 | * it under the terms of the GNU General Public License as published by |
1257 | @@ -12,8 +12,6 @@ |
1258 | * |
1259 | * You should have received a copy of the GNU General Public License |
1260 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1261 | - * |
1262 | - * Author: Michael Terry <michael.terry@canonical.com> |
1263 | */ |
1264 | |
1265 | #include "AccountsServiceDBusAdaptor.h" |
1266 | @@ -37,6 +35,15 @@ |
1267 | connection, this); |
1268 | } |
1269 | |
1270 | +QDBusPendingReply<QVariantMap> AccountsServiceDBusAdaptor::getAllPropertiesAsync(const QString &user, const QString &interface) |
1271 | +{ |
1272 | + QDBusInterface *iface = getUserInterface(user); |
1273 | + if (iface != nullptr && iface->isValid()) { |
1274 | + return iface->asyncCall(QStringLiteral("GetAll"), interface); |
1275 | + } |
1276 | + return QDBusPendingReply<QVariantMap>(QDBusMessage::createError(QDBusError::Other, QStringLiteral("Invalid Interface"))); |
1277 | +} |
1278 | + |
1279 | QDBusPendingReply<QVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property) |
1280 | { |
1281 | QDBusInterface *iface = getUserInterface(user); |
1282 | @@ -80,7 +87,7 @@ |
1283 | m_ignoreNextChanged = false; |
1284 | } |
1285 | |
1286 | -QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path) |
1287 | +QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path) const |
1288 | { |
1289 | QMap<QString, QDBusInterface *>::const_iterator i; |
1290 | for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) { |
1291 | |
1292 | === modified file 'plugins/AccountsService/AccountsServiceDBusAdaptor.h' |
1293 | --- plugins/AccountsService/AccountsServiceDBusAdaptor.h 2015-10-26 14:05:14 +0000 |
1294 | +++ plugins/AccountsService/AccountsServiceDBusAdaptor.h 2016-03-11 18:12:46 +0000 |
1295 | @@ -1,5 +1,5 @@ |
1296 | /* |
1297 | - * Copyright (C) 2013 Canonical, Ltd. |
1298 | + * Copyright (C) 2013-2016 Canonical, Ltd. |
1299 | * |
1300 | * This program is free software; you can redistribute it and/or modify |
1301 | * it under the terms of the GNU General Public License as published by |
1302 | @@ -12,8 +12,6 @@ |
1303 | * |
1304 | * You should have received a copy of the GNU General Public License |
1305 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1306 | - * |
1307 | - * Authors: Michael Terry <michael.terry@canonical.com> |
1308 | */ |
1309 | |
1310 | #ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H |
1311 | @@ -35,8 +33,9 @@ |
1312 | explicit AccountsServiceDBusAdaptor(QObject *parent = 0); |
1313 | ~AccountsServiceDBusAdaptor() = default; |
1314 | |
1315 | - Q_INVOKABLE QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property); |
1316 | - Q_INVOKABLE QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value); |
1317 | + QDBusPendingReply<QVariantMap> getAllPropertiesAsync(const QString &user, const QString &interface); |
1318 | + QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property); |
1319 | + QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value); |
1320 | |
1321 | Q_SIGNALS: |
1322 | void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed); |
1323 | @@ -48,7 +47,7 @@ |
1324 | |
1325 | private: |
1326 | QDBusInterface *getUserInterface(const QString &user); |
1327 | - QString getUserForPath(const QString &path); |
1328 | + QString getUserForPath(const QString &path) const; |
1329 | |
1330 | QDBusInterface *m_accountsManager; |
1331 | QMap<QString, QDBusInterface *> m_users; |
1332 | |
1333 | === modified file 'plugins/AccountsService/com.canonical.unity.AccountsService.xml' |
1334 | --- plugins/AccountsService/com.canonical.unity.AccountsService.xml 2015-02-04 15:12:36 +0000 |
1335 | +++ plugins/AccountsService/com.canonical.unity.AccountsService.xml 2016-03-11 18:12:46 +0000 |
1336 | @@ -14,6 +14,11 @@ |
1337 | <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/> |
1338 | </property> |
1339 | |
1340 | + <!-- List of tutorial pages that have been completed by the user --> |
1341 | + <property name="DemoEdgesCompleted" type="as" access="readwrite"> |
1342 | + <annotation name="org.freedesktop.Accounts.DefaultValue" value="[]"/> |
1343 | + </property> |
1344 | + |
1345 | <property name="LauncherItems" type="aa{sv}" access="readwrite"> |
1346 | <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/> |
1347 | </property> |
1348 | |
1349 | === modified file 'plugins/Dash/AudioProgressBar.qml' |
1350 | --- plugins/Dash/AudioProgressBar.qml 2015-12-03 14:44:08 +0000 |
1351 | +++ plugins/Dash/AudioProgressBar.qml 2016-03-11 18:12:46 +0000 |
1352 | @@ -31,6 +31,7 @@ |
1353 | anchors { left: parent.left; right: parent.right } |
1354 | height: units.dp(6) |
1355 | source: "graphics/music_progress_bg.png" |
1356 | + asynchronous: true |
1357 | sourceSize.width: width |
1358 | sourceSize.height: height |
1359 | } |
1360 | |
1361 | === modified file 'plugins/Dash/CardCreator.js' |
1362 | --- plugins/Dash/CardCreator.js 2016-02-12 00:11:52 +0000 |
1363 | +++ plugins/Dash/CardCreator.js 2016-03-11 18:12:46 +0000 |
1364 | @@ -18,12 +18,13 @@ |
1365 | |
1366 | // %1 is the template["card-background"]["elements"][0] |
1367 | // %2 is the template["card-background"]["elements"][1] |
1368 | -// %3 is the template["card-background"] string |
1369 | +// %3 is whether the loader should be asynchronous or not |
1370 | +// %4 is the template["card-background"] string |
1371 | var kBackgroundLoaderCode = 'Loader {\n\ |
1372 | id: backgroundLoader; \n\ |
1373 | objectName: "backgroundLoader"; \n\ |
1374 | anchors.fill: parent; \n\ |
1375 | - asynchronous: root.asynchronous; \n\ |
1376 | + asynchronous: %3; \n\ |
1377 | visible: status == Loader.Ready; \n\ |
1378 | sourceComponent: UbuntuShape { \n\ |
1379 | objectName: "background"; \n\ |
1380 | @@ -46,7 +47,7 @@ |
1381 | objectName: "backgroundImage"; \n\ |
1382 | source: { \n\ |
1383 | if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\ |
1384 | - else return %3; \n\ |
1385 | + else return %4; \n\ |
1386 | } \n\ |
1387 | } \n\ |
1388 | function getColor(index) { \n\ |
1389 | @@ -63,8 +64,9 @@ |
1390 | // %3 is used as image height |
1391 | // %4 is used for artShapeSource.hideSource and inner Loader visible |
1392 | // %5 is used as aspect ratio fallback |
1393 | -// %6 is injected as code to artImage |
1394 | -// %7 is used as image fallback |
1395 | +// %6 is whether the loader should be asynchronous or not |
1396 | +// %7 is injected as code to artImage |
1397 | +// %8 is used as image fallback |
1398 | var kArtShapeHolderCode = 'Item { \n\ |
1399 | id: artShapeHolder; \n\ |
1400 | height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\ |
1401 | @@ -73,9 +75,9 @@ |
1402 | Loader { \n\ |
1403 | id: artShapeLoader; \n\ |
1404 | objectName: "artShapeLoader"; \n\ |
1405 | - readonly property string cardArt: cardData && cardData["art"] || %7; \n\ |
1406 | + readonly property string cardArt: cardData && cardData["art"] || %8; \n\ |
1407 | active: cardArt != ""; \n\ |
1408 | - asynchronous: root.asynchronous; \n\ |
1409 | + asynchronous: %6; \n\ |
1410 | visible: status == Loader.Ready; \n\ |
1411 | sourceComponent: Item { \n\ |
1412 | id: artShape; \n\ |
1413 | @@ -132,10 +134,10 @@ |
1414 | id: artImage; \n\ |
1415 | objectName: "artImage"; \n\ |
1416 | source: artShapeLoader.cardArt; \n\ |
1417 | - asynchronous: root.asynchronous; \n\ |
1418 | + asynchronous: %6; \n\ |
1419 | width: %2; \n\ |
1420 | height: %3; \n\ |
1421 | - %6 \n\ |
1422 | + %7 \n\ |
1423 | } \n\ |
1424 | } \n\ |
1425 | } \n\ |
1426 | @@ -144,6 +146,7 @@ |
1427 | // %1 is anchors.fill |
1428 | // %2 is width |
1429 | // %3 is height |
1430 | +// %4 is whether the icon should be asynchronous or not |
1431 | var kAudioButtonCode = 'AbstractButton { \n\ |
1432 | id: audioButton; \n\ |
1433 | anchors.fill: %1; \n\ |
1434 | @@ -169,6 +172,7 @@ |
1435 | opacity: 0.9; \n\ |
1436 | name: DashAudioPlayer.playing && AudioUrlComparer.compare(parent.source, DashAudioPlayer.currentSource) ? "media-playback-pause" : "media-playback-start"; \n\ |
1437 | color: "white"; \n\ |
1438 | + asynchronous: %4; \n\ |
1439 | } \n\ |
1440 | onClicked: { \n\ |
1441 | if (AudioUrlComparer.compare(source, DashAudioPlayer.currentSource)) { \n\ |
1442 | @@ -187,12 +191,14 @@ |
1443 | } \n\ |
1444 | }'; |
1445 | |
1446 | +// %1 is whether the loader should be asynchronous or not |
1447 | +// %2 is the header height code |
1448 | var kOverlayLoaderCode = 'Loader { \n\ |
1449 | id: overlayLoader; \n\ |
1450 | - readonly property real overlayHeight: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\ |
1451 | + readonly property real overlayHeight: %2 + units.gu(2); \n\ |
1452 | anchors.fill: artShapeHolder; \n\ |
1453 | active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\ |
1454 | - asynchronous: root.asynchronous; \n\ |
1455 | + asynchronous: %1; \n\ |
1456 | visible: showHeader && status == Loader.Ready; \n\ |
1457 | sourceComponent: UbuntuShapeOverlay { \n\ |
1458 | id: overlay; \n\ |
1459 | @@ -211,17 +217,19 @@ |
1460 | objectName: "outerRow"; \n\ |
1461 | property real margins: units.gu(1); \n\ |
1462 | spacing: margins; \n\ |
1463 | - height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\ |
1464 | + %2\ |
1465 | anchors { %1 } \n\ |
1466 | anchors.right: parent.right; \n\ |
1467 | anchors.margins: margins; \n\ |
1468 | anchors.rightMargin: 0; \n\ |
1469 | data: [ \n\ |
1470 | - %2 \n\ |
1471 | + %3 \n\ |
1472 | ] \n\ |
1473 | }\n'; |
1474 | var args = Array.prototype.slice.call(arguments); |
1475 | - var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(args.join(',\n')); |
1476 | + var isCardTool = args.shift(); |
1477 | + var heightCode = isCardTool ? "" : "height: root.fixedHeaderHeight; \n"; |
1478 | + var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(heightCode).arg(args.join(',\n')); |
1479 | return code; |
1480 | } |
1481 | |
1482 | @@ -242,10 +250,11 @@ |
1483 | } |
1484 | |
1485 | // %1 is used as anchors of mascotShapeLoader |
1486 | +// %2 is whether the loader should be asynchronous or not |
1487 | var kMascotShapeLoaderCode = 'Loader { \n\ |
1488 | id: mascotShapeLoader; \n\ |
1489 | objectName: "mascotShapeLoader"; \n\ |
1490 | - asynchronous: root.asynchronous; \n\ |
1491 | + asynchronous: %2; \n\ |
1492 | active: mascotImage.status === Image.Ready; \n\ |
1493 | visible: showHeader && active && status == Loader.Ready; \n\ |
1494 | width: units.gu(6); \n\ |
1495 | @@ -275,6 +284,7 @@ |
1496 | // %2 is used as color of titleLabel |
1497 | // %3 is used as extra condition for visible of titleLabel |
1498 | // %4 is used as title width |
1499 | +// %5 is used as horizontal alignment |
1500 | var kTitleLabelCode = 'Label { \n\ |
1501 | id: titleLabel; \n\ |
1502 | objectName: "titleLabel"; \n\ |
1503 | @@ -289,7 +299,7 @@ |
1504 | width: %4; \n\ |
1505 | text: root.title; \n\ |
1506 | font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\ |
1507 | - horizontalAlignment: root.titleAlignment; \n\ |
1508 | + horizontalAlignment: %5; \n\ |
1509 | }\n'; |
1510 | |
1511 | // %1 is used as extra anchors of emblemIcon |
1512 | @@ -398,7 +408,7 @@ |
1513 | return colorString; |
1514 | } |
1515 | |
1516 | -function cardString(template, components) { |
1517 | +function cardString(template, components, isCardTool) { |
1518 | var code; |
1519 | |
1520 | var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false"; |
1521 | @@ -410,16 +420,16 @@ |
1522 | property string backgroundShapeStyle: "inset"; \n\ |
1523 | property real fontScale: 1.0; \n\ |
1524 | property var scopeStyle: null; \n\ |
1525 | - property int titleAlignment: Text.AlignLeft; \n\ |
1526 | - property int fixedHeaderHeight: -1; \n\ |
1527 | + %2\ |
1528 | property size fixedArtShapeSize: Qt.size(-1, -1); \n\ |
1529 | readonly property string title: cardData && cardData["title"] || ""; \n\ |
1530 | - property bool asynchronous: true; \n\ |
1531 | property bool showHeader: true; \n\ |
1532 | implicitWidth: childrenRect.width; \n\ |
1533 | enabled: %1; \n\ |
1534 | \n'.arg(templateInteractive); |
1535 | |
1536 | + code = code.arg(isCardTool ? "" : "property int fixedHeaderHeight: -1; \n"); |
1537 | + |
1538 | var hasArt = components["art"] && components["art"]["field"] || false; |
1539 | var hasSummary = components["summary"] || false; |
1540 | var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false; |
1541 | @@ -435,6 +445,7 @@ |
1542 | var hasHeaderRow = hasMascot && hasTitle; |
1543 | var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false; |
1544 | var isAudio = template["quick-preview-type"] === "audio"; |
1545 | + var asynchronous = isCardTool ? "false" : "true"; |
1546 | |
1547 | if (isAudio) { |
1548 | // For now we only support audio cards with [optional] art, title, subtitle |
1549 | @@ -468,7 +479,7 @@ |
1550 | backgroundElements1 = '"%1"'.arg(element1); |
1551 | } |
1552 | } |
1553 | - code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(templateCardBackground); |
1554 | + code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(asynchronous).arg(templateCardBackground); |
1555 | } |
1556 | |
1557 | if (hasArt) { |
1558 | @@ -497,23 +508,31 @@ |
1559 | if (isNaN(aspectRatio)) { |
1560 | aspectRatio = 1; |
1561 | } |
1562 | - var fallback = components["art"] && components["art"]["fallback"] || ""; |
1563 | + var fallback = !isCardTool && components["art"] && components["art"]["fallback"] || ""; |
1564 | fallback = encodeURI(fallback); |
1565 | var fallbackStatusCode = ""; |
1566 | var fallbackURICode = '""'; |
1567 | if (fallback !== "") { |
1568 | // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode |
1569 | - // which in kArtShapeHolderCode is %7 |
1570 | - fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %7;'; |
1571 | + // which in kArtShapeHolderCode is %8 |
1572 | + fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;'; |
1573 | fallbackURICode = 'decodeURI("%1")'.arg(fallback); |
1574 | } |
1575 | - code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode).arg(isConciergeMode ? "false" : "true").arg(aspectRatio).arg(fallbackStatusCode).arg(fallbackURICode); |
1576 | + code += kArtShapeHolderCode.arg(artAnchors) |
1577 | + .arg(widthCode) |
1578 | + .arg(heightCode) |
1579 | + .arg(isConciergeMode ? "false" : "true") |
1580 | + .arg(aspectRatio) |
1581 | + .arg(asynchronous) |
1582 | + .arg(fallbackStatusCode) |
1583 | + .arg(fallbackURICode); |
1584 | } else { |
1585 | code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n' |
1586 | } |
1587 | |
1588 | if (headerAsOverlay) { |
1589 | - code += kOverlayLoaderCode; |
1590 | + var headerHeightCode = isCardTool ? "headerHeight" : "root.fixedHeaderHeight"; |
1591 | + code += kOverlayLoaderCode.arg(asynchronous).arg(headerHeightCode); |
1592 | } |
1593 | |
1594 | var headerVerticalAnchors; |
1595 | @@ -595,11 +614,11 @@ |
1596 | } |
1597 | |
1598 | if (useMascotShape) { |
1599 | - mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors); |
1600 | + mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors).arg(asynchronous); |
1601 | } |
1602 | |
1603 | var mascotImageVisible = useMascotShape ? 'false' : 'showHeader'; |
1604 | - var fallback = components["mascot"] && components["mascot"]["fallback"] || ""; |
1605 | + var fallback = !isCardTool && components["mascot"] && components["mascot"]["fallback"] || ""; |
1606 | fallback = encodeURI(fallback); |
1607 | var fallbackStatusCode = ""; |
1608 | var fallbackURICode = '""'; |
1609 | @@ -715,9 +734,24 @@ |
1610 | } |
1611 | } |
1612 | |
1613 | + var titleAlignment = "Text.AlignHCenter"; |
1614 | + if (template["card-layout"] === "horizontal" |
1615 | + || typeof components["title"] !== "object" |
1616 | + || components["title"]["align"] === "left") titleAlignment = "Text.AlignLeft"; |
1617 | + var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"]; |
1618 | + for (var key in keys) { |
1619 | + key = keys[key]; |
1620 | + try { |
1621 | + if (typeof components[key] === "string" |
1622 | + || typeof components[key]["field"] === "string") titleAlignment = "Text.AlignLeft"; |
1623 | + } catch (e) { |
1624 | + continue; |
1625 | + } |
1626 | + } |
1627 | + |
1628 | // code for different elements |
1629 | var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': ''); |
1630 | - var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth); |
1631 | + var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth).arg(titleAlignment); |
1632 | var subtitleCode; |
1633 | var attributesCode; |
1634 | |
1635 | @@ -759,7 +793,7 @@ |
1636 | if (mascotShapeCode != '') { |
1637 | rowCode.unshift(mascotShapeCode); |
1638 | } |
1639 | - code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode) |
1640 | + code += kHeaderRowCodeGenerator(isCardTool, headerVerticalAnchors + headerLeftAnchor, rowCode) |
1641 | } else { |
1642 | code += mascotShapeCode + mascotCode + titleSubtitleCode; |
1643 | } |
1644 | @@ -783,9 +817,10 @@ |
1645 | } else { |
1646 | audioButtonAnchorsFill = 'undefined'; |
1647 | audioButtonWidth = 'height'; |
1648 | - audioButtonHeight = '(root.fixedHeaderHeight > 0 ? root.fixedHeaderHeight : headerHeight) + 2 * units.gu(1)'; |
1649 | + audioButtonHeight = isCardTool ? 'headerHeight + 2 * units.gu(1)' |
1650 | + : 'root.fixedHeaderHeight + 2 * units.gu(1)'; |
1651 | } |
1652 | - code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight); |
1653 | + code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight).arg(asynchronous); |
1654 | } |
1655 | |
1656 | if (hasSummary) { |
1657 | @@ -854,13 +889,13 @@ |
1658 | return code; |
1659 | } |
1660 | |
1661 | -function createCardComponent(parent, template, components, identifier) { |
1662 | +function createCardComponent(parent, template, components, isCardTool, identifier) { |
1663 | var imports = 'import QtQuick 2.4; \n\ |
1664 | import Ubuntu.Components 1.3; \n\ |
1665 | import Ubuntu.Settings.Components 0.1; \n\ |
1666 | import Dash 0.1;\n\ |
1667 | import Utils 0.1;\n'; |
1668 | - var card = cardString(template, components); |
1669 | + var card = cardString(template, components, isCardTool); |
1670 | var code = imports + 'Component {\n' + card + '}\n'; |
1671 | |
1672 | try { |
1673 | |
1674 | === modified file 'plugins/Dash/CardCreatorCache.qml' |
1675 | --- plugins/Dash/CardCreatorCache.qml 2016-01-21 17:56:08 +0000 |
1676 | +++ plugins/Dash/CardCreatorCache.qml 2016-03-11 18:12:46 +0000 |
1677 | @@ -23,16 +23,16 @@ |
1678 | |
1679 | property var cache: new Object(); |
1680 | |
1681 | - function getCardComponent(template, components) { |
1682 | + function getCardComponent(template, components, isCardTool) { |
1683 | if (template === undefined || components === undefined) |
1684 | return undefined; |
1685 | |
1686 | var tString = JSON.stringify(template); |
1687 | var cString = JSON.stringify(components); |
1688 | - var allString = tString + cString; |
1689 | + var allString = tString + cString + isCardTool; |
1690 | var component = cache[allString]; |
1691 | if (component === undefined) { |
1692 | - component = CardCreator.createCardComponent(root, template, components, allString); |
1693 | + component = CardCreator.createCardComponent(root, template, components, isCardTool, allString); |
1694 | cache[allString] = component; |
1695 | } |
1696 | return component; |
1697 | |
1698 | === modified file 'plugins/Dash/plugin.cpp' |
1699 | --- plugins/Dash/plugin.cpp 2015-09-18 07:44:50 +0000 |
1700 | +++ plugins/Dash/plugin.cpp 2016-03-11 18:12:46 +0000 |
1701 | @@ -28,12 +28,12 @@ |
1702 | static QUrl oauthCleanedUrl(QUrl u) |
1703 | { |
1704 | QUrlQuery q(u); |
1705 | - q.removeQueryItem("oauth_nonce"); |
1706 | - q.removeQueryItem("oauth_timestamp"); |
1707 | - q.removeQueryItem("oauth_consumer_key"); |
1708 | - q.removeQueryItem("oauth_signature_method"); |
1709 | - q.removeQueryItem("oauth_version"); |
1710 | - q.removeQueryItem("oauth_signature"); |
1711 | + q.removeQueryItem(QStringLiteral("oauth_nonce")); |
1712 | + q.removeQueryItem(QStringLiteral("oauth_timestamp")); |
1713 | + q.removeQueryItem(QStringLiteral("oauth_consumer_key")); |
1714 | + q.removeQueryItem(QStringLiteral("oauth_signature_method")); |
1715 | + q.removeQueryItem(QStringLiteral("oauth_version")); |
1716 | + q.removeQueryItem(QStringLiteral("oauth_signature")); |
1717 | u.setQuery(q); |
1718 | return u; |
1719 | } |
1720 | |
1721 | === modified file 'plugins/GlobalShortcut/globalshortcutregistry.cpp' |
1722 | --- plugins/GlobalShortcut/globalshortcutregistry.cpp 2015-11-20 15:01:39 +0000 |
1723 | +++ plugins/GlobalShortcut/globalshortcutregistry.cpp 2016-03-11 18:12:46 +0000 |
1724 | @@ -35,13 +35,13 @@ |
1725 | |
1726 | bool GlobalShortcutRegistry::hasShortcut(const QVariant &seq) const |
1727 | { |
1728 | - return m_shortcuts.keys().contains(seq); |
1729 | + return m_shortcuts.contains(seq); |
1730 | } |
1731 | |
1732 | void GlobalShortcutRegistry::addShortcut(const QVariant &seq, GlobalShortcut *sc) |
1733 | { |
1734 | if (sc) { |
1735 | - if (!m_shortcuts.keys().contains(seq)) { // create a new entry |
1736 | + if (!m_shortcuts.contains(seq)) { // create a new entry |
1737 | m_shortcuts.insert(seq, {sc}); |
1738 | } else { // append to an existing one |
1739 | auto shortcuts = m_shortcuts[seq]; |
1740 | @@ -75,8 +75,8 @@ |
1741 | |
1742 | if (event->type() == QEvent::KeyPress) { |
1743 | QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); |
1744 | - QKeySequence seq = QKeySequence(keyEvent->key() + keyEvent->modifiers()); |
1745 | - if (m_shortcuts.keys().contains(seq)) { |
1746 | + int seq = keyEvent->key() + keyEvent->modifiers(); |
1747 | + if (m_shortcuts.contains(seq)) { |
1748 | const auto shortcuts = m_shortcuts.value(seq); |
1749 | Q_FOREACH(const auto &shortcut, shortcuts) { |
1750 | if (shortcut) { |
1751 | |
1752 | === modified file 'plugins/IntegratedLightDM/liblightdm/CMakeLists.txt' |
1753 | --- plugins/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-02-01 15:15:09 +0000 |
1754 | +++ plugins/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-03-11 18:12:46 +0000 |
1755 | @@ -5,13 +5,16 @@ |
1756 | UsersModel.cpp |
1757 | GreeterPrivate.cpp |
1758 | UsersModelPrivate.cpp |
1759 | + ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp |
1760 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp |
1761 | ) |
1762 | |
1763 | add_library(integratedLightDM STATIC ${LibLightDM_SOURCES}) |
1764 | +add_library(integratedLightDMSession STATIC ${LibLightDM_SOURCES}) |
1765 | add_library(MockLightDM-demo-shared SHARED ${LibLightDM_SOURCES}) |
1766 | |
1767 | include_directories( |
1768 | + ${CMAKE_SOURCE_DIR}/plugins/AccountsService |
1769 | ${CMAKE_CURRENT_BINARY_DIR} |
1770 | ${GLIB_INCLUDE_DIRS} |
1771 | ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS} |
1772 | @@ -22,17 +25,27 @@ |
1773 | ${LIBUSERMETRICSOUTPUT_LDFLAGS} |
1774 | -lpam |
1775 | ) |
1776 | +target_link_libraries(integratedLightDMSession |
1777 | + ${GLIB_LIBRARIES} |
1778 | + ${LIBUSERMETRICSOUTPUT_LDFLAGS} |
1779 | + -lpam |
1780 | +) |
1781 | target_link_libraries(MockLightDM-demo-shared |
1782 | ${GLIB_LIBRARIES} |
1783 | ${LIBUSERMETRICSOUTPUT_LDFLAGS} |
1784 | -lpam |
1785 | ) |
1786 | |
1787 | -qt5_use_modules(integratedLightDM Concurrent Gui) |
1788 | -qt5_use_modules(MockLightDM-demo-shared Concurrent Gui) |
1789 | +qt5_use_modules(integratedLightDM Concurrent DBus Gui) |
1790 | +qt5_use_modules(integratedLightDMSession Concurrent DBus Gui) |
1791 | +qt5_use_modules(MockLightDM-demo-shared Concurrent DBus Gui) |
1792 | |
1793 | -set_target_properties(integratedLightDM PROPERTIES COMPILE_FLAGS -fPIC) |
1794 | +set_target_properties(integratedLightDM PROPERTIES |
1795 | + COMPILE_FLAGS "-DSM_BUSNAME=systemBus -fPIC") |
1796 | +set_target_properties(integratedLightDMSession PROPERTIES |
1797 | + COMPILE_FLAGS "-DSM_BUSNAME=sessionBus -fPIC") |
1798 | set_target_properties(MockLightDM-demo-shared PROPERTIES |
1799 | + COMPILE_FLAGS "-DSM_BUSNAME=systemBus" |
1800 | OUTPUT_NAME lightdm-qt5-2) |
1801 | |
1802 | install(TARGETS MockLightDM-demo-shared |
1803 | |
1804 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModel.cpp' |
1805 | --- plugins/IntegratedLightDM/liblightdm/UsersModel.cpp 2015-09-14 09:11:08 +0000 |
1806 | +++ plugins/IntegratedLightDM/liblightdm/UsersModel.cpp 2016-03-11 18:12:46 +0000 |
1807 | @@ -54,24 +54,10 @@ |
1808 | roles[ImagePathRole] = "imagePath"; |
1809 | setRoleNames(roles); |
1810 | |
1811 | - // Now modify our mock user backgrounds |
1812 | - QDir bgdir = QDir(QStringLiteral("/usr/share/demo-assets/shell/backgrounds/")); |
1813 | - QStringList backgrounds = bgdir.entryList(QDir::Files | QDir::NoDotAndDotDot); |
1814 | - |
1815 | - for (int i = 0, j = 0; i < d->entries.size(); i++) { |
1816 | - Entry &entry = d->entries[i]; |
1817 | - if (entry.background.isNull() && !backgrounds.isEmpty()) { |
1818 | - entry.background = bgdir.filePath(backgrounds[j++]); |
1819 | - if (j >= backgrounds.length()) { |
1820 | - j = 0; |
1821 | - } |
1822 | - } |
1823 | - } |
1824 | -} |
1825 | - |
1826 | -UsersModel::~UsersModel() |
1827 | -{ |
1828 | - delete d_ptr; |
1829 | + connect(d_ptr, &UsersModelPrivate::dataChanged, this, [this](int i) { |
1830 | + QModelIndex index = createIndex(i, 0); |
1831 | + Q_EMIT dataChanged(index, index); |
1832 | + }); |
1833 | } |
1834 | |
1835 | int UsersModel::rowCount(const QModelIndex &parent) const |
1836 | |
1837 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModel.h' |
1838 | --- plugins/IntegratedLightDM/liblightdm/UsersModel.h 2015-04-30 09:31:51 +0000 |
1839 | +++ plugins/IntegratedLightDM/liblightdm/UsersModel.h 2016-03-11 18:12:46 +0000 |
1840 | @@ -41,7 +41,7 @@ |
1841 | |
1842 | public: |
1843 | explicit UsersModel(QObject *parent = 0); |
1844 | - virtual ~UsersModel(); |
1845 | + virtual ~UsersModel() = default; |
1846 | |
1847 | enum UserModelRoles {NameRole = Qt::UserRole, |
1848 | RealNameRole, |
1849 | |
1850 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp' |
1851 | --- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-02-04 14:10:42 +0000 |
1852 | +++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-03-11 18:12:46 +0000 |
1853 | @@ -18,7 +18,11 @@ |
1854 | |
1855 | #include "UsersModelPrivate.h" |
1856 | |
1857 | +#include "AccountsServiceDBusAdaptor.h" |
1858 | +#include "UsersModel.h" |
1859 | + |
1860 | #include <glib.h> |
1861 | +#include <QDebug> |
1862 | #include <QDir> |
1863 | #include <QSettings> |
1864 | #include <QStringList> |
1865 | @@ -27,7 +31,9 @@ |
1866 | { |
1867 | |
1868 | UsersModelPrivate::UsersModelPrivate(UsersModel* parent) |
1869 | - : q_ptr(parent) |
1870 | + : QObject(parent), |
1871 | + q_ptr(parent), |
1872 | + m_service(new AccountsServiceDBusAdaptor(this)) |
1873 | { |
1874 | QFileInfo demoFile(QDir::homePath() + "/.unity8-greeter-demo"); |
1875 | QString currentUser = g_get_user_name(); |
1876 | @@ -43,15 +49,43 @@ |
1877 | entries.append({user, name, 0, 0, false, false, 0, 0}); |
1878 | } |
1879 | } else { |
1880 | - // If we were using the actual liblightdm, we could just ask it |
1881 | - // for the user's real name. But we aren't. We *should* ask |
1882 | - // AccountsService for the real name, like liblightdm does internally, |
1883 | - // but this is close enough since AS and passwd are always in sync. |
1884 | - QString realName = QString::fromUtf8(g_get_real_name()); // gets name from passwd entry |
1885 | - if (realName == QStringLiteral("Unknown")) { // glib doesn't translate this string |
1886 | - realName.clear(); |
1887 | - } |
1888 | - entries.append({currentUser, realName, 0, 0, false, false, 0, 0}); |
1889 | + entries.append({currentUser, 0, 0, 0, false, false, 0, 0}); |
1890 | + |
1891 | + connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, |
1892 | + this, [this](const QString &user) { |
1893 | + if (user == entries[0].username) { |
1894 | + updateName(true); |
1895 | + } |
1896 | + }); |
1897 | + updateName(false); |
1898 | + } |
1899 | +} |
1900 | + |
1901 | +void UsersModelPrivate::updateName(bool async) |
1902 | +{ |
1903 | + auto pendingReply = m_service->getUserPropertyAsync(entries[0].username, |
1904 | + QStringLiteral("org.freedesktop.Accounts.User"), |
1905 | + QStringLiteral("RealName")); |
1906 | + auto *watcher = new QDBusPendingCallWatcher(pendingReply, this); |
1907 | + |
1908 | + connect(watcher, &QDBusPendingCallWatcher::finished, |
1909 | + this, [this](QDBusPendingCallWatcher* watcher) { |
1910 | + |
1911 | + QDBusPendingReply<QVariant> reply = *watcher; |
1912 | + watcher->deleteLater(); |
1913 | + if (reply.isError()) { |
1914 | + qWarning() << "Failed to get 'RealName' property - " << reply.error().message(); |
1915 | + return; |
1916 | + } |
1917 | + |
1918 | + const QString realName = reply.value().toString(); |
1919 | + if (entries[0].real_name != realName) { |
1920 | + entries[0].real_name = realName; |
1921 | + Q_EMIT dataChanged(0); |
1922 | + } |
1923 | + }); |
1924 | + if (!async) { |
1925 | + watcher->waitForFinished(); |
1926 | } |
1927 | } |
1928 | |
1929 | |
1930 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h' |
1931 | --- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h 2015-01-20 11:50:19 +0000 |
1932 | +++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h 2016-03-11 18:12:46 +0000 |
1933 | @@ -19,8 +19,11 @@ |
1934 | #ifndef UNITY_MOCK_USERSMODEL_PRIVATE_H |
1935 | #define UNITY_MOCK_USERSMODEL_PRIVATE_H |
1936 | |
1937 | -#include <QtCore/QList> |
1938 | -#include <QtCore/QString> |
1939 | +#include <QList> |
1940 | +#include <QObject> |
1941 | +#include <QString> |
1942 | + |
1943 | +class AccountsServiceDBusAdaptor; |
1944 | |
1945 | namespace QLightDM |
1946 | { |
1947 | @@ -39,19 +42,28 @@ |
1948 | QString infographic; |
1949 | }; |
1950 | |
1951 | -class UsersModelPrivate |
1952 | +class UsersModelPrivate : public QObject |
1953 | { |
1954 | + Q_OBJECT |
1955 | + |
1956 | public: |
1957 | explicit UsersModelPrivate(UsersModel *parent = 0); |
1958 | virtual ~UsersModelPrivate() = default; |
1959 | |
1960 | QList<Entry> entries; |
1961 | |
1962 | +Q_SIGNALS: |
1963 | + void dataChanged(int); |
1964 | + |
1965 | protected: |
1966 | UsersModel * const q_ptr; |
1967 | |
1968 | private: |
1969 | Q_DECLARE_PUBLIC(UsersModel) |
1970 | + |
1971 | + void updateName(bool async); |
1972 | + |
1973 | + AccountsServiceDBusAdaptor *m_service; |
1974 | }; |
1975 | |
1976 | } |
1977 | |
1978 | === modified file 'plugins/ScreenGrabber/screengrabber.cpp' |
1979 | --- plugins/ScreenGrabber/screengrabber.cpp 2015-11-18 18:38:36 +0000 |
1980 | +++ plugins/ScreenGrabber/screengrabber.cpp 2016-03-11 18:12:46 +0000 |
1981 | @@ -46,12 +46,10 @@ |
1982 | |
1983 | QDir screenshotsDir; |
1984 | if (qEnvironmentVariableIsSet("UNITY_TESTING")) { |
1985 | - qDebug() << "Using test environment"; |
1986 | QTemporaryDir tDir; |
1987 | tDir.setAutoRemove(false); |
1988 | screenshotsDir = tDir.path(); |
1989 | } else { |
1990 | - qDebug() << "Using real environment"; |
1991 | screenshotsDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); |
1992 | } |
1993 | screenshotsDir.mkpath(QStringLiteral("Screenshots")); |
1994 | |
1995 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' |
1996 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2015-12-16 18:28:21 +0000 |
1997 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2016-03-11 18:12:46 +0000 |
1998 | @@ -194,6 +194,26 @@ |
1999 | } |
2000 | } |
2001 | |
2002 | +bool DirectionalDragArea::monitorOnly() const |
2003 | +{ |
2004 | + return d->monitorOnly; |
2005 | +} |
2006 | + |
2007 | +void DirectionalDragArea::setMonitorOnly(bool monitorOnly) |
2008 | +{ |
2009 | + if (d->monitorOnly != monitorOnly) { |
2010 | + d->monitorOnly = monitorOnly; |
2011 | + |
2012 | + if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) { |
2013 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this); |
2014 | + // We still wanna know when it ends for keeping the composition time window up-to-date |
2015 | + TouchRegistry::instance()->addTouchWatcher(d->touchId, this); |
2016 | + } |
2017 | + |
2018 | + Q_EMIT monitorOnlyChanged(monitorOnly); |
2019 | + } |
2020 | +} |
2021 | + |
2022 | void DirectionalDragArea::removeTimeConstraints() |
2023 | { |
2024 | d->setMaxTime(60 * 60 * 1000); |
2025 | @@ -260,7 +280,10 @@ |
2026 | unownedTouchEvent_undecided(unownedTouchEvent); |
2027 | break; |
2028 | default: // Recognized: |
2029 | - // do nothing |
2030 | + if (monitorOnly) { |
2031 | + // Treat unowned event as if we owned it, but we are really just watching it |
2032 | + touchEvent_recognized(event); |
2033 | + } |
2034 | break; |
2035 | } |
2036 | |
2037 | @@ -311,7 +334,9 @@ |
2038 | } |
2039 | |
2040 | if (movedFarEnoughAlongGestureAxis()) { |
2041 | - TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
2042 | + if (!monitorOnly) { |
2043 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
2044 | + } |
2045 | setStatus(Recognized); |
2046 | setPublicPos(touchPoint->pos()); |
2047 | setPublicScenePos(touchScenePos); |
2048 | @@ -411,12 +436,21 @@ |
2049 | if (recognitionIsDisabled()) { |
2050 | // Behave like a dumb TouchArea |
2051 | ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately."); |
2052 | - TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
2053 | setStatus(Recognized); |
2054 | - event->accept(); |
2055 | + if (monitorOnly) { |
2056 | + watchPressedTouchPoints(touchPoints); |
2057 | + event->ignore(); |
2058 | + } else { |
2059 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
2060 | + event->accept(); |
2061 | + } |
2062 | } else { |
2063 | // just monitor the touch points for now. |
2064 | - TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); |
2065 | + if (monitorOnly) { |
2066 | + watchPressedTouchPoints(touchPoints); |
2067 | + } else { |
2068 | + TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); |
2069 | + } |
2070 | |
2071 | setStatus(Undecided); |
2072 | // Let the item below have it. We will monitor it and grab it later if a gesture |
2073 | @@ -890,5 +924,6 @@ |
2074 | , recognitionTimer(nullptr) |
2075 | , timeSource(new RealTimeSource) |
2076 | , activeTouches(timeSource) |
2077 | + , monitorOnly(false) |
2078 | { |
2079 | } |
2080 | |
2081 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' |
2082 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2015-05-11 07:49:36 +0000 |
2083 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2016-03-11 18:12:46 +0000 |
2084 | @@ -77,6 +77,10 @@ |
2085 | WRITE setImmediateRecognition |
2086 | NOTIFY immediateRecognitionChanged) |
2087 | |
2088 | + // Whether we are merely monitoring touch events (in which case, we don't |
2089 | + // claim ownership of the touch). |
2090 | + Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged) |
2091 | + |
2092 | Q_ENUMS(Direction) |
2093 | public: |
2094 | DirectionalDragArea(QQuickItem *parent = 0); |
2095 | @@ -100,6 +104,9 @@ |
2096 | bool immediateRecognition() const; |
2097 | void setImmediateRecognition(bool enabled); |
2098 | |
2099 | + bool monitorOnly() const; |
2100 | + void setMonitorOnly(bool monitorOnly); |
2101 | + |
2102 | bool event(QEvent *e) override; |
2103 | |
2104 | /* |
2105 | @@ -123,6 +130,7 @@ |
2106 | void touchSceneXChanged(qreal value); |
2107 | void touchSceneYChanged(qreal value); |
2108 | void immediateRecognitionChanged(bool value); |
2109 | + void monitorOnlyChanged(bool value); |
2110 | |
2111 | protected: |
2112 | void touchEvent(QTouchEvent *event) override; |
2113 | |
2114 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea_p.h' |
2115 | --- plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2015-11-20 15:01:39 +0000 |
2116 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2016-03-11 18:12:46 +0000 |
2117 | @@ -160,6 +160,8 @@ |
2118 | |
2119 | ActiveTouchesInfo activeTouches; |
2120 | |
2121 | + bool monitorOnly; |
2122 | + |
2123 | Q_SIGNALS: |
2124 | void statusChanged(Status value); |
2125 | }; |
2126 | |
2127 | === modified file 'plugins/Unity/Indicators/indicatorsmanager.cpp' |
2128 | --- plugins/Unity/Indicators/indicatorsmanager.cpp 2015-12-02 12:02:50 +0000 |
2129 | +++ plugins/Unity/Indicators/indicatorsmanager.cpp 2016-03-11 18:12:46 +0000 |
2130 | @@ -116,7 +116,7 @@ |
2131 | QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this); |
2132 | const QString name = indicator_settings.value(QStringLiteral("Indicator Service/Name")).toString(); |
2133 | |
2134 | - if (m_platform.isPC() && name == "indicator-keyboard") { |
2135 | + if (m_platform.isPC() && name == QLatin1String("indicator-keyboard")) { |
2136 | return; // convergence: skip this indicator until it works in Mir |
2137 | } |
2138 | |
2139 | @@ -293,7 +293,7 @@ |
2140 | // The rest of the indicators respect their default profile (which is "phone", even on desktop PCs) |
2141 | if ((new_indicator->identifier() == QStringLiteral("indicator-session") && m_platform.isMultiSession()) |
2142 | || (new_indicator->identifier() == QStringLiteral("indicator-power") && m_platform.isPC())) { |
2143 | - new_indicator->setProfile("desktop"); |
2144 | + new_indicator->setProfile(QStringLiteral("desktop")); |
2145 | } else { |
2146 | new_indicator->setProfile(m_profile); |
2147 | } |
2148 | |
2149 | === modified file 'plugins/Unity/Indicators/rootstateparser.h' |
2150 | --- plugins/Unity/Indicators/rootstateparser.h 2014-11-11 15:28:13 +0000 |
2151 | +++ plugins/Unity/Indicators/rootstateparser.h 2016-03-11 18:12:46 +0000 |
2152 | @@ -23,6 +23,7 @@ |
2153 | |
2154 | class UNITYINDICATORS_EXPORT RootStateParser : public ActionStateParser |
2155 | { |
2156 | +Q_OBJECT |
2157 | public: |
2158 | RootStateParser(QObject* parent = nullptr); |
2159 | virtual QVariant toQVariant(GVariant* state) const override; |
2160 | |
2161 | === modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp' |
2162 | --- plugins/Unity/Launcher/desktopfilehandler.cpp 2015-09-30 12:43:53 +0000 |
2163 | +++ plugins/Unity/Launcher/desktopfilehandler.cpp 2016-03-11 18:12:46 +0000 |
2164 | @@ -146,9 +146,9 @@ |
2165 | QString iconString = settings.value(QStringLiteral("Icon")).toString(); |
2166 | QString pathString = settings.value(QStringLiteral("Path")).toString(); |
2167 | |
2168 | - if (QFileInfo(iconString).exists()) { |
2169 | + if (QFileInfo::exists(iconString)) { |
2170 | return QFileInfo(iconString).absoluteFilePath(); |
2171 | - } else if (QFileInfo(pathString + '/' + iconString).exists()) { |
2172 | + } else if (QFileInfo::exists(pathString + '/' + iconString)) { |
2173 | return pathString + '/' + iconString; |
2174 | } |
2175 | return "image://theme/" + iconString; |
2176 | |
2177 | === modified file 'plugins/Unity/Launcher/launcheritem.cpp' |
2178 | --- plugins/Unity/Launcher/launcheritem.cpp 2015-09-14 09:11:08 +0000 |
2179 | +++ plugins/Unity/Launcher/launcheritem.cpp 2016-03-11 18:12:46 +0000 |
2180 | @@ -37,6 +37,7 @@ |
2181 | m_alerting(false), |
2182 | m_quickList(new QuickListModel(this)) |
2183 | { |
2184 | + Q_ASSERT(parent != nullptr); |
2185 | QuickListEntry nameAction; |
2186 | nameAction.setActionId(QStringLiteral("launch_item")); |
2187 | nameAction.setText(m_name); |
2188 | |
2189 | === modified file 'plugins/Unity/Launcher/launcheritem.h' |
2190 | --- plugins/Unity/Launcher/launcheritem.h 2015-07-23 14:13:57 +0000 |
2191 | +++ plugins/Unity/Launcher/launcheritem.h 2016-03-11 18:12:46 +0000 |
2192 | @@ -32,7 +32,7 @@ |
2193 | { |
2194 | Q_OBJECT |
2195 | public: |
2196 | - LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0); |
2197 | + LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent); |
2198 | |
2199 | QString appId() const override; |
2200 | QString name() const override; |
2201 | |
2202 | === modified file 'plugins/Unity/Launcher/launchermodel.cpp' |
2203 | --- plugins/Unity/Launcher/launchermodel.cpp 2015-09-14 09:11:08 +0000 |
2204 | +++ plugins/Unity/Launcher/launchermodel.cpp 2016-03-11 18:12:46 +0000 |
2205 | @@ -103,7 +103,7 @@ |
2206 | LauncherItem *item = m_list.at(index); |
2207 | if (!item->focused()) { |
2208 | item->setAlerting(alerting); |
2209 | - Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting); |
2210 | + Q_EMIT dataChanged(modelIndex, modelIndex, {RoleAlerting}); |
2211 | } |
2212 | } |
2213 | } |
2214 | @@ -389,7 +389,8 @@ |
2215 | if (countVisible && desktopFile.isValid()) { |
2216 | LauncherItem *item = new LauncherItem(appId, |
2217 | desktopFile.displayName(), |
2218 | - desktopFile.icon()); |
2219 | + desktopFile.icon(), |
2220 | + this); |
2221 | item->setCountVisible(true); |
2222 | beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); |
2223 | m_list.append(item); |
2224 | @@ -414,10 +415,19 @@ |
2225 | } else { |
2226 | int idx = m_list.indexOf(item); |
2227 | item->setName(desktopFile.displayName()); |
2228 | - item->setIcon(desktopFile.icon()); |
2229 | item->setPinned(item->pinned()); // update pinned text if needed |
2230 | item->setRunning(item->running()); |
2231 | - Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleRunning}); |
2232 | + Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleRunning}); |
2233 | + |
2234 | + const QString oldIcon = item->icon(); |
2235 | + if (oldIcon == desktopFile.icon()) { // same icon file, perhaps different contents, simulate changing the icon name to force reload |
2236 | + item->setIcon(QString()); |
2237 | + Q_EMIT dataChanged(index(idx), index(idx), {RoleIcon}); |
2238 | + } |
2239 | + |
2240 | + // now set the icon for real |
2241 | + item->setIcon(desktopFile.icon()); |
2242 | + Q_EMIT dataChanged(index(idx), index(idx), {RoleIcon}); |
2243 | } |
2244 | } |
2245 | |
2246 | @@ -489,7 +499,7 @@ |
2247 | if (idx >= 0) { |
2248 | LauncherItem *item = m_list.at(idx); |
2249 | setAlerting(item->appId(), true); |
2250 | - Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleAlerting); |
2251 | + Q_EMIT dataChanged(index(idx), index(idx), {RoleAlerting}); |
2252 | } |
2253 | } |
2254 | |
2255 | |
2256 | === modified file 'plugins/Unity/Launcher/launchermodel.h' |
2257 | --- plugins/Unity/Launcher/launchermodel.h 2015-07-29 12:32:57 +0000 |
2258 | +++ plugins/Unity/Launcher/launchermodel.h 2016-03-11 18:12:46 +0000 |
2259 | @@ -38,7 +38,7 @@ |
2260 | Q_OBJECT |
2261 | |
2262 | public: |
2263 | - LauncherModel(QObject *parent = 0); |
2264 | + LauncherModel(QObject *parent = nullptr); |
2265 | ~LauncherModel(); |
2266 | |
2267 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
2268 | |
2269 | === modified file 'plugins/Utils/CMakeLists.txt' |
2270 | --- plugins/Utils/CMakeLists.txt 2016-02-08 09:37:48 +0000 |
2271 | +++ plugins/Utils/CMakeLists.txt 2016-03-11 18:12:46 +0000 |
2272 | @@ -17,12 +17,13 @@ |
2273 | unitysortfilterproxymodelqml.cpp |
2274 | Timer.cpp |
2275 | unitymenumodelpaths.cpp |
2276 | - windowkeysfilter.cpp |
2277 | + windowinputfilter.cpp |
2278 | windowscreenshotprovider.cpp |
2279 | easingcurve.cpp |
2280 | windowstatestorage.cpp |
2281 | timezoneFormatter.cpp |
2282 | inputeventgenerator.cpp |
2283 | + deviceconfigparser.cpp |
2284 | plugin.cpp |
2285 | ) |
2286 | |
2287 | |
2288 | === modified file 'plugins/Utils/Utils.qmltypes' |
2289 | --- plugins/Utils/Utils.qmltypes 2015-09-03 11:08:46 +0000 |
2290 | +++ plugins/Utils/Utils.qmltypes 2016-03-11 18:12:46 +0000 |
2291 | @@ -147,10 +147,10 @@ |
2292 | } |
2293 | } |
2294 | Component { |
2295 | - name: "WindowKeysFilter" |
2296 | + name: "WindowInputFilter" |
2297 | defaultProperty: "data" |
2298 | prototype: "QQuickItem" |
2299 | - exports: ["Utils/WindowKeysFilter 0.1"] |
2300 | + exports: ["Utils/WindowInputFilter 0.1"] |
2301 | exportMetaObjectRevisions: [0] |
2302 | } |
2303 | Component { |
2304 | |
2305 | === added file 'plugins/Utils/deviceconfigparser.cpp' |
2306 | --- plugins/Utils/deviceconfigparser.cpp 1970-01-01 00:00:00 +0000 |
2307 | +++ plugins/Utils/deviceconfigparser.cpp 2016-03-11 18:12:46 +0000 |
2308 | @@ -0,0 +1,150 @@ |
2309 | +/* |
2310 | + * Copyright 2016 Canonical Ltd. |
2311 | + * |
2312 | + * This program is free software; you can redistribute it and/or modify |
2313 | + * it under the terms of the GNU Lesser General Public License as published by |
2314 | + * the Free Software Foundation; version 3. |
2315 | + * |
2316 | + * This program is distributed in the hope that it will be useful, |
2317 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2318 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2319 | + * GNU Lesser General Public License for more details. |
2320 | + * |
2321 | + * You should have received a copy of the GNU Lesser General Public License |
2322 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2323 | + */ |
2324 | + |
2325 | +#include "deviceconfigparser.h" |
2326 | + |
2327 | +#include <QSettings> |
2328 | +#include <QFileInfo> |
2329 | +#include <QDebug> |
2330 | +#include <QStandardPaths> |
2331 | + |
2332 | +DeviceConfigParser::DeviceConfigParser(QObject *parent): QObject(parent) |
2333 | +{ |
2334 | + QString path; |
2335 | + Q_FOREACH (const QString &standardPath, QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation)) { |
2336 | + if (QFileInfo(standardPath + "/devices.conf").exists()) { |
2337 | + path = standardPath + "/devices.conf"; |
2338 | + break; |
2339 | + } |
2340 | + } |
2341 | + |
2342 | + if (path.isEmpty()) { |
2343 | + path = "/etc/ubuntu/devices.conf"; |
2344 | + } |
2345 | + qDebug() << "Using" << path << "as device configuration file"; |
2346 | + m_config = new QSettings(path, QSettings::IniFormat, this); |
2347 | +} |
2348 | + |
2349 | +QString DeviceConfigParser::name() const |
2350 | +{ |
2351 | + return m_name; |
2352 | +} |
2353 | + |
2354 | +void DeviceConfigParser::setName(const QString &name) |
2355 | +{ |
2356 | + if (m_name == name) { |
2357 | + return; |
2358 | + } |
2359 | + m_name = name; |
2360 | + Q_EMIT changed(); |
2361 | +} |
2362 | + |
2363 | +Qt::ScreenOrientation DeviceConfigParser::primaryOrientation() const |
2364 | +{ |
2365 | + return stringToOrientation(readOrientationFromConfig("PrimaryOrientation"), Qt::PrimaryOrientation); |
2366 | +} |
2367 | + |
2368 | +Qt::ScreenOrientations DeviceConfigParser::supportedOrientations() const |
2369 | +{ |
2370 | + QStringList values = readOrientationsFromConfig("SupportedOrientations"); |
2371 | + if (values.isEmpty()) { |
2372 | + return Qt::PortraitOrientation |
2373 | + | Qt::InvertedPortraitOrientation |
2374 | + | Qt::LandscapeOrientation |
2375 | + | Qt::InvertedLandscapeOrientation; |
2376 | + } |
2377 | + |
2378 | + Qt::ScreenOrientations ret = Qt::PrimaryOrientation; |
2379 | + Q_FOREACH(const QString &orientationString, values) { |
2380 | + ret |= stringToOrientation(orientationString, Qt::PrimaryOrientation); |
2381 | + } |
2382 | + return ret; |
2383 | +} |
2384 | + |
2385 | +Qt::ScreenOrientation DeviceConfigParser::landscapeOrientation() const |
2386 | +{ |
2387 | + return stringToOrientation(readOrientationFromConfig("LandscapeOrientation"), Qt::LandscapeOrientation); |
2388 | +} |
2389 | + |
2390 | +Qt::ScreenOrientation DeviceConfigParser::invertedLandscapeOrientation() const |
2391 | +{ |
2392 | + return stringToOrientation(readOrientationFromConfig("InvertedLandscapeOrientation"), Qt::InvertedLandscapeOrientation); |
2393 | +} |
2394 | + |
2395 | +Qt::ScreenOrientation DeviceConfigParser::portraitOrientation() const |
2396 | +{ |
2397 | + return stringToOrientation(readOrientationFromConfig("PortraitOrientation"), Qt::PortraitOrientation); |
2398 | +} |
2399 | + |
2400 | +Qt::ScreenOrientation DeviceConfigParser::invertedPortraitOrientation() const |
2401 | +{ |
2402 | + return stringToOrientation(readOrientationFromConfig("InvertedPortraitOrientation"), Qt::InvertedPortraitOrientation); |
2403 | +} |
2404 | + |
2405 | +QString DeviceConfigParser::category() const |
2406 | +{ |
2407 | + QStringList supportedValues = {"phone", "tablet", "desktop"}; |
2408 | + m_config->beginGroup(m_name); |
2409 | + QString value = m_config->value("Category", "phone").toString(); |
2410 | + if (!supportedValues.contains(value)) { |
2411 | + qWarning().nospace().noquote() << "Unknown option \"" << value << "\" in " << m_config->fileName() |
2412 | + << ". Supported options are: " << supportedValues.join(", ") << "."; |
2413 | + return "phone"; |
2414 | + } |
2415 | + m_config->endGroup(); |
2416 | + return value; |
2417 | +} |
2418 | + |
2419 | +QStringList DeviceConfigParser::readOrientationsFromConfig(const QString &key) const |
2420 | +{ |
2421 | + m_config->beginGroup(m_name); |
2422 | + |
2423 | + QStringList ret; |
2424 | + if (m_config->contains(key)) { |
2425 | + ret = m_config->value(key).toStringList(); |
2426 | + } |
2427 | + |
2428 | + m_config->endGroup(); |
2429 | + return ret; |
2430 | +} |
2431 | + |
2432 | +QString DeviceConfigParser::readOrientationFromConfig(const QString &key) const |
2433 | +{ |
2434 | + QStringList ret = readOrientationsFromConfig(key); |
2435 | + return ret.count() > 0 ? ret.first() : QString(); |
2436 | +} |
2437 | + |
2438 | +Qt::ScreenOrientation DeviceConfigParser::stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const |
2439 | +{ |
2440 | + if (orientationString == "Landscape") { |
2441 | + return Qt::LandscapeOrientation; |
2442 | + } |
2443 | + if (orientationString == "InvertedLandscape") { |
2444 | + return Qt::InvertedLandscapeOrientation; |
2445 | + } |
2446 | + if (orientationString == "Portrait") { |
2447 | + return Qt::PortraitOrientation; |
2448 | + } |
2449 | + if (orientationString == "InvertedPortrait") { |
2450 | + return Qt::InvertedPortraitOrientation; |
2451 | + } |
2452 | + if (!orientationString.isEmpty()) { |
2453 | + // Some option we don't know. Give some hint on what went wrong. |
2454 | + qWarning().nospace().noquote() << "Unknown option \"" << orientationString << "\" in " << m_config->fileName() |
2455 | + << ". Supported options are: Landscape, InvertedLandscape, Portrait and InvertedPortrait."; |
2456 | + } |
2457 | + return defaultValue; |
2458 | +} |
2459 | |
2460 | === added file 'plugins/Utils/deviceconfigparser.h' |
2461 | --- plugins/Utils/deviceconfigparser.h 1970-01-01 00:00:00 +0000 |
2462 | +++ plugins/Utils/deviceconfigparser.h 2016-03-11 18:12:46 +0000 |
2463 | @@ -0,0 +1,62 @@ |
2464 | +/* |
2465 | + * Copyright 2016 Canonical Ltd. |
2466 | + * |
2467 | + * This program is free software; you can redistribute it and/or modify |
2468 | + * it under the terms of the GNU Lesser General Public License as published by |
2469 | + * the Free Software Foundation; version 3. |
2470 | + * |
2471 | + * This program is distributed in the hope that it will be useful, |
2472 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2473 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2474 | + * GNU Lesser General Public License for more details. |
2475 | + * |
2476 | + * You should have received a copy of the GNU Lesser General Public License |
2477 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2478 | + */ |
2479 | + |
2480 | +#ifndef DEVICECONFIGPARSER_H |
2481 | +#define DEVICECONFIGPARSER_H |
2482 | + |
2483 | +#include <QObject> |
2484 | +#include <QSettings> |
2485 | + |
2486 | +class DeviceConfigParser: public QObject |
2487 | +{ |
2488 | + Q_OBJECT |
2489 | + Q_PROPERTY(QString name READ name WRITE setName NOTIFY changed) |
2490 | + |
2491 | + Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY changed) |
2492 | + Q_PROPERTY(Qt::ScreenOrientations supportedOrientations READ supportedOrientations NOTIFY changed) |
2493 | + Q_PROPERTY(Qt::ScreenOrientation landscapeOrientation READ landscapeOrientation NOTIFY changed) |
2494 | + Q_PROPERTY(Qt::ScreenOrientation invertedLandscapeOrientation READ invertedLandscapeOrientation NOTIFY changed) |
2495 | + Q_PROPERTY(Qt::ScreenOrientation portraitOrientation READ portraitOrientation NOTIFY changed) |
2496 | + Q_PROPERTY(Qt::ScreenOrientation invertedPortraitOrientation READ invertedPortraitOrientation NOTIFY changed) |
2497 | + Q_PROPERTY(QString category READ category NOTIFY changed) |
2498 | + |
2499 | +public: |
2500 | + DeviceConfigParser(QObject *parent = nullptr); |
2501 | + |
2502 | + QString name() const; |
2503 | + void setName(const QString &name); |
2504 | + |
2505 | + Qt::ScreenOrientation primaryOrientation() const; |
2506 | + Qt::ScreenOrientations supportedOrientations() const; |
2507 | + Qt::ScreenOrientation landscapeOrientation() const; |
2508 | + Qt::ScreenOrientation invertedLandscapeOrientation() const; |
2509 | + Qt::ScreenOrientation portraitOrientation() const; |
2510 | + Qt::ScreenOrientation invertedPortraitOrientation() const; |
2511 | + QString category() const; |
2512 | + |
2513 | +Q_SIGNALS: |
2514 | + void changed(); |
2515 | + |
2516 | +private: |
2517 | + QString m_name; |
2518 | + QSettings *m_config; |
2519 | + |
2520 | + QStringList readOrientationsFromConfig(const QString &key) const; |
2521 | + QString readOrientationFromConfig(const QString &key) const; |
2522 | + Qt::ScreenOrientation stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const; |
2523 | +}; |
2524 | + |
2525 | +#endif |
2526 | |
2527 | === modified file 'plugins/Utils/plugin.cpp' |
2528 | --- plugins/Utils/plugin.cpp 2016-01-29 11:52:14 +0000 |
2529 | +++ plugins/Utils/plugin.cpp 2016-03-11 18:12:46 +0000 |
2530 | @@ -30,13 +30,14 @@ |
2531 | #include "qlimitproxymodelqml.h" |
2532 | #include "unitysortfilterproxymodelqml.h" |
2533 | #include "unitymenumodelpaths.h" |
2534 | -#include "windowkeysfilter.h" |
2535 | +#include "windowinputfilter.h" |
2536 | #include "windowscreenshotprovider.h" |
2537 | #include "windowstatestorage.h" |
2538 | #include "constants.h" |
2539 | #include "timezoneFormatter.h" |
2540 | #include "applicationsfiltermodel.h" |
2541 | #include "inputeventgenerator.h" |
2542 | +#include "deviceconfigparser.h" |
2543 | |
2544 | static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine) |
2545 | { |
2546 | @@ -60,7 +61,7 @@ |
2547 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
2548 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
2549 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
2550 | - qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
2551 | + qmlRegisterType<WindowInputFilter>(uri, 0, 1, "WindowInputFilter"); |
2552 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
2553 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
2554 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
2555 | @@ -70,6 +71,7 @@ |
2556 | qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger"); |
2557 | qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel"); |
2558 | qmlRegisterType<InputEventGenerator>(uri, 0, 1, "InputEventGenerator"); |
2559 | + qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser"); |
2560 | } |
2561 | |
2562 | void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
2563 | |
2564 | === modified file 'plugins/Utils/timezoneFormatter.cpp' |
2565 | --- plugins/Utils/timezoneFormatter.cpp 2015-11-20 15:01:39 +0000 |
2566 | +++ plugins/Utils/timezoneFormatter.cpp 2016-03-11 18:12:46 +0000 |
2567 | @@ -33,3 +33,13 @@ |
2568 | } |
2569 | return QString(); |
2570 | } |
2571 | + |
2572 | +QString TimezoneFormatter::currentTimeInTimezoneWithAbbrev(const QVariant &tzId) const |
2573 | +{ |
2574 | + QTimeZone tz(tzId.toByteArray()); |
2575 | + if (tz.isValid()) { |
2576 | + const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz); |
2577 | + return QStringLiteral("%1 %2").arg(now.time().toString(QStringLiteral("h:mm"))).arg(tz.abbreviation(now)); |
2578 | + } |
2579 | + return QString(); |
2580 | +} |
2581 | |
2582 | === modified file 'plugins/Utils/timezoneFormatter.h' |
2583 | --- plugins/Utils/timezoneFormatter.h 2015-09-17 13:42:15 +0000 |
2584 | +++ plugins/Utils/timezoneFormatter.h 2016-03-11 18:12:46 +0000 |
2585 | @@ -27,6 +27,7 @@ |
2586 | ~TimezoneFormatter() = default; |
2587 | |
2588 | Q_INVOKABLE QString currentTimeInTimezone(const QVariant &tzId) const; |
2589 | + Q_INVOKABLE QString currentTimeInTimezoneWithAbbrev(const QVariant &tzId) const; |
2590 | }; |
2591 | |
2592 | #endif |
2593 | |
2594 | === renamed file 'plugins/Utils/windowkeysfilter.cpp' => 'plugins/Utils/windowinputfilter.cpp' |
2595 | --- plugins/Utils/windowkeysfilter.cpp 2015-10-22 17:37:26 +0000 |
2596 | +++ plugins/Utils/windowinputfilter.cpp 2016-03-11 18:12:46 +0000 |
2597 | @@ -16,36 +16,34 @@ |
2598 | * Author: Daniel d'Andrada <daniel.dandrada@canonical.com> |
2599 | */ |
2600 | |
2601 | -#include "windowkeysfilter.h" |
2602 | +#include "windowinputfilter.h" |
2603 | |
2604 | #include <QQuickWindow> |
2605 | |
2606 | -WindowKeysFilter::WindowKeysFilter(QQuickItem *parent) |
2607 | +WindowInputFilter::WindowInputFilter(QQuickItem *parent) |
2608 | : QQuickItem(parent), |
2609 | - m_currentEventTimestamp(0) |
2610 | + m_lastInputTimestamp(0) |
2611 | { |
2612 | connect(this, &QQuickItem::windowChanged, |
2613 | - this, &WindowKeysFilter::setupFilterOnWindow); |
2614 | + this, &WindowInputFilter::setupFilterOnWindow); |
2615 | } |
2616 | |
2617 | -bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event) |
2618 | +bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event) |
2619 | { |
2620 | Q_ASSERT(!m_filteredWindow.isNull()); |
2621 | Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data())); |
2622 | Q_UNUSED(watched); |
2623 | |
2624 | + QInputEvent *inputEvent = dynamic_cast<QInputEvent*>(event); |
2625 | + if (inputEvent) { |
2626 | + m_lastInputTimestamp = inputEvent->timestamp(); |
2627 | + Q_EMIT lastInputTimestampChanged(); |
2628 | + } |
2629 | + |
2630 | if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { |
2631 | // Let QML see this event and decide if it does not want it |
2632 | event->accept(); |
2633 | - |
2634 | - m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp(); |
2635 | - Q_EMIT currentEventTimestampChanged(); |
2636 | - |
2637 | QCoreApplication::sendEvent(this, event); |
2638 | - |
2639 | - m_currentEventTimestamp = 0; |
2640 | - Q_EMIT currentEventTimestampChanged(); |
2641 | - |
2642 | return event->isAccepted(); |
2643 | } else { |
2644 | // Not interested |
2645 | @@ -53,7 +51,7 @@ |
2646 | } |
2647 | } |
2648 | |
2649 | -void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window) |
2650 | +void WindowInputFilter::setupFilterOnWindow(QQuickWindow *window) |
2651 | { |
2652 | if (!m_filteredWindow.isNull()) { |
2653 | m_filteredWindow->removeEventFilter(this); |
2654 | @@ -66,7 +64,7 @@ |
2655 | } |
2656 | } |
2657 | |
2658 | -ulong WindowKeysFilter::currentEventTimestamp() const |
2659 | +ulong WindowInputFilter::lastInputTimestamp() const |
2660 | { |
2661 | - return m_currentEventTimestamp; |
2662 | + return m_lastInputTimestamp; |
2663 | } |
2664 | |
2665 | === renamed file 'plugins/Utils/windowkeysfilter.h' => 'plugins/Utils/windowinputfilter.h' |
2666 | --- plugins/Utils/windowkeysfilter.h 2015-10-22 17:37:26 +0000 |
2667 | +++ plugins/Utils/windowinputfilter.h 2016-03-11 18:12:46 +0000 |
2668 | @@ -16,8 +16,8 @@ |
2669 | * Author: Daniel d'Andrada <daniel.dandrada@canonical.com> |
2670 | */ |
2671 | |
2672 | -#ifndef UNITY_WINDOWKEYSFILTER_H |
2673 | -#define UNITY_WINDOWKEYSFILTER_H |
2674 | +#ifndef UNITY_WINDOWINPUTFILTER_H |
2675 | +#define UNITY_WINDOWINPUTFILTER_H |
2676 | |
2677 | #include <QQuickItem> |
2678 | #include <QPointer> |
2679 | @@ -29,30 +29,30 @@ |
2680 | accepted ones will be filtered out. Events are accepted by default, so make sure you reject |
2681 | the keys you're not interested in. |
2682 | |
2683 | - If more than one WindowKeysFilter exist in the same QML scene (and thus in the same QQuickWindow) |
2684 | + If more than one WindowInputFilter exist in the same QML scene (and thus in the same QQuickWindow) |
2685 | they will be called in the order of creation, which can be tricky to assess. So the best practice |
2686 | - is to have at most one WindowKeysFilter per QML scene. |
2687 | + is to have at most one WindowInputFilter per QML scene. |
2688 | */ |
2689 | -class WindowKeysFilter : public QQuickItem |
2690 | +class WindowInputFilter : public QQuickItem |
2691 | { |
2692 | Q_OBJECT |
2693 | - Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged) |
2694 | + Q_PROPERTY(ulong lastInputTimestamp READ lastInputTimestamp NOTIFY lastInputTimestampChanged) |
2695 | public: |
2696 | - WindowKeysFilter(QQuickItem *parent = 0); |
2697 | + WindowInputFilter(QQuickItem *parent = 0); |
2698 | |
2699 | bool eventFilter(QObject *watched, QEvent *event) override; |
2700 | |
2701 | - ulong currentEventTimestamp() const; |
2702 | + ulong lastInputTimestamp() const; |
2703 | |
2704 | Q_SIGNALS: |
2705 | - void currentEventTimestampChanged(); |
2706 | + void lastInputTimestampChanged(); |
2707 | |
2708 | private Q_SLOTS: |
2709 | void setupFilterOnWindow(QQuickWindow *window); |
2710 | |
2711 | private: |
2712 | QPointer<QQuickWindow> m_filteredWindow; |
2713 | - ulong m_currentEventTimestamp; |
2714 | + ulong m_lastInputTimestamp; |
2715 | }; |
2716 | |
2717 | -#endif // UNITY_WINDOWKEYSFILTER_H |
2718 | +#endif // UNITY_WINDOWINPUTFILTER_H |
2719 | |
2720 | === modified file 'plugins/Wizard/CMakeLists.txt' |
2721 | --- plugins/Wizard/CMakeLists.txt 2014-11-14 17:47:00 +0000 |
2722 | +++ plugins/Wizard/CMakeLists.txt 2016-03-11 18:12:46 +0000 |
2723 | @@ -1,10 +1,16 @@ |
2724 | +include_directories(${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}) |
2725 | + |
2726 | add_library(Wizard-qml MODULE |
2727 | plugin.cpp |
2728 | PageList.cpp |
2729 | System.cpp |
2730 | + LocalePlugin.cpp |
2731 | + timezonemodel.cpp |
2732 | + Status.cpp |
2733 | ) |
2734 | |
2735 | -qt5_use_modules(Wizard-qml DBus Qml) |
2736 | +qt5_use_modules(Wizard-qml DBus Qml Concurrent) |
2737 | +target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS}) |
2738 | add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml) |
2739 | |
2740 | set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1") |
2741 | |
2742 | === added file 'plugins/Wizard/LocalePlugin.cpp' |
2743 | --- plugins/Wizard/LocalePlugin.cpp 1970-01-01 00:00:00 +0000 |
2744 | +++ plugins/Wizard/LocalePlugin.cpp 2016-03-11 18:12:46 +0000 |
2745 | @@ -0,0 +1,291 @@ |
2746 | +/* |
2747 | + * Copyright (C) 2015 Canonical Ltd. |
2748 | + * |
2749 | + * This program is free software: you can redistribute it and/or modify it |
2750 | + * under the terms of the GNU General Public License version 3, as published |
2751 | + * by the Free Software Foundation. |
2752 | + * |
2753 | + * This program is distributed in the hope that it will be useful, but |
2754 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2755 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2756 | + * PURPOSE. See the GNU General Public License for more details. |
2757 | + * |
2758 | + * You should have received a copy of the GNU General Public License along |
2759 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2760 | + */ |
2761 | + |
2762 | +#include <QLocale> |
2763 | +#include <QStringList> |
2764 | + |
2765 | +#include <libintl.h> |
2766 | + |
2767 | +#include "LocalePlugin.h" |
2768 | + |
2769 | +class LocalePrivate { |
2770 | +public: |
2771 | + LocalePrivate() { |
2772 | + m_mccCodes = QHash<int, QString> |
2773 | + ({{202,"gr"}, |
2774 | + {204,"nl"}, |
2775 | + {206,"be"}, |
2776 | + {208,"fr"}, |
2777 | + {212,"mc"}, |
2778 | + {213,"ad"}, |
2779 | + {214,"es"}, |
2780 | + {216,"hu"}, |
2781 | + {218,"ba"}, |
2782 | + {219,"hr"}, |
2783 | + {220,"rs"}, |
2784 | + {222,"it"}, |
2785 | + {226,"ro"}, |
2786 | + {228,"ch"}, |
2787 | + {230,"cz"}, |
2788 | + {231,"sk"}, |
2789 | + {232,"at"}, |
2790 | + {234,"gb"}, |
2791 | + {235,"gb"}, |
2792 | + {238,"dk"}, |
2793 | + {240,"se"}, |
2794 | + {242,"no"}, |
2795 | + {244,"fi"}, |
2796 | + {246,"lt"}, |
2797 | + {247,"lv"}, |
2798 | + {248,"ee"}, |
2799 | + {250,"ru"}, |
2800 | + {255,"ua"}, |
2801 | + {257,"by"}, |
2802 | + {259,"md"}, |
2803 | + {260,"pl"}, |
2804 | + {262,"de"}, |
2805 | + {266,"gi"}, |
2806 | + {268,"pt"}, |
2807 | + {270,"lu"}, |
2808 | + {272,"ie"}, |
2809 | + {274,"is"}, |
2810 | + {276,"al"}, |
2811 | + {278,"mt"}, |
2812 | + {280,"cy"}, |
2813 | + {282,"ge"}, |
2814 | + {283,"am"}, |
2815 | + {284,"bg"}, |
2816 | + {286,"tr"}, |
2817 | + {288,"fo"}, |
2818 | + {289,"ge"}, |
2819 | + {290,"gl"}, |
2820 | + {292,"sm"}, |
2821 | + {293,"si"}, |
2822 | + {294,"mk"}, |
2823 | + {295,"li"}, |
2824 | + {297,"me"}, |
2825 | + {302,"ca"}, |
2826 | + {308,"pm"}, |
2827 | + {310,"gu"}, |
2828 | + {310,"us"}, |
2829 | + {311,"gu"}, |
2830 | + {311,"us"}, |
2831 | + {312,"us"}, |
2832 | + {316,"us"}, |
2833 | + {330,"pr"}, |
2834 | + {334,"mx"}, |
2835 | + {338,"jm"}, |
2836 | + {340,"fg"}, |
2837 | + {340,"gp"}, |
2838 | + {340,"mq"}, |
2839 | + {342,"bb"}, |
2840 | + {344,"ag"}, |
2841 | + {346,"ky"}, |
2842 | + {348,"vg"}, |
2843 | + {350,"bm"}, |
2844 | + {352,"gd"}, |
2845 | + {354,"ms"}, |
2846 | + {356,"kn"}, |
2847 | + {358,"lc"}, |
2848 | + {360,"vc"}, |
2849 | + {362,"an"}, |
2850 | + {362,"cw"}, |
2851 | + {363,"aw"}, |
2852 | + {364,"bs"}, |
2853 | + {365,"ai"}, |
2854 | + {366,"dm"}, |
2855 | + {368,"cu"}, |
2856 | + {370,"do"}, |
2857 | + {372,"ht"}, |
2858 | + {374,"tt"}, |
2859 | + {376,"tc"}, |
2860 | + {376,"vi"}, |
2861 | + {400,"az"}, |
2862 | + {401,"kz"}, |
2863 | + {402,"bt"}, |
2864 | + {404,"in"}, |
2865 | + {405,"in"}, |
2866 | + {410,"pk"}, |
2867 | + {412,"af"}, |
2868 | + {413,"lk"}, |
2869 | + {414,"mm"}, |
2870 | + {415,"lb"}, |
2871 | + {416,"jo"}, |
2872 | + {417,"sy"}, |
2873 | + {418,"iq"}, |
2874 | + {419,"kw"}, |
2875 | + {420,"sa"}, |
2876 | + {421,"ye"}, |
2877 | + {422,"om"}, |
2878 | + {424,"ae"}, |
2879 | + {425,"il"}, |
2880 | + {425,"ps"}, |
2881 | + {426,"bh"}, |
2882 | + {427,"qa"}, |
2883 | + {428,"mn"}, |
2884 | + {429,"np"}, |
2885 | + {430,"ae"}, |
2886 | + {431,"ae"}, |
2887 | + {432,"ir"}, |
2888 | + {434,"uz"}, |
2889 | + {436,"tk"}, |
2890 | + {437,"kg"}, |
2891 | + {438,"tm"}, |
2892 | + {440,"jp"}, |
2893 | + {441,"jp"}, |
2894 | + {450,"kr"}, |
2895 | + {452,"vn"}, |
2896 | + {454,"hk"}, |
2897 | + {455,"mo"}, |
2898 | + {456,"kh"}, |
2899 | + {457,"la"}, |
2900 | + {460,"cn"}, |
2901 | + {466,"tw"}, |
2902 | + {467,"kp"}, |
2903 | + {470,"bd"}, |
2904 | + {472,"mv"}, |
2905 | + {502,"my"}, |
2906 | + {505,"au"}, |
2907 | + {510,"id"}, |
2908 | + {514,"tp"}, |
2909 | + {515,"ph"}, |
2910 | + {520,"th"}, |
2911 | + {525,"sg"}, |
2912 | + {528,"bn"}, |
2913 | + {530,"nz"}, |
2914 | + {537,"pg"}, |
2915 | + {539,"to"}, |
2916 | + {540,"sb"}, |
2917 | + {541,"vu"}, |
2918 | + {542,"fj"}, |
2919 | + {544,"as"}, |
2920 | + {545,"ki"}, |
2921 | + {546,"nc"}, |
2922 | + {547,"pf"}, |
2923 | + {548,"ck"}, |
2924 | + {549,"ws"}, |
2925 | + {550,"fm"}, |
2926 | + {552,"pw"}, |
2927 | + {553,"tv"}, |
2928 | + {555,"nu"}, |
2929 | + {602,"eg"}, |
2930 | + {603,"dz"}, |
2931 | + {604,"ma"}, |
2932 | + {605,"tn"}, |
2933 | + {606,"ly"}, |
2934 | + {607,"gm"}, |
2935 | + {608,"sn"}, |
2936 | + {609,"mr"}, |
2937 | + {610,"ml"}, |
2938 | + {611,"gn"}, |
2939 | + {612,"ci"}, |
2940 | + {613,"bf"}, |
2941 | + {614,"ne"}, |
2942 | + {615,"tg"}, |
2943 | + {616,"bj"}, |
2944 | + {617,"mu"}, |
2945 | + {618,"lr"}, |
2946 | + {619,"sl"}, |
2947 | + {620,"gh"}, |
2948 | + {621,"ng"}, |
2949 | + {622,"td"}, |
2950 | + {623,"cf"}, |
2951 | + {624,"cm"}, |
2952 | + {625,"cv"}, |
2953 | + {626,"st"}, |
2954 | + {627,"gq"}, |
2955 | + {628,"ga"}, |
2956 | + {629,"cg"}, |
2957 | + {630,"cd"}, |
2958 | + {631,"ao"}, |
2959 | + {632,"gw"}, |
2960 | + {633,"sc"}, |
2961 | + {634,"sd"}, |
2962 | + {635,"rw"}, |
2963 | + {636,"et"}, |
2964 | + {637,"so"}, |
2965 | + {638,"dj"}, |
2966 | + {639,"ke"}, |
2967 | + {640,"tz"}, |
2968 | + {641,"ug"}, |
2969 | + {642,"bi"}, |
2970 | + {643,"mz"}, |
2971 | + {645,"zm"}, |
2972 | + {646,"mg"}, |
2973 | + {647,"re"}, |
2974 | + {648,"zw"}, |
2975 | + {649,"na"}, |
2976 | + {650,"mw"}, |
2977 | + {651,"ls"}, |
2978 | + {652,"bw"}, |
2979 | + {653,"sz"}, |
2980 | + {654,"km"}, |
2981 | + {655,"za"}, |
2982 | + {657,"er"}, |
2983 | + {659,"ss"}, |
2984 | + {702,"bz"}, |
2985 | + {704,"gt"}, |
2986 | + {706,"sv"}, |
2987 | + {708,"hn"}, |
2988 | + {710,"ni"}, |
2989 | + {712,"cr"}, |
2990 | + {714,"pa"}, |
2991 | + {716,"pe"}, |
2992 | + {722,"ar"}, |
2993 | + {724,"br"}, |
2994 | + {730,"cl"}, |
2995 | + {732,"co"}, |
2996 | + {734,"ve"}, |
2997 | + {736,"bo"}, |
2998 | + {738,"gy"}, |
2999 | + {740,"ec"}, |
3000 | + {744,"py"}, |
3001 | + {746,"sr"}, |
3002 | + {748,"uy"}, |
3003 | + {750,"fk"}} |
3004 | + ); |
3005 | + } |
3006 | + |
3007 | + QString mccToCountryCode(int mcc) const { |
3008 | + return m_mccCodes.value(mcc, "us").toUpper(); |
3009 | + } |
3010 | + |
3011 | +private: |
3012 | + // MCC = Mobile Country Code, see https://en.wikipedia.org/wiki/Mobile_country_code |
3013 | + QHash<int,QString> m_mccCodes; |
3014 | +}; |
3015 | + |
3016 | +Q_GLOBAL_STATIC(LocalePrivate, d) |
3017 | + |
3018 | +LocaleAttached::LocaleAttached(QObject* parent) |
3019 | + : QObject(parent) |
3020 | +{ |
3021 | +} |
3022 | + |
3023 | +QString LocaleAttached::mccToCountryCode(int mcc) const |
3024 | +{ |
3025 | + return d->mccToCountryCode(mcc); |
3026 | +} |
3027 | + |
3028 | +LocalePlugin::LocalePlugin(QObject* parent) |
3029 | + : QObject(parent) |
3030 | +{ |
3031 | +} |
3032 | + |
3033 | +LocaleAttached* LocalePlugin::qmlAttachedProperties(QObject* parent) |
3034 | +{ |
3035 | + return new LocaleAttached(parent); |
3036 | +} |
3037 | |
3038 | === added file 'plugins/Wizard/LocalePlugin.h' |
3039 | --- plugins/Wizard/LocalePlugin.h 1970-01-01 00:00:00 +0000 |
3040 | +++ plugins/Wizard/LocalePlugin.h 2016-03-11 18:12:46 +0000 |
3041 | @@ -0,0 +1,58 @@ |
3042 | +/* |
3043 | + * Copyright (C) 2015 Canonical Ltd. |
3044 | + * |
3045 | + * This program is free software: you can redistribute it and/or modify it |
3046 | + * under the terms of the GNU General Public License version 3, as published |
3047 | + * by the Free Software Foundation. |
3048 | + * |
3049 | + * This program is distributed in the hope that it will be useful, but |
3050 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3051 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3052 | + * PURPOSE. See the GNU General Public License for more details. |
3053 | + * |
3054 | + * You should have received a copy of the GNU General Public License along |
3055 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3056 | + */ |
3057 | + |
3058 | +#ifndef LOCALE_PLUGIN_H |
3059 | +#define LOCALE_PLUGIN_H |
3060 | + |
3061 | +#include <QObject> |
3062 | +#include <QString> |
3063 | +#include <QJsonObject> |
3064 | +#include <QtQml> |
3065 | + |
3066 | +class LocaleAttached: public QObject |
3067 | +{ |
3068 | + Q_OBJECT |
3069 | +protected: |
3070 | + explicit LocaleAttached(QObject *parent = 0); |
3071 | + |
3072 | +public: |
3073 | + Q_INVOKABLE QString mccToCountryCode(int mcc) const; |
3074 | + |
3075 | + friend class LocalePlugin; |
3076 | +}; |
3077 | + |
3078 | +/** |
3079 | + * A simplified wrapper around QLocale. |
3080 | + * |
3081 | + * The wrapper is implemented as an attached property, which makes it possible |
3082 | + * to use it as if its methods were static: |
3083 | + * |
3084 | + * @code |
3085 | + * var langs = LocalePlugin.languages(); |
3086 | + * @endcode |
3087 | + */ |
3088 | +class LocalePlugin: public QObject |
3089 | +{ |
3090 | + Q_OBJECT |
3091 | +public: |
3092 | + explicit LocalePlugin(QObject *parent = 0); |
3093 | + |
3094 | + static LocaleAttached* qmlAttachedProperties(QObject *parent); |
3095 | +}; |
3096 | + |
3097 | +QML_DECLARE_TYPEINFO(LocalePlugin, QML_HAS_ATTACHED_PROPERTIES) |
3098 | + |
3099 | +#endif // LOCALE_PLUGIN_H |
3100 | |
3101 | === modified file 'plugins/Wizard/PageList.cpp' |
3102 | --- plugins/Wizard/PageList.cpp 2015-09-14 09:11:08 +0000 |
3103 | +++ plugins/Wizard/PageList.cpp 2016-03-11 18:12:46 +0000 |
3104 | @@ -40,20 +40,20 @@ |
3105 | m_index(-1), |
3106 | m_pages() |
3107 | { |
3108 | - QString qmlSuffix = QStringLiteral(".qml"); |
3109 | - QString disabledSuffix = QStringLiteral(".disabled"); |
3110 | + const QString qmlSuffix = QStringLiteral(".qml"); |
3111 | + const QString disabledSuffix = QStringLiteral(".disabled"); |
3112 | QSet<QString> disabledPages; |
3113 | QStringList dataDirs; |
3114 | |
3115 | if (!isRunningInstalled() && getenv("WIZARD_TESTING") == nullptr) { |
3116 | - dataDirs = QStringList() << qmlDirectory(); |
3117 | + dataDirs << qmlDirectory(); |
3118 | } else { |
3119 | dataDirs = shellDataDirs(); |
3120 | } |
3121 | |
3122 | Q_FOREACH(const QString &dataDir, dataDirs) { |
3123 | QDir dir(dataDir + "/Wizard/Pages"); |
3124 | - QStringList entries = dir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Files | QDir::Readable); |
3125 | + const QStringList entries = dir.entryList(QStringList(QStringLiteral("[0-9]*")), QDir::Files | QDir::Readable); |
3126 | Q_FOREACH(const QString &entry, entries) { |
3127 | if (!m_pages.contains(entry) && entry.endsWith(qmlSuffix)) |
3128 | m_pages.insert(entry, dir.absoluteFilePath(entry)); |
3129 | |
3130 | === added file 'plugins/Wizard/Status.cpp' |
3131 | --- plugins/Wizard/Status.cpp 1970-01-01 00:00:00 +0000 |
3132 | +++ plugins/Wizard/Status.cpp 2016-03-11 18:12:46 +0000 |
3133 | @@ -0,0 +1,143 @@ |
3134 | +/* |
3135 | + * Copyright (C) 2015 Canonical Ltd. |
3136 | + * |
3137 | + * This program is free software: you can redistribute it and/or modify it |
3138 | + * under the terms of the GNU General Public License version 3, as published |
3139 | + * by the Free Software Foundation. |
3140 | + * |
3141 | + * This program is distributed in the hope that it will be useful, but |
3142 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3143 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3144 | + * PURPOSE. See the GNU General Public License for more details. |
3145 | + * |
3146 | + * You should have received a copy of the GNU General Public License along |
3147 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3148 | + */ |
3149 | + |
3150 | +#include <QDebug> |
3151 | +#include <QDBusConnection> |
3152 | + |
3153 | +#include "Status.h" |
3154 | + |
3155 | +Status::Status() |
3156 | +{ |
3157 | + initNM(); |
3158 | + initUPower(); |
3159 | +} |
3160 | + |
3161 | +void Status::initNM() |
3162 | +{ |
3163 | + m_nmIface = new QDBusInterface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", |
3164 | + QDBusConnection::systemBus(), this); |
3165 | + |
3166 | + QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "PropertiesChanged", |
3167 | + this, SLOT(onNMPropertiesChanged(QVariantMap))); |
3168 | +} |
3169 | + |
3170 | +void Status::onNMPropertiesChanged(const QVariantMap &changedProps) |
3171 | +{ |
3172 | + if (changedProps.contains("State") || changedProps.contains("Connectivity")) { |
3173 | + Q_EMIT onlineChanged(); |
3174 | + Q_EMIT networkIconChanged(); |
3175 | + } |
3176 | + |
3177 | + if (changedProps.contains("PrimaryConnection") || changedProps.contains("SpecificObject") || changedProps.contains("Strength")) { |
3178 | + Q_EMIT networkIconChanged(); |
3179 | + } |
3180 | +} |
3181 | + |
3182 | +bool Status::online() const |
3183 | +{ |
3184 | + if (!m_nmIface->isValid()) |
3185 | + return false; |
3186 | + |
3187 | + return m_nmIface->property("State").toUInt() == 70; |
3188 | +} |
3189 | + |
3190 | +QString Status::networkIcon() |
3191 | +{ |
3192 | + QString iconName = QStringLiteral("nm-no-connection"); |
3193 | + |
3194 | + if (!online()) { |
3195 | + return iconName; |
3196 | + } |
3197 | + |
3198 | + const QString primaryConn = m_nmIface->property("PrimaryConnection").value<QDBusObjectPath>().path(); |
3199 | + const QString primaryConnType = m_nmIface->property("PrimaryConnectionType").toString(); |
3200 | + |
3201 | + if (primaryConn.isEmpty()) { |
3202 | + qWarning() << "Empty primary connection"; |
3203 | + return iconName; |
3204 | + } |
3205 | + |
3206 | + if (primaryConnType == "802-11-wireless") { |
3207 | + QDBusInterface activeConn("org.freedesktop.NetworkManager", primaryConn, "org.freedesktop.NetworkManager.Connection.Active", QDBusConnection::systemBus()); |
3208 | + |
3209 | + if (activeConn.isValid()) { |
3210 | + const QString apPath = activeConn.property("SpecificObject").value<QDBusObjectPath>().path(); |
3211 | + |
3212 | + if (apPath.isEmpty()) { |
3213 | + qWarning() << "No AP path"; |
3214 | + return iconName; |
3215 | + } |
3216 | + |
3217 | + QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", primaryConn, "org.freedesktop.NetworkManager.Connection.Active", "PropertiesChanged", |
3218 | + this, SLOT(onNMPropertiesChanged(QVariantMap))); |
3219 | + |
3220 | + QDBusInterface ap("org.freedesktop.NetworkManager", apPath, "org.freedesktop.NetworkManager.AccessPoint", QDBusConnection::systemBus()); |
3221 | + |
3222 | + if (!ap.isValid()) { |
3223 | + qWarning() << "Invalid AP"; |
3224 | + return iconName; |
3225 | + } |
3226 | + |
3227 | + QDBusConnection::systemBus().connect("org.freedesktop.NetworkManager", apPath, "org.freedesktop.NetworkManager.AccessPoint", "PropertiesChanged", |
3228 | + this, SLOT(onNMPropertiesChanged(QVariantMap))); |
3229 | + |
3230 | + const uint strength = ap.property("Strength").toUInt(); |
3231 | + const uint flags = ap.property("Flags").toUInt(); |
3232 | + |
3233 | + if (strength == 0) { |
3234 | + iconName = "nm-signal-00"; |
3235 | + } else if (strength <= 25) { |
3236 | + iconName = "nm-signal-25"; |
3237 | + } else if (strength <= 50) { |
3238 | + iconName = "nm-signal-50"; |
3239 | + } else if (strength <= 75) { |
3240 | + iconName = "nm-signal-75"; |
3241 | + } else if (strength <= 100) { |
3242 | + iconName = "nm-signal-100"; |
3243 | + } |
3244 | + |
3245 | + if (flags >= 1) { |
3246 | + iconName += "-secure"; |
3247 | + } |
3248 | + } |
3249 | + } |
3250 | + |
3251 | + return iconName; |
3252 | +} |
3253 | + |
3254 | +void Status::initUPower() |
3255 | +{ |
3256 | + m_upowerIface = new QDBusInterface("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.UPower.Device", |
3257 | + QDBusConnection::systemBus(), this); |
3258 | + QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice", "org.freedesktop.DBus.Properties", |
3259 | + "PropertiesChanged", this, SLOT(onUPowerPropertiesChanged(QString,QVariantMap,QStringList))); |
3260 | +} |
3261 | + |
3262 | +void Status::onUPowerPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps) |
3263 | +{ |
3264 | + Q_UNUSED(iface) |
3265 | + Q_UNUSED(invalidatedProps) |
3266 | + |
3267 | + if (changedProps.contains("IconName")) { |
3268 | + Q_EMIT batteryIconChanged(); |
3269 | + } |
3270 | +} |
3271 | + |
3272 | +QString Status::batteryIcon() const |
3273 | +{ |
3274 | + const QString iconName = m_upowerIface->property("IconName").toString(); |
3275 | + return iconName; |
3276 | +} |
3277 | |
3278 | === added file 'plugins/Wizard/Status.h' |
3279 | --- plugins/Wizard/Status.h 1970-01-01 00:00:00 +0000 |
3280 | +++ plugins/Wizard/Status.h 2016-03-11 18:12:46 +0000 |
3281 | @@ -0,0 +1,60 @@ |
3282 | +/* |
3283 | + * Copyright (C) 2015 Canonical Ltd. |
3284 | + * |
3285 | + * This program is free software: you can redistribute it and/or modify it |
3286 | + * under the terms of the GNU General Public License version 3, as published |
3287 | + * by the Free Software Foundation. |
3288 | + * |
3289 | + * This program is distributed in the hope that it will be useful, but |
3290 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3291 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3292 | + * PURPOSE. See the GNU General Public License for more details. |
3293 | + * |
3294 | + * You should have received a copy of the GNU General Public License along |
3295 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3296 | + */ |
3297 | + |
3298 | +#ifndef WIZARD_STATUS_H |
3299 | +#define WIZARD_STATUS_H |
3300 | + |
3301 | +#include <QObject> |
3302 | +#include <QString> |
3303 | +#include <QDBusInterface> |
3304 | + |
3305 | +class Status: public QObject |
3306 | +{ |
3307 | + Q_OBJECT |
3308 | + Q_PROPERTY(bool online READ online NOTIFY onlineChanged) |
3309 | + Q_PROPERTY(QString networkIcon READ networkIcon NOTIFY networkIconChanged) |
3310 | + Q_PROPERTY(QString batteryIcon READ batteryIcon NOTIFY batteryIconChanged) |
3311 | +public: |
3312 | + Status(); |
3313 | + ~Status() = default; |
3314 | + |
3315 | + bool online() const; |
3316 | + QString networkIcon(); |
3317 | + |
3318 | + QString batteryIcon() const; |
3319 | + |
3320 | +Q_SIGNALS: |
3321 | + void networkIconChanged(); |
3322 | + void onlineChanged(); |
3323 | + void batteryIconChanged(); |
3324 | + |
3325 | +private Q_SLOTS: |
3326 | + void onNMPropertiesChanged(const QVariantMap &changedProps); |
3327 | + void onUPowerPropertiesChanged(const QString &iface, const QVariantMap &changedProps, const QStringList &invalidatedProps); |
3328 | + |
3329 | +private: |
3330 | + Q_DISABLE_COPY(Status) |
3331 | + |
3332 | + // network status |
3333 | + void initNM(); |
3334 | + QDBusInterface * m_nmIface = nullptr; |
3335 | + |
3336 | + // battery status |
3337 | + void initUPower(); |
3338 | + QDBusInterface * m_upowerIface = nullptr; |
3339 | +}; |
3340 | + |
3341 | +#endif |
3342 | |
3343 | === modified file 'plugins/Wizard/System.cpp' |
3344 | --- plugins/Wizard/System.cpp 2015-09-23 15:14:01 +0000 |
3345 | +++ plugins/Wizard/System.cpp 2016-03-11 18:12:46 +0000 |
3346 | @@ -1,5 +1,5 @@ |
3347 | /* |
3348 | - * Copyright (C) 2014 Canonical Ltd. |
3349 | + * Copyright (C) 2014-2015 Canonical Ltd. |
3350 | * |
3351 | * This program is free software: you can redistribute it and/or modify it |
3352 | * under the terms of the GNU General Public License version 3, as published |
3353 | @@ -25,10 +25,10 @@ |
3354 | #include <QLocale> |
3355 | #include <QMap> |
3356 | #include <QProcess> |
3357 | +#include <QDebug> |
3358 | |
3359 | System::System() |
3360 | - : QObject(), |
3361 | - m_fsWatcher() |
3362 | + : QObject() |
3363 | { |
3364 | // Register the argument needed for UpdateActivationEnvironment below |
3365 | qDBusRegisterMetaType<QMap<QString,QString>>(); |
3366 | @@ -88,7 +88,7 @@ |
3367 | QDBusConnection::sessionBus().asyncCall(msg); |
3368 | } |
3369 | |
3370 | -void System::updateSessionLanguage(const QString &locale) |
3371 | +void System::updateSessionLocale(const QString &locale) |
3372 | { |
3373 | const QString language = locale.split(QStringLiteral("."))[0]; |
3374 | |
3375 | @@ -106,5 +106,6 @@ |
3376 | initctl stop smart-scopes-proxy; \ |
3377 | initctl emit --no-wait indicator-services-start; \ |
3378 | initctl restart --no-wait maliit-server; \ |
3379 | + initctl restart --no-wait indicator-messages; \ |
3380 | initctl restart --no-wait unity8-dash\"")); |
3381 | } |
3382 | |
3383 | === modified file 'plugins/Wizard/System.h' |
3384 | --- plugins/Wizard/System.h 2015-05-21 16:05:57 +0000 |
3385 | +++ plugins/Wizard/System.h 2016-03-11 18:12:46 +0000 |
3386 | @@ -1,5 +1,5 @@ |
3387 | /* |
3388 | - * Copyright (C) 2014 Canonical Ltd. |
3389 | + * Copyright (C) 2014-2015 Canonical Ltd. |
3390 | * |
3391 | * This program is free software: you can redistribute it and/or modify it |
3392 | * under the terms of the GNU General Public License version 3, as published |
3393 | @@ -28,12 +28,13 @@ |
3394 | |
3395 | public: |
3396 | System(); |
3397 | + ~System() = default; |
3398 | |
3399 | bool wizardEnabled() const; |
3400 | void setWizardEnabled(bool enabled); |
3401 | |
3402 | public Q_SLOTS: |
3403 | - void updateSessionLanguage(const QString &locale); |
3404 | + void updateSessionLocale(const QString &locale); |
3405 | |
3406 | Q_SIGNALS: |
3407 | void wizardEnabledChanged(); |
3408 | |
3409 | === modified file 'plugins/Wizard/plugin.cpp' |
3410 | --- plugins/Wizard/plugin.cpp 2014-11-21 19:28:16 +0000 |
3411 | +++ plugins/Wizard/plugin.cpp 2016-03-11 18:12:46 +0000 |
3412 | @@ -17,19 +17,18 @@ |
3413 | #include "plugin.h" |
3414 | #include "PageList.h" |
3415 | #include "System.h" |
3416 | +#include "timezonemodel.h" |
3417 | +#include "LocalePlugin.h" |
3418 | +#include "Status.h" |
3419 | |
3420 | #include <QtQml/qqml.h> |
3421 | |
3422 | -static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
3423 | -{ |
3424 | - Q_UNUSED(engine) |
3425 | - Q_UNUSED(scriptEngine) |
3426 | - return new System(); |
3427 | -} |
3428 | - |
3429 | void WizardPlugin::registerTypes(const char *uri) |
3430 | { |
3431 | Q_ASSERT(uri == QLatin1String("Wizard")); |
3432 | qmlRegisterType<PageList>(uri, 0, 1, "PageList"); |
3433 | - qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider); |
3434 | + qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; }); |
3435 | + qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; }); |
3436 | + qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel"); |
3437 | + qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin"); |
3438 | } |
3439 | |
3440 | === modified file 'plugins/Wizard/plugin.h' |
3441 | --- plugins/Wizard/plugin.h 2015-04-30 09:31:51 +0000 |
3442 | +++ plugins/Wizard/plugin.h 2016-03-11 18:12:46 +0000 |
3443 | @@ -17,13 +17,12 @@ |
3444 | #ifndef WIZARD_PLUGIN_H |
3445 | #define WIZARD_PLUGIN_H |
3446 | |
3447 | -#include <QtQml/QQmlEngine> |
3448 | #include <QtQml/QQmlExtensionPlugin> |
3449 | |
3450 | class WizardPlugin : public QQmlExtensionPlugin |
3451 | { |
3452 | Q_OBJECT |
3453 | - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
3454 | + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) |
3455 | |
3456 | public: |
3457 | void registerTypes(const char *uri) override; |
3458 | |
3459 | === added file 'plugins/Wizard/timezonemodel.cpp' |
3460 | --- plugins/Wizard/timezonemodel.cpp 1970-01-01 00:00:00 +0000 |
3461 | +++ plugins/Wizard/timezonemodel.cpp 2016-03-11 18:12:46 +0000 |
3462 | @@ -0,0 +1,239 @@ |
3463 | +/* |
3464 | + * Copyright (C) 2016 Canonical Ltd. |
3465 | + * |
3466 | + * This program is free software: you can redistribute it and/or modify it |
3467 | + * under the terms of the GNU General Public License version 3, as published |
3468 | + * by the Free Software Foundation. |
3469 | + * |
3470 | + * This program is distributed in the hope that it will be useful, but |
3471 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3472 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3473 | + * PURPOSE. See the GNU General Public License for more details. |
3474 | + * |
3475 | + * You should have received a copy of the GNU General Public License along |
3476 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3477 | + */ |
3478 | + |
3479 | +#include <QDebug> |
3480 | + |
3481 | +#include <glib.h> |
3482 | +#include <glib-object.h> |
3483 | + |
3484 | +#include "LocalePlugin.h" |
3485 | +#include "timezonemodel.h" |
3486 | + |
3487 | +TimeZoneLocationModel::TimeZoneLocationModel(QObject *parent): |
3488 | + QAbstractListModel(parent), |
3489 | + m_listUpdating(false), |
3490 | + m_cancellable(nullptr) |
3491 | +{ |
3492 | + m_roleNames[Qt::DisplayRole] = "displayName"; |
3493 | + m_roleNames[TimeZoneRole] = "timeZone"; |
3494 | + m_roleNames[CityRole] = "city"; |
3495 | + m_roleNames[CountryRole] = "country"; |
3496 | + m_roleNames[OffsetRole] = "offset"; |
3497 | + m_roleNames[LatitudeRole] = "latitude"; |
3498 | + m_roleNames[LongitudeRole] = "longitude"; |
3499 | +} |
3500 | + |
3501 | +int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const |
3502 | +{ |
3503 | + if (parent.isValid()) { |
3504 | + return 0; |
3505 | + } else if (m_filter.isEmpty()) { |
3506 | + return m_countryLocations.count(); |
3507 | + } else { |
3508 | + return m_locations.count(); |
3509 | + } |
3510 | +} |
3511 | + |
3512 | +QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const |
3513 | +{ |
3514 | + GeonamesCity *city; |
3515 | + if (m_filter.isEmpty()) { |
3516 | + city = m_countryLocations.value(index.row()); |
3517 | + } else { |
3518 | + city = m_locations.value(index.row()); |
3519 | + } |
3520 | + if (!city) |
3521 | + return QVariant(); |
3522 | + |
3523 | + switch (role) { |
3524 | + case Qt::DisplayRole: |
3525 | + return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city)) |
3526 | + .arg(geonames_city_get_state(city)) |
3527 | + .arg(geonames_city_get_country(city)); |
3528 | + case SimpleRole: |
3529 | + return QStringLiteral("%1, %2").arg(geonames_city_get_name(city)) |
3530 | + .arg(geonames_city_get_country(city)); |
3531 | + case TimeZoneRole: |
3532 | + return geonames_city_get_timezone(city); |
3533 | + case CountryRole: |
3534 | + return geonames_city_get_country(city); |
3535 | + case CityRole: |
3536 | + return geonames_city_get_name(city); |
3537 | + case OffsetRole: { |
3538 | + QTimeZone tmp(geonames_city_get_timezone(city)); |
3539 | + return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600; |
3540 | + } |
3541 | + case LatitudeRole: |
3542 | + return geonames_city_get_latitude(city); |
3543 | + case LongitudeRole: |
3544 | + return geonames_city_get_longitude(city); |
3545 | + default: |
3546 | + qWarning() << Q_FUNC_INFO << "Unknown role"; |
3547 | + return QVariant(); |
3548 | + } |
3549 | +} |
3550 | + |
3551 | +QHash<int, QByteArray> TimeZoneLocationModel::roleNames() const |
3552 | +{ |
3553 | + return m_roleNames; |
3554 | +} |
3555 | + |
3556 | +void TimeZoneLocationModel::setModel(const QList<GeonamesCity *> &locations) |
3557 | +{ |
3558 | + beginResetModel(); |
3559 | + |
3560 | + Q_FOREACH(GeonamesCity *city, m_locations) { |
3561 | + geonames_city_free(city); |
3562 | + } |
3563 | + |
3564 | + m_locations = locations; |
3565 | + endResetModel(); |
3566 | +} |
3567 | + |
3568 | +void TimeZoneLocationModel::filterFinished(GObject *source_object, |
3569 | + GAsyncResult *res, |
3570 | + gpointer user_data) |
3571 | +{ |
3572 | + Q_UNUSED(source_object); |
3573 | + |
3574 | + g_autofree gint *cities = nullptr; |
3575 | + guint cities_len = 0; |
3576 | + g_autoptr(GError) error = nullptr; |
3577 | + |
3578 | + cities = geonames_query_cities_finish(res, &cities_len, &error); |
3579 | + if (error) { |
3580 | + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { |
3581 | + TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data); |
3582 | + g_clear_object(&model->m_cancellable); |
3583 | + model->setListUpdating(false); |
3584 | + qWarning() << "Could not filter timezones:" << error->message; |
3585 | + } |
3586 | + return; |
3587 | + } |
3588 | + |
3589 | + QList<GeonamesCity *> locations; |
3590 | + |
3591 | + for (guint i = 0; i < cities_len; ++i) { |
3592 | + GeonamesCity *city = geonames_get_city(cities[i]); |
3593 | + if (city) { |
3594 | + locations.append(city); |
3595 | + } |
3596 | + } |
3597 | + |
3598 | + TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data); |
3599 | + |
3600 | + g_clear_object(&model->m_cancellable); |
3601 | + |
3602 | + model->setModel(locations); |
3603 | + model->setListUpdating(false); |
3604 | +} |
3605 | + |
3606 | +bool TimeZoneLocationModel::listUpdating() const |
3607 | +{ |
3608 | + return m_listUpdating; |
3609 | +} |
3610 | + |
3611 | +void TimeZoneLocationModel::setListUpdating(bool listUpdating) |
3612 | +{ |
3613 | + if (m_listUpdating != listUpdating) { |
3614 | + m_listUpdating = listUpdating; |
3615 | + Q_EMIT listUpdatingChanged(); |
3616 | + } |
3617 | +} |
3618 | + |
3619 | +QString TimeZoneLocationModel::filter() const |
3620 | +{ |
3621 | + return m_filter; |
3622 | +} |
3623 | + |
3624 | +void TimeZoneLocationModel::setFilter(const QString &filter) |
3625 | +{ |
3626 | + if (filter != m_filter) { |
3627 | + m_filter = filter; |
3628 | + Q_EMIT filterChanged(); |
3629 | + } |
3630 | + |
3631 | + setListUpdating(true); |
3632 | + |
3633 | + if (m_cancellable) { |
3634 | + g_cancellable_cancel(m_cancellable); |
3635 | + g_clear_object(&m_cancellable); |
3636 | + } |
3637 | + |
3638 | + setModel(QList<GeonamesCity *>()); |
3639 | + |
3640 | + if (filter.isEmpty()) { |
3641 | + setListUpdating(false); |
3642 | + return; |
3643 | + } |
3644 | + |
3645 | + m_cancellable = g_cancellable_new(); |
3646 | + geonames_query_cities(filter.toUtf8().data(), |
3647 | + GEONAMES_QUERY_DEFAULT, |
3648 | + m_cancellable, |
3649 | + filterFinished, |
3650 | + this); |
3651 | +} |
3652 | + |
3653 | +QString TimeZoneLocationModel::country() const |
3654 | +{ |
3655 | + return m_country; |
3656 | +} |
3657 | + |
3658 | +static bool citycmp(GeonamesCity *a, GeonamesCity *b) |
3659 | +{ |
3660 | + return geonames_city_get_population(b) < geonames_city_get_population(a); |
3661 | +} |
3662 | + |
3663 | +void TimeZoneLocationModel::setCountry(const QString &country) |
3664 | +{ |
3665 | + if (m_country == country) |
3666 | + return; |
3667 | + |
3668 | + m_country = country; |
3669 | + |
3670 | + Q_FOREACH(GeonamesCity *city, m_countryLocations) { |
3671 | + geonames_city_free(city); |
3672 | + } |
3673 | + |
3674 | + gint num_cities = geonames_get_n_cities(); |
3675 | + for (gint i = 0; i < num_cities; i++) { |
3676 | + GeonamesCity *city = geonames_get_city(i); |
3677 | + if (city && m_country == geonames_city_get_country_code(city)) { |
3678 | + m_countryLocations.append(city); |
3679 | + } |
3680 | + } |
3681 | + |
3682 | + std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp); |
3683 | + |
3684 | + Q_EMIT countryChanged(country); |
3685 | +} |
3686 | + |
3687 | +TimeZoneLocationModel::~TimeZoneLocationModel() |
3688 | +{ |
3689 | + if (m_cancellable) { |
3690 | + g_cancellable_cancel(m_cancellable); |
3691 | + g_clear_object(&m_cancellable); |
3692 | + } |
3693 | + |
3694 | + Q_FOREACH(GeonamesCity *city, m_countryLocations) { |
3695 | + geonames_city_free(city); |
3696 | + } |
3697 | + |
3698 | + Q_FOREACH(GeonamesCity *city, m_locations) { |
3699 | + geonames_city_free(city); |
3700 | + } |
3701 | +} |
3702 | |
3703 | === added file 'plugins/Wizard/timezonemodel.h' |
3704 | --- plugins/Wizard/timezonemodel.h 1970-01-01 00:00:00 +0000 |
3705 | +++ plugins/Wizard/timezonemodel.h 2016-03-11 18:12:46 +0000 |
3706 | @@ -0,0 +1,80 @@ |
3707 | +/* |
3708 | + * Copyright (C) 2016 Canonical Ltd. |
3709 | + * |
3710 | + * This program is free software: you can redistribute it and/or modify it |
3711 | + * under the terms of the GNU General Public License version 3, as published |
3712 | + * by the Free Software Foundation. |
3713 | + * |
3714 | + * This program is distributed in the hope that it will be useful, but |
3715 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3716 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3717 | + * PURPOSE. See the GNU General Public License for more details. |
3718 | + * |
3719 | + * You should have received a copy of the GNU General Public License along |
3720 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3721 | + */ |
3722 | + |
3723 | +#ifndef TIMEZONEMODEL_H |
3724 | +#define TIMEZONEMODEL_H |
3725 | + |
3726 | +#include <geonames.h> |
3727 | +#include <glib.h> |
3728 | +#include <QAbstractListModel> |
3729 | + |
3730 | +class TimeZoneLocationModel: public QAbstractListModel |
3731 | +{ |
3732 | + Q_OBJECT |
3733 | + Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged) |
3734 | + Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) |
3735 | + Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged) |
3736 | + Q_ENUMS(Roles) |
3737 | + |
3738 | +public: |
3739 | + explicit TimeZoneLocationModel(QObject *parent = nullptr); |
3740 | + ~TimeZoneLocationModel(); |
3741 | + |
3742 | + enum Roles { |
3743 | + TimeZoneRole = Qt::UserRole + 1, |
3744 | + CityRole, |
3745 | + CountryRole, |
3746 | + SimpleRole, |
3747 | + OffsetRole, |
3748 | + LatitudeRole, |
3749 | + LongitudeRole |
3750 | + }; |
3751 | + |
3752 | + int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
3753 | + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
3754 | + QHash<int, QByteArray> roleNames() const override; |
3755 | + |
3756 | + bool listUpdating() const; |
3757 | + |
3758 | + QString filter() const; |
3759 | + void setFilter(const QString &filter); |
3760 | + |
3761 | + QString country() const; |
3762 | + void setCountry(const QString &country); |
3763 | + |
3764 | +Q_SIGNALS: |
3765 | + void listUpdatingChanged(); |
3766 | + void filterChanged(); |
3767 | + void countryChanged(const QString &country); |
3768 | + |
3769 | +private: |
3770 | + void setModel(const QList<GeonamesCity *> &locations); |
3771 | + void setListUpdating(bool listUpdating); |
3772 | + static void filterFinished(GObject *source_object, |
3773 | + GAsyncResult *res, |
3774 | + gpointer user_data); |
3775 | + |
3776 | + |
3777 | + bool m_listUpdating; |
3778 | + QString m_filter; |
3779 | + QString m_country; |
3780 | + GCancellable *m_cancellable; |
3781 | + QHash<int, QByteArray> m_roleNames; |
3782 | + QList<GeonamesCity *> m_locations; |
3783 | + QList<GeonamesCity *> m_countryLocations; |
3784 | +}; |
3785 | + |
3786 | +#endif |
3787 | |
3788 | === modified file 'po/unity8.pot' |
3789 | --- po/unity8.pot 2016-03-08 21:04:17 +0000 |
3790 | +++ po/unity8.pot 2016-03-11 18:12:46 +0000 |
3791 | @@ -8,7 +8,7 @@ |
3792 | msgstr "" |
3793 | "Project-Id-Version: unity8\n" |
3794 | "Report-Msgid-Bugs-To: \n" |
3795 | -"POT-Creation-Date: 2016-03-08 21:04+0000\n" |
3796 | +"POT-Creation-Date: 2016-03-10 22:48+0000\n" |
3797 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
3798 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
3799 | "Language-Team: LANGUAGE <LL@li.org>\n" |
3800 | @@ -22,16 +22,16 @@ |
3801 | msgid "Password: " |
3802 | msgstr "" |
3803 | |
3804 | -#: plugins/Unity/Launcher/launcheritem.cpp:47 |
3805 | -#: plugins/Unity/Launcher/launcheritem.cpp:106 |
3806 | +#: plugins/Unity/Launcher/launcheritem.cpp:48 |
3807 | +#: plugins/Unity/Launcher/launcheritem.cpp:107 |
3808 | msgid "Pin shortcut" |
3809 | msgstr "" |
3810 | |
3811 | -#: plugins/Unity/Launcher/launcheritem.cpp:52 |
3812 | +#: plugins/Unity/Launcher/launcheritem.cpp:53 |
3813 | msgid "Quit" |
3814 | msgstr "" |
3815 | |
3816 | -#: plugins/Unity/Launcher/launcheritem.cpp:106 |
3817 | +#: plugins/Unity/Launcher/launcheritem.cpp:107 |
3818 | msgid "Unpin shortcut" |
3819 | msgstr "" |
3820 | |
3821 | @@ -135,15 +135,15 @@ |
3822 | msgid "Restart" |
3823 | msgstr "" |
3824 | |
3825 | -#: qml/Components/Lockscreen.qml:245 |
3826 | +#: qml/Components/Lockscreen.qml:231 |
3827 | msgid "Return to Call" |
3828 | msgstr "" |
3829 | |
3830 | -#: qml/Components/Lockscreen.qml:245 |
3831 | +#: qml/Components/Lockscreen.qml:231 |
3832 | msgid "Emergency Call" |
3833 | msgstr "" |
3834 | |
3835 | -#: qml/Components/Lockscreen.qml:277 |
3836 | +#: qml/Components/Lockscreen.qml:263 |
3837 | msgid "OK" |
3838 | msgstr "" |
3839 | |
3840 | @@ -152,6 +152,8 @@ |
3841 | msgstr "" |
3842 | |
3843 | #: qml/Components/ModeSwitchWarningDialog.qml:57 |
3844 | +msgctxt "" |
3845 | +"Re-dock means connect the device again to an external screen/mouse/keyboard" |
3846 | msgid "Re-dock, save your work and close these apps to continue." |
3847 | msgstr "" |
3848 | |
3849 | @@ -194,15 +196,15 @@ |
3850 | msgid "Add to Favorites" |
3851 | msgstr "" |
3852 | |
3853 | -#: qml/Dash/GenericScopeView.qml:565 qml/Dash/GenericScopeView.qml:723 |
3854 | +#: qml/Dash/GenericScopeView.qml:567 qml/Dash/GenericScopeView.qml:725 |
3855 | msgid "See less" |
3856 | msgstr "" |
3857 | |
3858 | -#: qml/Dash/GenericScopeView.qml:565 |
3859 | +#: qml/Dash/GenericScopeView.qml:567 |
3860 | msgid "See all" |
3861 | msgstr "" |
3862 | |
3863 | -#: qml/Dash/GenericScopeView.qml:627 |
3864 | +#: qml/Dash/GenericScopeView.qml:629 |
3865 | msgctxt "Label: Hint for dash search line edit" |
3866 | msgid "Search" |
3867 | msgstr "" |
3868 | @@ -228,7 +230,7 @@ |
3869 | msgid "Add a review" |
3870 | msgstr "" |
3871 | |
3872 | -#: qml/Dash/Previews/PreviewSharing.qml:50 |
3873 | +#: qml/Dash/Previews/PreviewSharing.qml:66 |
3874 | msgid "Preview Share Item" |
3875 | msgstr "" |
3876 | |
3877 | @@ -256,13 +258,13 @@ |
3878 | msgid "Also installed" |
3879 | msgstr "" |
3880 | |
3881 | -#: qml/DisabledScreenNotice.qml:87 |
3882 | +#: qml/DisabledScreenNotice.qml:104 |
3883 | msgid "" |
3884 | "Your device is now connected to an external display. Use this screen as a " |
3885 | -"touch pad to interact with the mouse." |
3886 | +"touch pad to interact with the pointer." |
3887 | msgstr "" |
3888 | |
3889 | -#: qml/Greeter/CoverPage.qml:107 |
3890 | +#: qml/Greeter/CoverPage.qml:118 |
3891 | msgid "Unlock" |
3892 | msgstr "" |
3893 | |
3894 | @@ -341,62 +343,62 @@ |
3895 | msgid "Conference" |
3896 | msgstr "" |
3897 | |
3898 | -#: qml/Panel/Indicators/MenuItemFactory.qml:753 |
3899 | +#: qml/Panel/Indicators/MenuItemFactory.qml:752 |
3900 | msgid "Nothing is playing" |
3901 | msgstr "" |
3902 | |
3903 | -#: qml/Panel/Indicators/MenuItemFactory.qml:882 |
3904 | +#: qml/Panel/Indicators/MenuItemFactory.qml:881 |
3905 | #, qt-format |
3906 | msgid "%1 hour" |
3907 | msgid_plural "%1 hours" |
3908 | msgstr[0] "" |
3909 | msgstr[1] "" |
3910 | |
3911 | -#: qml/Panel/Indicators/MenuItemFactory.qml:886 |
3912 | +#: qml/Panel/Indicators/MenuItemFactory.qml:885 |
3913 | #, qt-format |
3914 | msgid "%1 minute" |
3915 | msgid_plural "%1 minutes" |
3916 | msgstr[0] "" |
3917 | msgstr[1] "" |
3918 | |
3919 | -#: qml/Panel/Indicators/MenuItemFactory.qml:891 |
3920 | +#: qml/Panel/Indicators/MenuItemFactory.qml:890 |
3921 | #, qt-format |
3922 | msgid "%1 second" |
3923 | msgid_plural "%1 seconds" |
3924 | msgstr[0] "" |
3925 | msgstr[1] "" |
3926 | |
3927 | -#: qml/Panel/Indicators/MenuItemFactory.qml:894 |
3928 | +#: qml/Panel/Indicators/MenuItemFactory.qml:893 |
3929 | msgid "0 seconds" |
3930 | msgstr "" |
3931 | |
3932 | #. Translators: String like "1 hour, 2 minutes, 3 seconds remaining" |
3933 | -#: qml/Panel/Indicators/MenuItemFactory.qml:896 |
3934 | +#: qml/Panel/Indicators/MenuItemFactory.qml:895 |
3935 | #, qt-format |
3936 | msgid "%1 remaining" |
3937 | msgstr "" |
3938 | |
3939 | -#: qml/Panel/Indicators/MenuItemFactory.qml:902 |
3940 | +#: qml/Panel/Indicators/MenuItemFactory.qml:901 |
3941 | msgid "In queue…" |
3942 | msgstr "" |
3943 | |
3944 | -#: qml/Panel/Indicators/MenuItemFactory.qml:906 |
3945 | +#: qml/Panel/Indicators/MenuItemFactory.qml:905 |
3946 | msgid "Downloading" |
3947 | msgstr "" |
3948 | |
3949 | -#: qml/Panel/Indicators/MenuItemFactory.qml:908 |
3950 | +#: qml/Panel/Indicators/MenuItemFactory.qml:907 |
3951 | msgid "Paused, tap to resume" |
3952 | msgstr "" |
3953 | |
3954 | -#: qml/Panel/Indicators/MenuItemFactory.qml:910 |
3955 | +#: qml/Panel/Indicators/MenuItemFactory.qml:909 |
3956 | msgid "Canceled" |
3957 | msgstr "" |
3958 | |
3959 | -#: qml/Panel/Indicators/MenuItemFactory.qml:912 |
3960 | +#: qml/Panel/Indicators/MenuItemFactory.qml:911 |
3961 | msgid "Finished" |
3962 | msgstr "" |
3963 | |
3964 | -#: qml/Panel/Indicators/MenuItemFactory.qml:914 |
3965 | +#: qml/Panel/Indicators/MenuItemFactory.qml:913 |
3966 | msgid "Failed, tap to retry" |
3967 | msgstr "" |
3968 | |
3969 | |
3970 | === modified file 'qml/Components/EdgeBarrier.qml' |
3971 | --- qml/Components/EdgeBarrier.qml 2015-11-24 17:44:18 +0000 |
3972 | +++ qml/Components/EdgeBarrier.qml 2016-03-11 18:12:46 +0000 |
3973 | @@ -105,7 +105,7 @@ |
3974 | }, |
3975 | Transition { |
3976 | from: "resisting"; to: "passed" |
3977 | - UbuntuNumberAnimation { target: materialContainer; property: "opacity" } |
3978 | + UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration; target: materialContainer; property: "opacity" } |
3979 | } |
3980 | ] |
3981 | } |
3982 | |
3983 | === modified file 'qml/Components/Lockscreen.qml' |
3984 | --- qml/Components/Lockscreen.qml 2015-07-15 15:07:19 +0000 |
3985 | +++ qml/Components/Lockscreen.qml 2016-03-11 18:12:46 +0000 |
3986 | @@ -121,107 +121,93 @@ |
3987 | opacity: root.darkenBackground |
3988 | } |
3989 | |
3990 | - MouseArea { |
3991 | - anchors.fill: root |
3992 | - onClicked: { |
3993 | - if (pinPadLoader.item) |
3994 | - pinPadLoader.item.forceActiveFocus() |
3995 | - } |
3996 | - } |
3997 | - |
3998 | - FocusScope { |
3999 | - id: loaderScope |
4000 | + Loader { |
4001 | + id: pinPadLoader |
4002 | + objectName: "pinPadLoader" |
4003 | anchors.fill: parent |
4004 | - |
4005 | - Loader { |
4006 | - id: pinPadLoader |
4007 | - objectName: "pinPadLoader" |
4008 | - anchors.fill: parent |
4009 | - property bool resetting: false |
4010 | - property bool waiting: false |
4011 | - property bool showWrongText: false |
4012 | - |
4013 | - source: { |
4014 | - if (resetting || !root.required) { |
4015 | - return "" |
4016 | - } else if (root.delayMinutes > 0) { |
4017 | - return "DelayedLockscreen.qml" |
4018 | - } else if (root.alphaNumeric) { |
4019 | - return "PassphraseLockscreen.qml" |
4020 | - } else { |
4021 | - return "PinLockscreen.qml" |
4022 | - } |
4023 | - } |
4024 | - onSourceChanged: { |
4025 | - waiting = false |
4026 | - showWrongText = false |
4027 | - if (loaderScope.activeFocus && pinPadLoader.item) |
4028 | - pinPadLoader.item.forceActiveFocus() |
4029 | - } |
4030 | - |
4031 | - Connections { |
4032 | - target: pinPadLoader.item |
4033 | - |
4034 | - onEntered: { |
4035 | - pinPadLoader.waiting = true |
4036 | - root.entered(passphrase); |
4037 | - } |
4038 | - |
4039 | - onCancel: { |
4040 | - root.cancel() |
4041 | - } |
4042 | - } |
4043 | - |
4044 | - Binding { |
4045 | - target: pinPadLoader.item |
4046 | - property: "minPinLength" |
4047 | - value: root.minPinLength |
4048 | - } |
4049 | - Binding { |
4050 | - target: pinPadLoader.item |
4051 | - property: "maxPinLength" |
4052 | - value: root.maxPinLength |
4053 | - } |
4054 | - Binding { |
4055 | - target: pinPadLoader.item |
4056 | - property: "infoText" |
4057 | - value: root.infoText |
4058 | - } |
4059 | - Binding { |
4060 | - target: pinPadLoader.item |
4061 | - property: "retryText" |
4062 | - value: root.retryText |
4063 | - } |
4064 | - Binding { |
4065 | - target: pinPadLoader.item |
4066 | - property: "errorText" |
4067 | - value: pinPadLoader.showWrongText ? root.errorText : "" |
4068 | - } |
4069 | - Binding { |
4070 | - target: pinPadLoader.item |
4071 | - property: "entryEnabled" |
4072 | - value: !pinPadLoader.waiting |
4073 | - } |
4074 | - Binding { |
4075 | - target: pinPadLoader.item |
4076 | - property: "alphaNumeric" |
4077 | - value: root.alphaNumeric |
4078 | - } |
4079 | - Binding { |
4080 | - target: pinPadLoader.item |
4081 | - property: "delayMinutes" |
4082 | - value: root.delayMinutes |
4083 | - } |
4084 | - Binding { |
4085 | - target: pinPadLoader.item |
4086 | - property: "showCancelButton" |
4087 | - value: root.showCancelButton |
4088 | - } |
4089 | - Binding { |
4090 | - target: pinPadLoader.item |
4091 | - property: "foregroundColor" |
4092 | - value: root.foregroundColor |
4093 | - } |
4094 | + property bool resetting: false |
4095 | + property bool waiting: false |
4096 | + property bool showWrongText: false |
4097 | + focus: true |
4098 | + |
4099 | + source: { |
4100 | + if (resetting || !root.required) { |
4101 | + return "" |
4102 | + } else if (root.delayMinutes > 0) { |
4103 | + return "DelayedLockscreen.qml" |
4104 | + } else if (root.alphaNumeric) { |
4105 | + return "PassphraseLockscreen.qml" |
4106 | + } else { |
4107 | + return "PinLockscreen.qml" |
4108 | + } |
4109 | + } |
4110 | + onSourceChanged: { |
4111 | + waiting = false |
4112 | + showWrongText = false |
4113 | + } |
4114 | + |
4115 | + Connections { |
4116 | + target: pinPadLoader.item |
4117 | + |
4118 | + onEntered: { |
4119 | + pinPadLoader.waiting = true |
4120 | + root.entered(passphrase); |
4121 | + } |
4122 | + |
4123 | + onCancel: { |
4124 | + root.cancel() |
4125 | + } |
4126 | + } |
4127 | + |
4128 | + Binding { |
4129 | + target: pinPadLoader.item |
4130 | + property: "minPinLength" |
4131 | + value: root.minPinLength |
4132 | + } |
4133 | + Binding { |
4134 | + target: pinPadLoader.item |
4135 | + property: "maxPinLength" |
4136 | + value: root.maxPinLength |
4137 | + } |
4138 | + Binding { |
4139 | + target: pinPadLoader.item |
4140 | + property: "infoText" |
4141 | + value: root.infoText |
4142 | + } |
4143 | + Binding { |
4144 | + target: pinPadLoader.item |
4145 | + property: "retryText" |
4146 | + value: root.retryText |
4147 | + } |
4148 | + Binding { |
4149 | + target: pinPadLoader.item |
4150 | + property: "errorText" |
4151 | + value: pinPadLoader.showWrongText ? root.errorText : "" |
4152 | + } |
4153 | + Binding { |
4154 | + target: pinPadLoader.item |
4155 | + property: "entryEnabled" |
4156 | + value: !pinPadLoader.waiting |
4157 | + } |
4158 | + Binding { |
4159 | + target: pinPadLoader.item |
4160 | + property: "alphaNumeric" |
4161 | + value: root.alphaNumeric |
4162 | + } |
4163 | + Binding { |
4164 | + target: pinPadLoader.item |
4165 | + property: "delayMinutes" |
4166 | + value: root.delayMinutes |
4167 | + } |
4168 | + Binding { |
4169 | + target: pinPadLoader.item |
4170 | + property: "showCancelButton" |
4171 | + value: root.showCancelButton |
4172 | + } |
4173 | + Binding { |
4174 | + target: pinPadLoader.item |
4175 | + property: "foregroundColor" |
4176 | + value: root.foregroundColor |
4177 | } |
4178 | } |
4179 | |
4180 | |
4181 | === modified file 'qml/Components/ModeSwitchWarningDialog.qml' |
4182 | --- qml/Components/ModeSwitchWarningDialog.qml 2015-11-25 13:57:34 +0000 |
4183 | +++ qml/Components/ModeSwitchWarningDialog.qml 2016-03-11 18:12:46 +0000 |
4184 | @@ -54,7 +54,7 @@ |
4185 | } |
4186 | |
4187 | Label { |
4188 | - text: i18n.tr("Re-dock, save your work and close these apps to continue.") |
4189 | + text: i18n.ctr("Re-dock means connect the device again to an external screen/mouse/keyboard", "Re-dock, save your work and close these apps to continue.") |
4190 | wrapMode: Text.WordWrap |
4191 | color: "#888888" |
4192 | } |
4193 | |
4194 | === modified file 'qml/Components/PassphraseLockscreen.qml' |
4195 | --- qml/Components/PassphraseLockscreen.qml 2015-07-15 15:07:19 +0000 |
4196 | +++ qml/Components/PassphraseLockscreen.qml 2016-03-11 18:12:46 +0000 |
4197 | @@ -18,10 +18,11 @@ |
4198 | import Ubuntu.Components 1.3 |
4199 | import "../Components" |
4200 | |
4201 | -Item { |
4202 | +FocusScope { |
4203 | id: root |
4204 | y: units.gu(4) |
4205 | height: shakeContainer.height |
4206 | + focus: true |
4207 | |
4208 | property string infoText |
4209 | property string errorText |
4210 | @@ -42,8 +43,6 @@ |
4211 | } |
4212 | } |
4213 | |
4214 | - onActiveFocusChanged: if (activeFocus) pinentryField.forceActiveFocus() |
4215 | - |
4216 | Column { |
4217 | id: shakeContainer |
4218 | anchors.horizontalCenter: parent.horizontalCenter |
4219 | @@ -59,14 +58,16 @@ |
4220 | text: root.infoText |
4221 | } |
4222 | |
4223 | - Item { |
4224 | + FocusScope { |
4225 | id: entryContainer |
4226 | anchors { left: parent.left; right: parent.right; margins: units.gu(2) } |
4227 | height: units.gu(4) |
4228 | + focus: true |
4229 | |
4230 | TextInput { |
4231 | id: pinentryField |
4232 | objectName: "pinentryField" |
4233 | + focus: true |
4234 | |
4235 | property bool incorrectOverride: false |
4236 | |
4237 | |
4238 | === modified file 'qml/Components/PhysicalKeysMapper.qml' |
4239 | --- qml/Components/PhysicalKeysMapper.qml 2016-01-13 18:43:34 +0000 |
4240 | +++ qml/Components/PhysicalKeysMapper.qml 2016-03-11 18:12:46 +0000 |
4241 | @@ -42,12 +42,15 @@ |
4242 | signal screenshotTriggered; |
4243 | |
4244 | readonly property bool altTabPressed: d.altTabPressed |
4245 | + readonly property bool superPressed: d.superPressed |
4246 | + readonly property bool superTabPressed: d.superTabPressed |
4247 | |
4248 | property int powerKeyLongPressTime: 2000 |
4249 | |
4250 | // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the |
4251 | // running desktop, set this to true to use Ctrl+Tab instead. |
4252 | property bool controlInsteadOfAlt: false |
4253 | + property bool controlInsteadOfSuper: false |
4254 | |
4255 | QtObject { |
4256 | id: d |
4257 | @@ -59,6 +62,9 @@ |
4258 | property bool altPressed: false |
4259 | property bool altTabPressed: false |
4260 | |
4261 | + property bool superPressed: false |
4262 | + property bool superTabPressed: false |
4263 | + |
4264 | property var powerButtonPressStart: 0 |
4265 | |
4266 | // We need to eat ALT presses until we know what they're for (Alt+Tab or going to the app?) |
4267 | @@ -119,11 +125,23 @@ |
4268 | event.accepted = true; |
4269 | d.altPressInjected = false; |
4270 | } |
4271 | + |
4272 | + // Adding MetaModifier here because that's what keyboards do. Pressing Super_L actually gives |
4273 | + // Super_L + MetaModifier. This helps to make sure we only invoke superPressed if no other |
4274 | + // Modifier is pressed too. |
4275 | + } else if (((event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R) && event.modifiers === Qt.MetaModifier) |
4276 | + || (root.controlInsteadOfSuper && event.key == Qt.Key_Control) |
4277 | + ) { |
4278 | + d.superPressed = true; |
4279 | } else if (event.key == Qt.Key_Tab) { |
4280 | if (d.altPressed && !d.altTabPressed) { |
4281 | d.altTabPressed = true; |
4282 | event.accepted = true; |
4283 | } |
4284 | + if (d.superPressed && !d.superTabPressed) { |
4285 | + d.superTabPressed = true; |
4286 | + event.accepted = true; |
4287 | + } |
4288 | } |
4289 | } |
4290 | |
4291 | @@ -154,6 +172,12 @@ |
4292 | if (d.altTabPressed) { |
4293 | event.accepted = true; |
4294 | } |
4295 | + } else if (event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)) { |
4296 | + d.superPressed = false; |
4297 | + if (d.superTabPressed) { |
4298 | + d.superTabPressed = false; |
4299 | + event.accepted = true; |
4300 | + } |
4301 | } |
4302 | } |
4303 | } |
4304 | |
4305 | === modified file 'qml/Components/PinLockscreen.qml' |
4306 | --- qml/Components/PinLockscreen.qml 2015-07-15 15:07:19 +0000 |
4307 | +++ qml/Components/PinLockscreen.qml 2016-03-11 18:12:46 +0000 |
4308 | @@ -19,8 +19,9 @@ |
4309 | import Ubuntu.Components.ListItems 1.3 |
4310 | import "../Components" |
4311 | |
4312 | -Item { |
4313 | +FocusScope { |
4314 | id: root |
4315 | + focus: true |
4316 | |
4317 | property string infoText |
4318 | property string retryText |
4319 | @@ -45,6 +46,24 @@ |
4320 | } |
4321 | } |
4322 | |
4323 | + Keys.onPressed: { |
4324 | + if (pinentryField.text.length == root.maxPinLength) |
4325 | + return; |
4326 | + |
4327 | + if (event.key === Qt.Key_Backspace) { |
4328 | + pinentryField.backspace(); |
4329 | + } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Escape) { |
4330 | + closeButton.clicked() |
4331 | + } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { |
4332 | + confirmButton.clicked() |
4333 | + } else { |
4334 | + var digit = parseInt(event.text); |
4335 | + if (!isNaN(digit) && typeof digit == "number") { |
4336 | + pinentryField.appendNumber(digit); |
4337 | + } |
4338 | + } |
4339 | + } |
4340 | + |
4341 | Column { |
4342 | anchors { |
4343 | left: parent.left; |
4344 | @@ -204,6 +223,7 @@ |
4345 | width: numbersGrid.buttonWidth |
4346 | } |
4347 | PinPadButton { |
4348 | + id: closeButton |
4349 | iconName: "close" |
4350 | height: units.gu(5) // visual spec has this row a little closer in |
4351 | width: numbersGrid.buttonWidth |
4352 | @@ -216,6 +236,7 @@ |
4353 | width: numbersGrid.buttonWidth |
4354 | } |
4355 | PinPadButton { |
4356 | + id: confirmButton |
4357 | iconName: "tick" |
4358 | objectName: "confirmButton" |
4359 | height: units.gu(5) |
4360 | |
4361 | === modified file 'qml/Components/ShellDialog.qml' |
4362 | --- qml/Components/ShellDialog.qml 2015-11-06 10:06:58 +0000 |
4363 | +++ qml/Components/ShellDialog.qml 2016-03-11 18:12:46 +0000 |
4364 | @@ -37,7 +37,15 @@ |
4365 | |
4366 | focus: true |
4367 | |
4368 | + // FIXME: this is a hack because Dialog subtheming seems broken atm |
4369 | + // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1555548 |
4370 | + ThemeSettings { |
4371 | + id: themeHack |
4372 | + name: "Ubuntu.Components.Themes.Ambiance" |
4373 | + } |
4374 | + |
4375 | Component.onCompleted: { |
4376 | + __foreground.theme = themeHack |
4377 | show(); |
4378 | } |
4379 | } |
4380 | |
4381 | === modified file 'qml/Dash/CardCarousel.qml' |
4382 | --- qml/Dash/CardCarousel.qml 2016-01-28 14:11:14 +0000 |
4383 | +++ qml/Dash/CardCarousel.qml 2016-03-11 18:12:46 +0000 |
4384 | @@ -66,7 +66,6 @@ |
4385 | item.cardData = Qt.binding(function() { return model; }); |
4386 | item.fontScale = Qt.binding(function() { return carousel.fontScale; }); |
4387 | item.showHeader = Qt.binding(function() { return loader.explicitlyScaled; }); |
4388 | - item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; }); |
4389 | item.artShapeStyle = "shadow"; |
4390 | item.scopeStyle = cardCarousel.scopeStyle; |
4391 | } |
4392 | |
4393 | === modified file 'qml/Dash/CardGrid.qml' |
4394 | --- qml/Dash/CardGrid.qml 2016-02-02 08:47:07 +0000 |
4395 | +++ qml/Dash/CardGrid.qml 2016-03-11 18:12:46 +0000 |
4396 | @@ -70,7 +70,6 @@ |
4397 | item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; }); |
4398 | item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; }); |
4399 | item.cardData = Qt.binding(function() { return model; }); |
4400 | - item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; }); |
4401 | item.scopeStyle = root.scopeStyle; |
4402 | item.artShapeStyle = root.artShapeStyle; |
4403 | item.backgroundShapeStyle = root.backgroundShapeStyle; |
4404 | |
4405 | === modified file 'qml/Dash/CardHorizontalList.qml' |
4406 | --- qml/Dash/CardHorizontalList.qml 2016-01-28 14:11:14 +0000 |
4407 | +++ qml/Dash/CardHorizontalList.qml 2016-03-11 18:12:46 +0000 |
4408 | @@ -53,7 +53,6 @@ |
4409 | item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; }); |
4410 | item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; }); |
4411 | item.cardData = Qt.binding(function() { return model; }); |
4412 | - item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; }); |
4413 | item.scopeStyle = root.scopeStyle; |
4414 | } |
4415 | Connections { |
4416 | |
4417 | === modified file 'qml/Dash/CardTool.qml' |
4418 | --- qml/Dash/CardTool.qml 2016-01-28 14:11:14 +0000 |
4419 | +++ qml/Dash/CardTool.qml 2016-03-11 18:12:46 +0000 |
4420 | @@ -66,7 +66,7 @@ |
4421 | return layout; |
4422 | } |
4423 | |
4424 | - property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components); |
4425 | + property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false); |
4426 | |
4427 | // FIXME: Saviq |
4428 | // Only way for the card below to actually be laid out completely. |
4429 | @@ -139,29 +139,6 @@ |
4430 | readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0 |
4431 | property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0 |
4432 | |
4433 | - /*! |
4434 | - \brief Desired alignment of title |
4435 | - */ |
4436 | - readonly property int titleAlignment: { |
4437 | - if (template["card-layout"] === "horizontal" |
4438 | - || typeof components["title"] !== "object" |
4439 | - || components["title"]["align"] === "left") return Text.AlignLeft; |
4440 | - |
4441 | - var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"]; |
4442 | - |
4443 | - for (var key in keys) { |
4444 | - key = keys[key]; |
4445 | - try { |
4446 | - if (typeof components[key] === "string" |
4447 | - || typeof components[key]["field"] === "string") return Text.AlignLeft; |
4448 | - } catch (e) { |
4449 | - continue; |
4450 | - } |
4451 | - } |
4452 | - |
4453 | - return Text.AlignHCenter; |
4454 | - } |
4455 | - |
4456 | QtObject { |
4457 | id: carouselTool |
4458 | |
4459 | @@ -216,10 +193,9 @@ |
4460 | "summary": "—\n—\n—\n—\n—", |
4461 | "attributes": attributesModel.model |
4462 | } |
4463 | - sourceComponent: cardTool.cardComponent |
4464 | + sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true); |
4465 | onLoaded: { |
4466 | item.objectName = "cardToolCard"; |
4467 | - item.asynchronous = false; |
4468 | item.width = Qt.binding(function() { return cardTool.cardWidth !== -1 ? cardTool.cardWidth : item.implicitWidth; }); |
4469 | item.height = Qt.binding(function() { return cardTool.cardHeight !== -1 ? cardTool.cardHeight : item.implicitHeight; }); |
4470 | } |
4471 | |
4472 | === modified file 'qml/Dash/CardVerticalJournal.qml' |
4473 | --- qml/Dash/CardVerticalJournal.qml 2016-01-28 14:11:14 +0000 |
4474 | +++ qml/Dash/CardVerticalJournal.qml 2016-03-11 18:12:46 +0000 |
4475 | @@ -72,7 +72,6 @@ |
4476 | item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; }); |
4477 | item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; }); |
4478 | item.cardData = Qt.binding(function() { return model; }); |
4479 | - item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; }); |
4480 | item.scopeStyle = root.scopeStyle; |
4481 | } |
4482 | Connections { |
4483 | |
4484 | === modified file 'qml/Dash/Dash.qml' |
4485 | --- qml/Dash/Dash.qml 2015-11-19 16:55:31 +0000 |
4486 | +++ qml/Dash/Dash.qml 2016-03-11 18:12:46 +0000 |
4487 | @@ -37,6 +37,7 @@ |
4488 | } |
4489 | |
4490 | property bool windowActive: window.active |
4491 | + property bool showOverlayScope: false |
4492 | |
4493 | DashCommunicatorService { |
4494 | objectName: "dashCommunicatorService" |
4495 | @@ -80,7 +81,7 @@ |
4496 | return |
4497 | } |
4498 | |
4499 | - closeOverlayScope(); |
4500 | + dash.showOverlayScope = false; |
4501 | |
4502 | dashContent.closePreview(); |
4503 | |
4504 | @@ -93,12 +94,6 @@ |
4505 | dashContent.setCurrentScopeAtIndex(scopeIndex, animate, reset) |
4506 | } |
4507 | |
4508 | - function closeOverlayScope() { |
4509 | - if (dashContent.x != 0) { |
4510 | - dashContent.x = 0; |
4511 | - } |
4512 | - } |
4513 | - |
4514 | Scopes { |
4515 | id: scopes |
4516 | } |
4517 | @@ -133,12 +128,13 @@ |
4518 | height: dash.height |
4519 | scopes: scopes |
4520 | visible: x != -width |
4521 | + x: dash.showOverlayScope ? -width : 0 |
4522 | onGotoScope: { |
4523 | dash.setCurrentScope(scopeId, true, false); |
4524 | } |
4525 | onOpenScope: { |
4526 | scopeItem.scope = scope; |
4527 | - x = -width; |
4528 | + dash.showOverlayScope = true; |
4529 | } |
4530 | Behavior on x { |
4531 | UbuntuNumberAnimation { |
4532 | @@ -207,7 +203,7 @@ |
4533 | bottomEdgeController.enableAnimation = true; |
4534 | bottomEdgeController.progress = 0; |
4535 | scopeItem.scope = scope; |
4536 | - dashContent.x = -dashContent.width; |
4537 | + dash.showOverlayScope = true; |
4538 | } |
4539 | onGotoScope: { |
4540 | bottomEdgeController.enableAnimation = true; |
4541 | @@ -226,7 +222,7 @@ |
4542 | id: scopeItem |
4543 | objectName: "dashTempScopeItem" |
4544 | |
4545 | - x: dashContent.x + width |
4546 | + x: dash.showOverlayScope ? 0 : width |
4547 | y: dashContent.y |
4548 | width: parent.width |
4549 | height: parent.height |
4550 | @@ -234,7 +230,7 @@ |
4551 | hasBackAction: true |
4552 | isCurrent: visible |
4553 | onBackClicked: { |
4554 | - closeOverlayScope(); |
4555 | + dash.showOverlayScope = false; |
4556 | closePreview(); |
4557 | } |
4558 | |
4559 | @@ -250,6 +246,10 @@ |
4560 | scopes.closeScope(oldScope); |
4561 | } |
4562 | } |
4563 | + |
4564 | + Behavior on x { |
4565 | + UbuntuNumberAnimation { } |
4566 | + } |
4567 | } |
4568 | |
4569 | Rectangle { |
4570 | |
4571 | === modified file 'qml/Dash/GenericScopeView.qml' |
4572 | --- qml/Dash/GenericScopeView.qml 2016-02-19 11:50:12 +0000 |
4573 | +++ qml/Dash/GenericScopeView.qml 2016-03-11 18:12:46 +0000 |
4574 | @@ -370,6 +370,8 @@ |
4575 | } else { |
4576 | cardTool.cardWidth = units.gu(10); |
4577 | } |
4578 | + } else { |
4579 | + cardTool.cardWidth = units.gu(12); |
4580 | } |
4581 | item.minimumHorizontalSpacing = item.defaultMinimumHorizontalSpacing; |
4582 | } |
4583 | |
4584 | === modified file 'qml/Dash/Previews/PreviewHeader.qml' |
4585 | --- qml/Dash/Previews/PreviewHeader.qml 2016-01-08 14:19:08 +0000 |
4586 | +++ qml/Dash/Previews/PreviewHeader.qml 2016-03-11 18:12:46 +0000 |
4587 | @@ -25,6 +25,7 @@ |
4588 | * The mascot fall back image comes in widgetData["fallback"] |
4589 | * The subtitle comes in widgetData["subtitle"] |
4590 | * The attributes comes in widgetData["attributes"] |
4591 | + * The emblem comes in widgetData["emblem"] |
4592 | */ |
4593 | |
4594 | PreviewWidget { |
4595 | @@ -40,6 +41,7 @@ |
4596 | readonly property string title: root.widgetData["title"] || "" |
4597 | readonly property string subtitle: root.widgetData["subtitle"] || "" |
4598 | readonly property var attributes: root.widgetData["attributes"] || null |
4599 | + readonly property url emblem: root.widgetData["emblem"] || "" |
4600 | readonly property color fontColor: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText |
4601 | |
4602 | // Rewire the source since we may have unwired it on onStatusChanged |
4603 | @@ -98,16 +100,42 @@ |
4604 | spacing: units.dp(2) |
4605 | anchors.verticalCenter: parent.verticalCenter |
4606 | |
4607 | - Label { |
4608 | - id: titleLabel |
4609 | - objectName: "titleLabel" |
4610 | + Item { |
4611 | anchors { left: parent.left; right: parent.right } |
4612 | - elide: Text.ElideRight |
4613 | - font.weight: Font.Normal |
4614 | - fontSize: "large" |
4615 | - wrapMode: Text.Wrap |
4616 | - color: headerRoot.fontColor |
4617 | - text: headerRoot.title |
4618 | + height: titleLabel.height |
4619 | + |
4620 | + Label { |
4621 | + id: titleLabel |
4622 | + objectName: "titleLabel" |
4623 | + anchors { |
4624 | + left: parent.left; |
4625 | + right: iconLoader.right |
4626 | + rightMargin: iconLoader.width > 0 ? units.gu(0.5) : 0 |
4627 | + } |
4628 | + elide: Text.ElideRight |
4629 | + font.weight: Font.Normal |
4630 | + fontSize: "large" |
4631 | + wrapMode: Text.Wrap |
4632 | + color: headerRoot.fontColor |
4633 | + text: headerRoot.title |
4634 | + } |
4635 | + |
4636 | + Loader { |
4637 | + id: iconLoader |
4638 | + active: headerRoot.emblem != "" |
4639 | + anchors { |
4640 | + bottom: titleLabel.baseline |
4641 | + right: parent.right |
4642 | + } |
4643 | + sourceComponent: Icon { |
4644 | + objectName: "emblemIcon" |
4645 | + source: headerRoot.emblem |
4646 | + color: headerRoot.fontColor |
4647 | + height: source != "" ? titleLabel.font.pixelSize : 0 |
4648 | + // FIXME Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293 |
4649 | + width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth |
4650 | + } |
4651 | + } |
4652 | } |
4653 | |
4654 | Loader { |
4655 | |
4656 | === modified file 'qml/Dash/Previews/PreviewOverlay.qml' |
4657 | --- qml/Dash/Previews/PreviewOverlay.qml 2015-07-15 15:07:19 +0000 |
4658 | +++ qml/Dash/Previews/PreviewOverlay.qml 2016-03-11 18:12:46 +0000 |
4659 | @@ -158,7 +158,7 @@ |
4660 | anchors.centerIn: parent |
4661 | width: units.gu(2.5) |
4662 | height: width |
4663 | - color: theme.palette.normal.foregroundText |
4664 | + color: "white" |
4665 | name: "close" |
4666 | } |
4667 | } |
4668 | |
4669 | === modified file 'qml/Dash/Previews/PreviewSharing.qml' |
4670 | --- qml/Dash/Previews/PreviewSharing.qml 2015-12-17 15:42:39 +0000 |
4671 | +++ qml/Dash/Previews/PreviewSharing.qml 2016-03-11 18:12:46 +0000 |
4672 | @@ -44,6 +44,22 @@ |
4673 | } |
4674 | } |
4675 | |
4676 | + function createExportedItems(url) { |
4677 | + var items = new Array(); |
4678 | + if (typeof url === "string") { |
4679 | + var exportItem = exportItemComponent.createObject(); |
4680 | + exportItem.url = url; |
4681 | + items.push(exportItem); |
4682 | + } else { |
4683 | + for (var i = 0; i < url.length; i++) { |
4684 | + var exportItem = exportItemComponent.createObject(); |
4685 | + exportItem.url = url[i]; |
4686 | + items.push(exportItem); |
4687 | + } |
4688 | + } |
4689 | + return items; |
4690 | + } |
4691 | + |
4692 | Component { |
4693 | id: exportItemComponent |
4694 | ContentItem { |
4695 | @@ -76,13 +92,7 @@ |
4696 | onPeerSelected: { |
4697 | var transfer = peer.request(); |
4698 | if (transfer.state === ContentTransfer.InProgress) { |
4699 | - var items = new Array(); |
4700 | - for (var i = 0; i < url.length; i++) { |
4701 | - var exportItem = exportItemComponent.createObject(); |
4702 | - exportItem.url = url[i]; |
4703 | - items.push(exportItem); |
4704 | - } |
4705 | - transfer.items = items; |
4706 | + transfer.items = createExportedItems(url); |
4707 | transfer.state = ContentTransfer.Charged; |
4708 | } |
4709 | peerPicker.visible = false; |
4710 | |
4711 | === modified file 'qml/Dash/ScopesListCategoryItem.qml' |
4712 | --- qml/Dash/ScopesListCategoryItem.qml 2015-11-04 14:57:13 +0000 |
4713 | +++ qml/Dash/ScopesListCategoryItem.qml 2016-03-11 18:12:46 +0000 |
4714 | @@ -18,7 +18,7 @@ |
4715 | import QtQuick.Layouts 1.1 |
4716 | import Ubuntu.Components 1.3 |
4717 | |
4718 | -MouseArea { |
4719 | +AbstractButton { |
4720 | id: root |
4721 | |
4722 | signal requestFavorite(string scopeId, bool favorite) |
4723 | @@ -84,15 +84,19 @@ |
4724 | visible: text != "" |
4725 | } |
4726 | } |
4727 | - MouseArea { |
4728 | + AbstractButton { |
4729 | id: starArea |
4730 | objectName: "starArea" |
4731 | height: parent.height |
4732 | width: height |
4733 | anchors.right: parent.right |
4734 | onClicked: if (!editMode) root.requestFavorite(model.scopeId, !isFavorite); |
4735 | - onPressed: if (editMode) root.handlePressed(starArea); |
4736 | - onReleased: if (editMode) root.handleReleased(starArea); |
4737 | + onPressedChanged: { |
4738 | + if (editMode) { |
4739 | + if (pressed) root.handlePressed(starArea.__mouseArea); |
4740 | + else root.handleReleased(starArea.__mouseArea); |
4741 | + } |
4742 | + } |
4743 | visible: editMode || showStar |
4744 | Icon { |
4745 | id: star |
4746 | |
4747 | === modified file 'qml/DeviceConfiguration.qml' |
4748 | --- qml/DeviceConfiguration.qml 2015-12-01 13:56:54 +0000 |
4749 | +++ qml/DeviceConfiguration.qml 2016-03-11 18:12:46 +0000 |
4750 | @@ -1,5 +1,5 @@ |
4751 | /* |
4752 | - * Copyright (C) 2015 Canonical, Ltd. |
4753 | + * Copyright (C) 2015-2016 Canonical, Ltd. |
4754 | * |
4755 | * This program is free software; you can redistribute it and/or modify |
4756 | * it under the terms of the GNU General Public License as published by |
4757 | @@ -15,6 +15,7 @@ |
4758 | */ |
4759 | |
4760 | import QtQuick 2.4 |
4761 | +import Utils 0.1 |
4762 | |
4763 | QtObject { |
4764 | id: root |
4765 | @@ -34,57 +35,83 @@ |
4766 | |
4767 | readonly property alias category: priv.category |
4768 | |
4769 | + readonly property var deviceConfigParser: DeviceConfigParser { |
4770 | + name: root.name |
4771 | + } |
4772 | + |
4773 | readonly property var priv: StateGroup { |
4774 | id: priv |
4775 | |
4776 | - property int primaryOrientation: root.useNativeOrientation |
4777 | - |
4778 | - property int supportedOrientations: Qt.PortraitOrientation |
4779 | - | Qt.InvertedPortraitOrientation |
4780 | - | Qt.LandscapeOrientation |
4781 | - | Qt.InvertedLandscapeOrientation |
4782 | - |
4783 | - property int landscapeOrientation: Qt.LandscapeOrientation |
4784 | - property int invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4785 | - property int portraitOrientation: Qt.PortraitOrientation |
4786 | - property int invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4787 | - |
4788 | - // Supported values so far: |
4789 | - // "phone", "tablet" or "desktop" |
4790 | - property string category: "phone" |
4791 | + property int primaryOrientation: deviceConfigParser.primaryOrientation == Qt.PrimaryOrientation ? |
4792 | + root.useNativeOrientation : deviceConfigParser.primaryOrientation |
4793 | + |
4794 | + property int supportedOrientations: deviceConfigParser.supportedOrientations |
4795 | + |
4796 | + property int landscapeOrientation: deviceConfigParser.landscapeOrientation |
4797 | + property int invertedLandscapeOrientation: deviceConfigParser.invertedLandscapeOrientation |
4798 | + property int portraitOrientation: deviceConfigParser.portraitOrientation |
4799 | + property int invertedPortraitOrientation: deviceConfigParser.invertedPortraitOrientation |
4800 | + property string category: deviceConfigParser.category |
4801 | |
4802 | states: [ |
4803 | State { |
4804 | name: "mako" |
4805 | PropertyChanges { |
4806 | target: priv |
4807 | + primaryOrientation: root.useNativeOrientation |
4808 | supportedOrientations: Qt.PortraitOrientation |
4809 | | Qt.LandscapeOrientation |
4810 | | Qt.InvertedLandscapeOrientation |
4811 | + landscapeOrientation: Qt.LandscapeOrientation |
4812 | + invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4813 | + portraitOrientation: Qt.PortraitOrientation |
4814 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4815 | + category: "phone" |
4816 | } |
4817 | }, |
4818 | State { |
4819 | name: "krillin" |
4820 | PropertyChanges { |
4821 | target: priv |
4822 | + primaryOrientation: root.useNativeOrientation |
4823 | supportedOrientations: Qt.PortraitOrientation |
4824 | | Qt.LandscapeOrientation |
4825 | | Qt.InvertedLandscapeOrientation |
4826 | + landscapeOrientation: Qt.LandscapeOrientation |
4827 | + invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4828 | + portraitOrientation: Qt.PortraitOrientation |
4829 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4830 | + category: "phone" |
4831 | } |
4832 | }, |
4833 | State { |
4834 | name: "arale" |
4835 | PropertyChanges { |
4836 | target: priv |
4837 | + primaryOrientation: root.useNativeOrientation |
4838 | supportedOrientations: Qt.PortraitOrientation |
4839 | | Qt.LandscapeOrientation |
4840 | | Qt.InvertedLandscapeOrientation |
4841 | + landscapeOrientation: Qt.LandscapeOrientation |
4842 | + invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4843 | + portraitOrientation: Qt.PortraitOrientation |
4844 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4845 | + category: "phone" |
4846 | } |
4847 | }, |
4848 | State { |
4849 | name: "manta" |
4850 | PropertyChanges { |
4851 | target: priv |
4852 | + primaryOrientation: root.useNativeOrientation |
4853 | + supportedOrientations: Qt.PortraitOrientation |
4854 | + | Qt.InvertedPortraitOrientation |
4855 | + | Qt.LandscapeOrientation |
4856 | + | Qt.InvertedLandscapeOrientation |
4857 | + landscapeOrientation: Qt.LandscapeOrientation |
4858 | + invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4859 | + portraitOrientation: Qt.PortraitOrientation |
4860 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4861 | category: "tablet" |
4862 | } |
4863 | }, |
4864 | @@ -92,9 +119,15 @@ |
4865 | name: "flo" |
4866 | PropertyChanges { |
4867 | target: priv |
4868 | + primaryOrientation: Qt.InvertedLandscapeOrientation |
4869 | + supportedOrientations: Qt.PortraitOrientation |
4870 | + | Qt.InvertedPortraitOrientation |
4871 | + | Qt.LandscapeOrientation |
4872 | + | Qt.InvertedLandscapeOrientation |
4873 | landscapeOrientation: Qt.InvertedLandscapeOrientation |
4874 | invertedLandscapeOrientation: Qt.LandscapeOrientation |
4875 | - primaryOrientation: Qt.InvertedLandscapeOrientation |
4876 | + portraitOrientation: Qt.PortraitOrientation |
4877 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4878 | category: "tablet" |
4879 | } |
4880 | }, |
4881 | @@ -102,8 +135,13 @@ |
4882 | name: "desktop" |
4883 | PropertyChanges { |
4884 | target: priv |
4885 | + primaryOrientation: root.useNativeOrientation |
4886 | + supportedOrientations: root.useNativeOrientation |
4887 | + landscapeOrientation: Qt.LandscapeOrientation |
4888 | + invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation |
4889 | + portraitOrientation: Qt.PortraitOrientation |
4890 | + invertedPortraitOrientation: Qt.InvertedPortraitOrientation |
4891 | category: "desktop" |
4892 | - supportedOrientations: root.useNativeOrientation |
4893 | } |
4894 | } |
4895 | ] |
4896 | |
4897 | === modified file 'qml/DisabledScreenNotice.qml' |
4898 | --- qml/DisabledScreenNotice.qml 2016-01-26 15:29:54 +0000 |
4899 | +++ qml/DisabledScreenNotice.qml 2016-03-11 18:12:46 +0000 |
4900 | @@ -17,6 +17,7 @@ |
4901 | import QtQuick 2.4 |
4902 | import QtQuick.Layouts 1.1 |
4903 | import Ubuntu.Components 1.3 |
4904 | +import Unity.Session 0.1 |
4905 | import QtQuick.Window 2.2 |
4906 | import "Components" |
4907 | |
4908 | @@ -25,19 +26,36 @@ |
4909 | |
4910 | property bool infoNoteDisplayed: true |
4911 | |
4912 | - WallpaperResolver { |
4913 | - width: root.width |
4914 | - id: wallpaperResolver |
4915 | + // For testing |
4916 | + property var screen: Screen |
4917 | + property var orientationLock: OrientationLock |
4918 | + |
4919 | + DeviceConfiguration { |
4920 | + id: deviceConfiguration |
4921 | + name: applicationArguments.deviceName |
4922 | } |
4923 | |
4924 | Item { |
4925 | id: contentContainer |
4926 | + objectName: "contentContainer" |
4927 | anchors.centerIn: parent |
4928 | height: rotation == 90 || rotation == 270 ? parent.width : parent.height |
4929 | width: rotation == 90 || rotation == 270 ? parent.height : parent.width |
4930 | |
4931 | + property int savedOrientation: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation |
4932 | + ? (root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation) |
4933 | + : deviceConfiguration.primaryOrientation |
4934 | + |
4935 | rotation: { |
4936 | - switch (Screen.orientation) { |
4937 | + var usedOrientation = root.screen.orientation; |
4938 | + |
4939 | + if (root.orientationLock.enabled) { |
4940 | + usedOrientation = savedOrientation; |
4941 | + } |
4942 | + |
4943 | + savedOrientation = usedOrientation; |
4944 | + |
4945 | + switch (usedOrientation) { |
4946 | case Qt.PortraitOrientation: |
4947 | return 0; |
4948 | case Qt.LandscapeOrientation: |
4949 | @@ -47,6 +65,8 @@ |
4950 | case Qt.InvertedLandscapeOrientation: |
4951 | return 90; |
4952 | } |
4953 | + |
4954 | + return 0; |
4955 | } |
4956 | transformOrigin: Item.Center |
4957 | |
4958 | @@ -60,9 +80,9 @@ |
4959 | } |
4960 | } |
4961 | |
4962 | - Image { |
4963 | + Rectangle { |
4964 | anchors.fill: parent |
4965 | - source: wallpaperResolver.background |
4966 | + color: "#3b3b3b" |
4967 | } |
4968 | |
4969 | Item { |
4970 | @@ -74,22 +94,26 @@ |
4971 | UbuntuNumberAnimation { } |
4972 | } |
4973 | |
4974 | - Rectangle { |
4975 | - anchors.fill: parent |
4976 | - color: "black" |
4977 | - opacity: 0.4 |
4978 | - } |
4979 | - |
4980 | - Label { |
4981 | - id: text |
4982 | + Column { |
4983 | anchors.centerIn: parent |
4984 | width: parent.width - units.gu(8) |
4985 | - text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the mouse.") |
4986 | - color: "white" |
4987 | - horizontalAlignment: Text.AlignHCenter |
4988 | - verticalAlignment: Text.AlignVCenter |
4989 | - fontSize: "x-large" |
4990 | - wrapMode: Text.Wrap |
4991 | + spacing: units.gu(4) |
4992 | + |
4993 | + Label { |
4994 | + id: text |
4995 | + text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.") |
4996 | + color: "white" |
4997 | + width: parent.width |
4998 | + fontSize: "large" |
4999 | + wrapMode: Text.Wrap |
5000 | + } |
<dandrader> mterry, DDA changes in lp:~mterry/unity8/tutorial-redesign look fine
<mterry> dandrader, awesome, thanks
will quote you in the MP :)
<dandrader> mterry, only unsure about the property name. Because it will work all the same, only difference is that it won't claim ownership over the touch point once it recognizes it's performing a gesture
<mterry> dandrader, yeah. I'm happy to rename it. Got something you like better?
<dandrader> mterry, no :)