Merge lp:~azzar1/unity/devices-cleanup-and-test into lp:unity

Proposed by Andrea Azzarone
Status: Merged
Approved by: Andrea Azzarone
Approved revision: no longer in the source branch.
Merged at revision: 2641
Proposed branch: lp:~azzar1/unity/devices-cleanup-and-test
Merge into: lp:unity
Diff against target: 3673 lines (+2330/-692)
35 files modified
com.canonical.Unity.gschema.xml (+3/-3)
launcher/AbstractVolumeMonitorWrapper.h (+3/-4)
launcher/CMakeLists.txt (+6/-3)
launcher/DeviceLauncherSection.cpp (+23/-27)
launcher/DeviceLauncherSection.h (+17/-7)
launcher/DeviceNotificationDisplay.h (+45/-0)
launcher/DeviceNotificationDisplayImp.cpp (+82/-0)
launcher/DeviceNotificationDisplayImp.h (+46/-0)
launcher/DevicesSettings.h (+26/-48)
launcher/DevicesSettingsImp.cpp (+133/-125)
launcher/DevicesSettingsImp.h (+50/-0)
launcher/FileManagerOpener.h (+45/-0)
launcher/FileManagerOpenerImp.cpp (+35/-0)
launcher/FileManagerOpenerImp.h (+39/-0)
launcher/Launcher.cpp (+12/-2)
launcher/Launcher.h (+5/-0)
launcher/LauncherController.cpp (+6/-4)
launcher/LauncherController.h (+1/-0)
launcher/LauncherControllerPrivate.h (+2/-0)
launcher/Volume.h (+62/-0)
launcher/VolumeImp.cpp (+294/-0)
launcher/VolumeImp.h (+68/-0)
launcher/VolumeLauncherIcon.cpp (+262/-382)
launcher/VolumeLauncherIcon.h (+27/-43)
plugins/unityshell/src/unityshell.cpp (+0/-5)
plugins/unityshell/unityshell.xml.in (+0/-20)
po/POTFILES.in (+2/-1)
tests/CMakeLists.txt (+8/-2)
tests/gmockmount.c (+167/-0)
tests/gmockmount.h (+55/-0)
tests/gmockvolume.c (+120/-13)
tests/gmockvolume.h (+14/-2)
tests/test_device_launcher_section.cpp (+11/-1)
tests/test_volume_imp.cpp (+163/-0)
tests/test_volume_launcher_icon.cpp (+498/-0)
To merge this branch: bzr merge lp:~azzar1/unity/devices-cleanup-and-test
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) Approve
Review via email: mp+119265@code.launchpad.net

Commit message

Refactor device launcher icons.

Description of the change

== Problems ==
#. Unity launcher gets cluttered when having multiple partitions and/or external volumes attached.
#. Devices launcher icons needs test.

== Fix ==
#. DeviceNotificationShower and FileManagerOpener are written rely on SRP and DI.
#. Volume/VolumeImp is a wrapper for GVolume. It makes the VolumeLauncherIcon testable and readable.

== Test ==
#. Unit tests added for VolumeLauncherIcon and VolumeImpl. DeviceLauncherSection already has unit test.
#. I've not added tests for DevicesSettingsImp because Trevinho will remove DevicesSettingsImp in his next branch.

---

Forgive me for the long diff. Refactoring code to make it testable is hard without breaking legacy code.

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> Forgive me for the long diff. Refactoring code to make it testable is hard without breaking legacy code.

There is no need to apologize for this - a large diff that gets code under test and makes it cleaner is better than a short diff that does not include test cases.

235 +class DeviceNotificationShower : private boost::noncopyable
236 +{
237 +public:
238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
239 +

This class can probably be renamed to DeviceNotificationDisplay - the word "Shower" has two meanings in the english langauge and although it was silly of me to confuse one for the other, I did so anyways.

235 +class DeviceNotificationShower : private boost::noncopyable
236 +{
237 +public:
238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
239 +

I'm also not entirely certain about making the interface noncopyable. Generally speaking the object should be noncopyable.

> IconLoader::GetDefault().

Can we remove that singleton?

3019 + g_mock_volume_set_can_eject(gvolume_, TRUE);
3020 + EXPECT_TRUE(volume_->CanBeEjected());

Generally speaking I prefer to operate mocked objects through their interfaces, eg

g_volume_set_can_eject (...); (I assume that you're testing the effect of external GIO code calling set_can_eject through the interface ...).

Also it might be useful for you to hook up your mock implementation of GDrive to a Google Mock directly. That way you can expect that your VolumeLauncherImp is calling the correct function and also determine what the return value is directly within the test code without having to add new api to GMockDrive to set them.

3068 + EXPECT_CALL(*file_manager_opener_, Open("file:///some/directory/testfile"))
3069 + .Times(1);
3070 +
3071 + volume_->MountAndOpenInFileManager();
3072 + EXPECT_TRUE(volume_->IsMounted());

It was a bit confusing as to where: "file:///some/directory/testfile" came from - better make it a constant.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> > Forgive me for the long diff. Refactoring code to make it testable is hard
> without breaking legacy code.
>
> There is no need to apologize for this - a large diff that gets code under
> test and makes it cleaner is better than a short diff that does not include
> test cases.
>
> 235 +class DeviceNotificationShower : private boost::noncopyable
> 236 +{
> 237 +public:
> 238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
> 239 +
>
> This class can probably be renamed to DeviceNotificationDisplay - the word
> "Shower" has two meanings in the english langauge and although it was silly of
> me to confuse one for the other, I did so anyways.

Will do!

>
> 235 +class DeviceNotificationShower : private boost::noncopyable
> 236 +{
> 237 +public:
> 238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
> 239 +
>
> I'm also not entirely certain about making the interface noncopyable.
> Generally speaking the object should be noncopyable.
>

We really don't need to make that object copyable. Also making in un-copyable force us to use it through a pointer.

> > IconLoader::GetDefault().
>

IconLoader is used in dash/hud/launcher/switcher code. I think it's not a good idea to do it in this branch.

> Can we remove that singleton?
>
> 3019 + g_mock_volume_set_can_eject(gvolume_, TRUE);
> 3020 + EXPECT_TRUE(volume_->CanBeEjected());
>
> Generally speaking I prefer to operate mocked objects through their
> interfaces, eg
>
> g_volume_set_can_eject (...); (I assume that you're testing the effect of
> external GIO code calling set_can_eject through the interface ...).

Here I'm testing the VolumeImp mocking GVolumeIface.

>
> Also it might be useful for you to hook up your mock implementation of GDrive
> to a Google Mock directly. That way you can expect that your VolumeLauncherImp
> is calling the correct function and also determine what the return value is
> directly within the test code without having to add new api to GMockDrive to
> set them.
>

Can we mock a GObject using Google Mock?

> 3068 + EXPECT_CALL(*file_manager_opener_,
> Open("file:///some/directory/testfile"))
> 3069 + .Times(1);
> 3070 +
> 3071 + volume_->MountAndOpenInFileManager();
> 3072 + EXPECT_TRUE(volume_->IsMounted());
>
> It was a bit confusing as to where: "file:///some/directory/testfile" came
> from - better make it a constant.

Will fix it.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :
Download full text (3.5 KiB)

> > > Forgive me for the long diff. Refactoring code to make it testable is hard
> > without breaking legacy code.
> >
> > There is no need to apologize for this - a large diff that gets code under
> > test and makes it cleaner is better than a short diff that does not include
> > test cases.
> >
> > 235 +class DeviceNotificationShower : private boost::noncopyable
> > 236 +{
> > 237 +public:
> > 238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
> > 239 +
> >
> > This class can probably be renamed to DeviceNotificationDisplay - the word
> > "Shower" has two meanings in the english langauge and although it was silly
> of
> > me to confuse one for the other, I did so anyways.
>
> Will do!
>
> >
> > 235 +class DeviceNotificationShower : private boost::noncopyable
> > 236 +{
> > 237 +public:
> > 238 + typedef std::shared_ptr<DeviceNotificationShower> Ptr;
> > 239 +
> >
> > I'm also not entirely certain about making the interface noncopyable.
> > Generally speaking the object should be noncopyable.
> >
>
> We really don't need to make that object copyable. Also making in un-copyable
> force us to use it through a pointer.

Right, my point was that you've made the interface itself noncopyable. However there probably isn't much
of a way to prevent copyablility except if we were to do it like that, so that seems okay.

>
> > > IconLoader::GetDefault().
> >
>
> IconLoader is used in dash/hud/launcher/switcher code. I think it's not a good
> idea to do it in this branch.

Sure, just food for thought.

>
> > Can we remove that singleton?
> >
> > 3019 + g_mock_volume_set_can_eject(gvolume_, TRUE);
> > 3020 + EXPECT_TRUE(volume_->CanBeEjected());
> >
> > Generally speaking I prefer to operate mocked objects through their
> > interfaces, eg
> >
> > g_volume_set_can_eject (...); (I assume that you're testing the effect of
> > external GIO code calling set_can_eject through the interface ...).
>
> Here I'm testing the VolumeImp mocking GVolumeIface.

Is VolumeImp providing a C++ wrapper around GVolumeIface ?

I feel like its a bit strange then, if the contents of the underlying GVolume can never be altered except by VolumeImp, that they are being altered in the tests to check the behaviour of VolumeImp.

Wouldn't it be better to alter GVolume through VolumeImp ?

Unless it is that it wraps an /existing/ GVolume, which has can_eject () already set. In this case, it probably makes more ense to implement GMockVolume in terms of google mock.

>
> >
> > Also it might be useful for you to hook up your mock implementation of
> GDrive
> > to a Google Mock directly. That way you can expect that your
> VolumeLauncherImp
> > is calling the correct function and also determine what the return value is
> > directly within the test code without having to add new api to GMockDrive to
> > set them.
> >
>
> Can we mock a GObject using Google Mock?

Yes you can, by making the interface delegate to a google mock.

Have a look at this:

http://bazaar.launchpad.net/~compiz-team/compiz/compiz.gtk-window-decorator-gsettings/view/head:/gtk/window-decorator/tests/compiz_gwd_mock_settings_writable.cpp
>
> > 3068 + EX...

Read more...

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> Is VolumeImp providing a C++ wrapper around GVolumeIface ?

Volume is the interface, VolumeImp is the implementation. Volume doesn't know nothing about GVolume, VolumeImp is a kind of a wrapper. I added unit-test for VolumeImp because it's not a simple wrapper.

> I feel like its a bit strange then, if the contents of the underlying GVolume can never be altered except by VolumeImp, that they are being altered in the tests to check the behaviour of VolumeImp.

> Wouldn't it be better to alter GVolume through VolumeImp ?

We do it in VolumeLauncherIcon, mocking Volume. VolumeLauncherIcon doesn't use VolumeImp...

> Unless it is that it wraps an /existing/ GVolume, which has can_eject () already set. In this case, it probably makes more ense to implement GMockVolume in terms of google mock.

I will study this opportunity. Thank you :)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

There are conflicts with trunk now...

50 - DeviceLauncherIcon.cpp
51 + VolumeLauncherIcon.cpp

Please, keep these in alphabetic order.

2252 void OnRemoved();

Please, make this protected in case you need this for testing.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> There are conflicts with trunk now...
>
> 50 - DeviceLauncherIcon.cpp
> 51 + VolumeLauncherIcon.cpp
>
> Please, keep these in alphabetic order.

Sure, will do?

>
> 2252 void OnRemoved();
>
> Please, make this protected in case you need this for testing.

It needs to be public. Maybe you meant "virtual"?

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Nice, this work good for me... What about renaming IsABlacklistedDevice to IsBlackListedDevice?

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> Nice, this work good for me... What about renaming IsABlacklistedDevice to
> IsBlackListedDevice?

Ok, but I think there is no need to change it if you're going to remove DevicesSettings ;)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Probably I will keep it, since we still need a blacklist for these devices, so for now I'll keep as you wrote it.
Also maybe it's better if you get rid of the "TryTo..." prefix.

Also is this idle still needed:
113 + device_populate_idle_.Run([this] () {
114 PopulateEntries();
115 return false;
116 });

I think it was added to make the launcher controller properly populate the devices, right?
If you confirm this, I'll handle it in another way into my branch.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

> Probably I will keep it, since we still need a blacklist for these devices, so
> for now I'll keep as you wrote it.
> Also maybe it's better if you get rid of the "TryTo..." prefix.

I'd prefer too keep the prefix because adding/removing can fail. When you call TryTo... you're sure that adding/removing are completed successfully when you got the changed signal.

>
> Also is this idle still needed:
> 113 + device_populate_idle_.Run([this] () {
> 114 PopulateEntries();
> 115 return false;
> 116 });
>
> I think it was added to make the launcher controller properly populate the
> devices, right?
> If you confirm this, I'll handle it in another way into my branch.

Yeah you can remove it if it's a problem for you ;)

Revision history for this message
Andrea Azzarone (azzar1) wrote :

I removed the OnRemoved function ;)

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

I like the way you removed OnRemoved, I think this is fine for trunk now.

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1155/console reported an error when processing this lp:~andyrock/unity/devices-cleanup-and-test branch.
Not merging it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'com.canonical.Unity.gschema.xml'
2--- com.canonical.Unity.gschema.xml 2012-07-19 10:13:55 +0000
3+++ com.canonical.Unity.gschema.xml 2012-08-29 08:24:20 +0000
4@@ -42,10 +42,10 @@
5 </key>
6 </schema>
7 <schema path="/com/canonical/unity/devices/" id="com.canonical.Unity.Devices" gettext-domain="unity">
8- <key type="as" name="favorites">
9+ <key type="as" name="blacklist">
10 <default>[]</default>
11- <summary>List of device uuid for favorites on the launcher.</summary>
12- <description>These devices are shown in the Launcher by default.</description>
13+ <summary>List of device uuid blacklist from the launcher.</summary>
14+ <description>These devices are not shown in the launcher by default.</description>
15 </key>
16 </schema>
17 <schema path="/com/canonical/unity/dash/" id="com.canonical.Unity.Dash" gettext-domain="unity">
18
19=== modified file 'launcher/AbstractVolumeMonitorWrapper.h'
20--- launcher/AbstractVolumeMonitorWrapper.h 2012-07-18 22:54:22 +0000
21+++ launcher/AbstractVolumeMonitorWrapper.h 2012-08-29 08:24:20 +0000
22@@ -27,7 +27,6 @@
23 #include <sigc++/trackable.h>
24
25 #include <UnityCore/GLibWrapper.h>
26-#include <UnityCore/GLibSignal.h>
27
28 namespace unity
29 {
30@@ -54,8 +53,8 @@
31 sigc::signal<void, glib::Object<GVolume> const&> volume_removed;
32 };
33
34-} // namespace launcher
35-} // namespace unity
36+}
37+}
38
39-#endif // UNITYSHELL_ABSTRACT_VOLUME_MONITOR_WRAPPER_H
40+#endif
41
42
43=== modified file 'launcher/CMakeLists.txt'
44--- launcher/CMakeLists.txt 2012-07-27 20:20:29 +0000
45+++ launcher/CMakeLists.txt 2012-08-29 08:24:20 +0000
46@@ -37,14 +37,15 @@
47 DNDCollectionWindow.cpp
48 Decaymulator.cpp
49 DesktopLauncherIcon.cpp
50- DeviceLauncherIcon.cpp
51 DeviceLauncherSection.cpp
52- DevicesSettings.cpp
53+ DeviceNotificationDisplayImp.cpp
54+ DevicesSettingsImp.cpp
55 DndData.cpp
56 EdgeBarrierController.cpp
57 FavoriteStore.cpp
58 FavoriteStoreGSettings.cpp
59 FavoriteStorePrivate.cpp
60+ FileManagerOpenerImp.cpp
61 HudLauncherIcon.cpp
62 Launcher.cpp
63 LauncherController.cpp
64@@ -71,6 +72,8 @@
65 SpacerLauncherIcon.cpp
66 Tooltip.cpp
67 TrashLauncherIcon.cpp
68+ VolumeImp.cpp
69+ VolumeLauncherIcon.cpp
70 VolumeMonitorWrapper.cpp
71 )
72
73@@ -87,7 +90,7 @@
74 add_library (switcher-lib STATIC ${SWITCHER_SOURCES})
75 add_dependencies (switcher-lib unity-core-${UNITY_API_VERSION} unity-shared)
76
77-#
78+#
79 # Standalone variant
80 #
81 add_executable (launcher StandaloneLauncher.cpp)
82
83=== modified file 'launcher/DeviceLauncherSection.cpp'
84--- launcher/DeviceLauncherSection.cpp 2012-07-18 17:51:56 +0000
85+++ launcher/DeviceLauncherSection.cpp 2012-08-29 08:24:20 +0000
86@@ -18,19 +18,27 @@
87 */
88
89 #include "DeviceLauncherSection.h"
90+#include "DeviceNotificationDisplayImp.h"
91+#include "DevicesSettings.h"
92+#include "FileManagerOpenerImp.h"
93+#include "VolumeImp.h"
94
95 namespace unity
96 {
97 namespace launcher
98 {
99
100-DeviceLauncherSection::DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr volume_monitor)
101+DeviceLauncherSection::DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr volume_monitor,
102+ DevicesSettings::Ptr devices_settings)
103 : monitor_(volume_monitor)
104+ , devices_settings_(devices_settings)
105+ , file_manager_opener_(new FileManagerOpenerImp)
106+ , device_notification_display_(new DeviceNotificationDisplayImp)
107 {
108 monitor_->volume_added.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeAdded));
109 monitor_->volume_removed.connect(sigc::mem_fun(this, &DeviceLauncherSection::OnVolumeRemoved));
110-
111- device_populate_idle_.Run([&] () {
112+
113+ device_populate_idle_.Run([this] () {
114 PopulateEntries();
115 return false;
116 });
117@@ -39,29 +47,21 @@
118 void DeviceLauncherSection::PopulateEntries()
119 {
120 for (auto volume : monitor_->GetVolumes())
121- {
122- // Sanity check. Avoid duplicates.
123- if (map_.find(volume) != map_.end())
124- continue;
125-
126- DeviceLauncherIcon::Ptr icon(new DeviceLauncherIcon(volume));
127-
128- map_[volume] = icon;
129- IconAdded.emit(icon);
130- }
131+ TryToCreateAndAddIcon(volume);
132 }
133
134-/* Uses a std::map to track all the volume icons shown and not shown.
135- * Keep in mind: when "volume-removed" is recevied we should erase
136- * the pair (GVolume - DeviceLauncherIcon) from the std::map to avoid leaks
137- */
138 void DeviceLauncherSection::OnVolumeAdded(glib::Object<GVolume> const& volume)
139 {
140- // Sanity check. Avoid duplicates.
141+ TryToCreateAndAddIcon(volume);
142+}
143+
144+void DeviceLauncherSection::TryToCreateAndAddIcon(glib::Object<GVolume> volume)
145+{
146 if (map_.find(volume) != map_.end())
147 return;
148
149- DeviceLauncherIcon::Ptr icon(new DeviceLauncherIcon(volume));
150+ VolumeLauncherIcon::Ptr icon(new VolumeLauncherIcon(std::make_shared<VolumeImp>(volume, file_manager_opener_, device_notification_display_),
151+ devices_settings_));
152
153 map_[volume] = icon;
154 IconAdded.emit(icon);
155@@ -73,12 +73,8 @@
156
157 // Sanity check
158 if (volume_it != map_.end())
159- {
160- volume_it->second->OnRemoved();
161 map_.erase(volume_it);
162- }
163-}
164-
165-} // namespace launcher
166-} // namespace unity
167-
168+}
169+
170+}
171+}
172
173=== modified file 'launcher/DeviceLauncherSection.h'
174--- launcher/DeviceLauncherSection.h 2012-07-18 17:51:56 +0000
175+++ launcher/DeviceLauncherSection.h 2012-08-29 08:24:20 +0000
176@@ -17,15 +17,19 @@
177 * Andrea Azzarone <andrea.azzarone@canonical.com>
178 */
179
180-#ifndef _DEVICE_LAUNCHER_SECTION_H_
181-#define _DEVICE_LAUNCHER_SECTION_H_
182+#ifndef UNITYSHELL_DEVICE_LAUNCHER_SECTION_H
183+#define UNITYSHELL_DEVICE_LAUNCHER_SECTION_H
184
185 #include <map>
186+#include <memory>
187
188 #include <UnityCore/GLibSource.h>
189
190-#include "DeviceLauncherIcon.h"
191 #include "AbstractVolumeMonitorWrapper.h"
192+#include "DevicesSettings.h"
193+#include "DeviceNotificationDisplay.h"
194+#include "FileManagerOpener.h"
195+#include "VolumeLauncherIcon.h"
196
197 namespace unity
198 {
199@@ -35,7 +39,8 @@
200 class DeviceLauncherSection : public sigc::trackable
201 {
202 public:
203- DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr volume_monitor);
204+ DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr volume_monitor,
205+ DevicesSettings::Ptr devices_settings);
206
207 sigc::signal<void, AbstractLauncherIcon::Ptr> IconAdded;
208
209@@ -43,13 +48,18 @@
210 void PopulateEntries();
211 void OnVolumeAdded(glib::Object<GVolume> const& volume);
212 void OnVolumeRemoved(glib::Object<GVolume> const& volume);
213+ void TryToCreateAndAddIcon(glib::Object<GVolume> volume);
214
215- std::map<GVolume*, DeviceLauncherIcon::Ptr> map_;
216+ std::map<GVolume*, VolumeLauncherIcon::Ptr> map_;
217 AbstractVolumeMonitorWrapper::Ptr monitor_;
218+ DevicesSettings::Ptr devices_settings_;
219+ FileManagerOpener::Ptr file_manager_opener_;
220+ DeviceNotificationDisplay::Ptr device_notification_display_;
221+
222 glib::Idle device_populate_idle_;
223 };
224
225 }
226-} // namespace unity
227+}
228
229-#endif // _DEVICE_LAUNCHER_SECTION_H_
230+#endif
231
232=== added file 'launcher/DeviceNotificationDisplay.h'
233--- launcher/DeviceNotificationDisplay.h 1970-01-01 00:00:00 +0000
234+++ launcher/DeviceNotificationDisplay.h 2012-08-29 08:24:20 +0000
235@@ -0,0 +1,45 @@
236+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
237+/*
238+ * Copyright (C) 2012 Canonical Ltd
239+ *
240+ * This program is free software: you can redistribute it and/or modify
241+ * it under the terms of the GNU General Public License version 3 as
242+ * published by the Free Software Foundation.
243+ *
244+ * This program is distributed in the hope that it will be useful,
245+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
246+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
247+ * GNU General Public License for more details.
248+ *
249+ * You should have received a copy of the GNU General Public License
250+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
251+ *
252+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
253+ */
254+
255+#ifndef UNITYSHELL_DEVICE_NOTIFICATION_DISPLAY_H
256+#define UNITYSHELL_DEVICE_NOTIFICATION_DISPLAY_H
257+
258+#include <boost/noncopyable.hpp>
259+#include <memory>
260+#include <string>
261+
262+namespace unity
263+{
264+namespace launcher
265+{
266+
267+class DeviceNotificationDisplay : private boost::noncopyable
268+{
269+public:
270+ typedef std::shared_ptr<DeviceNotificationDisplay> Ptr;
271+
272+ virtual ~DeviceNotificationDisplay() {}
273+
274+ virtual void Display(std::string const& icon_name, std::string const& volume_name) = 0;
275+};
276+
277+}
278+}
279+
280+#endif
281
282=== added file 'launcher/DeviceNotificationDisplayImp.cpp'
283--- launcher/DeviceNotificationDisplayImp.cpp 1970-01-01 00:00:00 +0000
284+++ launcher/DeviceNotificationDisplayImp.cpp 2012-08-29 08:24:20 +0000
285@@ -0,0 +1,82 @@
286+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
287+/*
288+ * Copyright (C) 2012 Canonical Ltd
289+ *
290+ * This program is free software: you can redistribute it and/or modify
291+ * it under the terms of the GNU General Public License version 3 as
292+ * published by the Free Software Foundation.
293+ *
294+ * This program is distributed in the hope that it will be useful,
295+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
296+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
297+ * GNU General Public License for more details.
298+ *
299+ * You should have received a copy of the GNU General Public License
300+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
301+ *
302+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
303+ */
304+
305+#include <gdk/gdk.h>
306+#include <glib/gi18n-lib.h>
307+#include <libnotify/notify.h>
308+#include <sigc++/sigc++.h>
309+#include <UnityCore/GLibWrapper.h>
310+
311+#include "DeviceNotificationDisplayImp.h"
312+#include "unity-shared/IconLoader.h"
313+
314+namespace unity
315+{
316+namespace launcher
317+{
318+
319+//
320+// Start private implementation
321+//
322+class DeviceNotificationDisplayImp::Impl
323+{
324+public:
325+ void Show(std::string const& icon_name, std::string const& volume_name)
326+ {
327+ int icon_size = 48;
328+ IconLoader::GetDefault().LoadFromGIconString(icon_name, icon_size,
329+ sigc::bind(sigc::mem_fun(this, &Impl::ShowNotificationWhenIconIsReady), volume_name));
330+ }
331+
332+ void ShowNotificationWhenIconIsReady(std::string const& icon_name,
333+ unsigned size,
334+ glib::Object<GdkPixbuf> const& pixbuf,
335+ std::string const& volume_name)
336+ {
337+ glib::Object<NotifyNotification> notification(notify_notification_new(volume_name.c_str(),
338+ _("The drive has been successfully ejected"),
339+ nullptr));
340+
341+ notify_notification_set_hint(notification, "x-canonical-private-synchronous", g_variant_new_boolean(TRUE));
342+
343+ if (GDK_IS_PIXBUF(pixbuf.RawPtr()))
344+ notify_notification_set_image_from_pixbuf(notification, pixbuf);
345+
346+ notify_notification_show(notification, nullptr);
347+ }
348+};
349+
350+//
351+// End private implementation
352+//
353+
354+DeviceNotificationDisplayImp::DeviceNotificationDisplayImp()
355+ : pimpl(new Impl)
356+{}
357+
358+DeviceNotificationDisplayImp::~DeviceNotificationDisplayImp()
359+{}
360+
361+void DeviceNotificationDisplayImp::Display(std::string const& icon_name, std::string const& volume_name)
362+{
363+ pimpl->Show(icon_name, volume_name);
364+}
365+
366+}
367+}
368
369=== added file 'launcher/DeviceNotificationDisplayImp.h'
370--- launcher/DeviceNotificationDisplayImp.h 1970-01-01 00:00:00 +0000
371+++ launcher/DeviceNotificationDisplayImp.h 2012-08-29 08:24:20 +0000
372@@ -0,0 +1,46 @@
373+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
374+/*
375+ * Copyright (C) 2012 Canonical Ltd
376+ *
377+ * This program is free software: you can redistribute it and/or modify
378+ * it under the terms of the GNU General Public License version 3 as
379+ * published by the Free Software Foundation.
380+ *
381+ * This program is distributed in the hope that it will be useful,
382+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
383+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
384+ * GNU General Public License for more details.
385+ *
386+ * You should have received a copy of the GNU General Public License
387+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
388+ *
389+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
390+ */
391+
392+#ifndef UNITYSHELL_DEVICE_NOTIFICATION_DISPLAY_IMP_H
393+#define UNITYSHELL_DEVICE_NOTIFICATION_DISPLAY_IMP_H
394+
395+#include "DeviceNotificationDisplay.h"
396+
397+namespace unity
398+{
399+namespace launcher
400+{
401+
402+class DeviceNotificationDisplayImp : public DeviceNotificationDisplay
403+{
404+public:
405+ DeviceNotificationDisplayImp();
406+ virtual ~DeviceNotificationDisplayImp();
407+
408+ virtual void Display(std::string const& icon_name, std::string const& volume_name);
409+
410+private:
411+ class Impl;
412+ std::unique_ptr<Impl> pimpl;
413+};
414+
415+}
416+}
417+
418+#endif
419
420=== modified file 'launcher/DevicesSettings.h'
421--- launcher/DevicesSettings.h 2012-05-07 19:52:54 +0000
422+++ launcher/DevicesSettings.h 2012-08-29 08:24:20 +0000
423@@ -1,6 +1,6 @@
424 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
425 /*
426- * Copyright (C) 2010 Canonical Ltd
427+ * Copyright (C) 2010-12 Canonical Ltd
428 *
429 * This program is free software: you can redistribute it and/or modify
430 * it under the terms of the GNU General Public License version 3 as
431@@ -14,61 +14,39 @@
432 * You should have received a copy of the GNU General Public License
433 * along with this program. If not, see <http://www.gnu.org/licenses/>.
434 *
435- * Authored by: Andrea Azzarone <aazzarone@hotmail.it>
436+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
437 */
438
439-#ifndef DEVICES_SETTINGS_H
440-#define DEVICES_SETTINGS_H
441+#ifndef UNITYSHELL_DEVICES_SETTINGS_H
442+#define UNITYSHELL_DEVICES_SETTINGS_H
443
444-#include <list>
445+#include <boost/noncopyable.hpp>
446+#include <memory>
447 #include <string>
448
449-#include <gio/gio.h>
450-#include <boost/utility.hpp>
451-#include <sigc++/sigc++.h>
452-#include <UnityCore/GLibWrapper.h>
453-
454-namespace unity {
455-
456-typedef std::list<std::string> DeviceList;
457-
458-class DevicesSettings : boost::noncopyable
459+#include <sigc++/signal.h>
460+#include <sigc++/trackable.h>
461+
462+namespace unity
463+{
464+namespace launcher
465+{
466+
467+class DevicesSettings : boost::noncopyable, public sigc::trackable
468 {
469 public:
470- typedef enum
471- {
472- NEVER = 0,
473- ONLY_MOUNTED,
474- ALWAYS
475-
476- } DevicesOption;
477-
478- DevicesSettings();
479-
480- static DevicesSettings& GetDefault();
481-
482- void SetDevicesOption(DevicesOption devices_option);
483- DevicesOption GetDevicesOption() { return devices_option_; };
484-
485- DeviceList const& GetFavorites() { return favorites_; };
486- void AddFavorite(std::string const& uuid);
487- void RemoveFavorite(std::string const& uuid);
488-
489- void Changed(std::string const& key);
490-
491- // Signals
492+ typedef std::shared_ptr<DevicesSettings> Ptr;
493+
494+ virtual ~DevicesSettings() {};
495+
496+ virtual bool IsABlacklistedDevice(std::string const& uuid) const = 0;
497+ virtual void TryToBlacklist(std::string const& uuid) = 0;
498+ virtual void TryToUnblacklist(std::string const& uuid) = 0;
499+
500 sigc::signal<void> changed;
501-
502-private:
503- void Refresh();
504- void SaveFavorites(DeviceList const& favorites);
505-
506- glib::Object<GSettings> settings_;
507- DeviceList favorites_;
508- bool ignore_signals_;
509- DevicesOption devices_option_;
510 };
511
512-} // namespace unity
513+}
514+}
515
516-#endif // DEVICES_SETTINGS_H
517+#endif
518
519=== renamed file 'launcher/DevicesSettings.cpp' => 'launcher/DevicesSettingsImp.cpp'
520--- launcher/DevicesSettings.cpp 2012-05-07 19:52:54 +0000
521+++ launcher/DevicesSettingsImp.cpp 2012-08-29 08:24:20 +0000
522@@ -1,6 +1,6 @@
523 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
524 /*
525- * Copyright (C) 2010 Canonical Ltd
526+ * Copyright (C) 2010-12 Canonical Ltd
527 *
528 * This program is free software: you can redistribute it and/or modify
529 * it under the terms of the GNU General Public License version 3 as
530@@ -14,130 +14,138 @@
531 * You should have received a copy of the GNU General Public License
532 * along with this program. If not, see <http://www.gnu.org/licenses/>.
533 *
534- * Authored by: Andrea Azzarone <aazzarone@hotmail.it>
535+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
536 */
537
538-#include "DevicesSettings.h"
539-
540-#include <algorithm>
541-
542-namespace unity {
543-
544-namespace {
545-
546-const char* SETTINGS_NAME = "com.canonical.Unity.Devices";
547-
548-void on_settings_updated(GSettings* settings,
549- const gchar* key,
550- DevicesSettings* self);
551-
552-} // anonymous namespace
553-
554-DevicesSettings& DevicesSettings::GetDefault()
555-{
556- static DevicesSettings instance;
557- return instance;
558-}
559-
560-DevicesSettings::DevicesSettings()
561- : settings_(g_settings_new(SETTINGS_NAME))
562- , ignore_signals_(false)
563- , devices_option_(ONLY_MOUNTED)
564-{
565-
566- g_signal_connect(settings_, "changed", G_CALLBACK(on_settings_updated), this);
567-
568- Refresh();
569-}
570-
571-void DevicesSettings::Refresh()
572-{
573- gchar** favs = g_settings_get_strv(settings_, "favorites");
574-
575- favorites_.clear();
576-
577- for (int i = 0; favs[i] != NULL; i++)
578- favorites_.push_back(favs[i]);
579-
580- g_strfreev(favs);
581-}
582-
583-void DevicesSettings::AddFavorite(std::string const& uuid)
584-{
585- if (uuid.empty())
586- return;
587-
588- favorites_.push_back(uuid);
589-
590- SaveFavorites(favorites_);
591- Refresh();
592-}
593-
594-void DevicesSettings::RemoveFavorite(std::string const& uuid)
595-{
596- if (uuid.empty())
597- return;
598-
599- DeviceList::iterator pos = std::find(favorites_.begin(), favorites_.end(), uuid);
600- if (pos == favorites_.end())
601- return;
602-
603- favorites_.erase(pos);
604- SaveFavorites(favorites_);
605- Refresh();
606-}
607-
608-void DevicesSettings::SaveFavorites(DeviceList const& favorites)
609-{
610- const int size = favorites.size();
611- const char* favs[size + 1];
612- favs[size] = NULL;
613-
614- int index = 0;
615- for (DeviceList::const_iterator i = favorites.begin(), end = favorites.end();
616- i != end; ++i, ++index)
617- {
618- favs[index] = i->c_str();
619- }
620-
621- ignore_signals_ = true;
622- if (!g_settings_set_strv(settings_, "favorites", favs))
623- g_warning("Saving favorites failed.");
624- ignore_signals_ = false;
625-}
626-
627-
628-void DevicesSettings::Changed(std::string const& key)
629-{
630- if (ignore_signals_)
631- return;
632-
633- Refresh();
634-
635- changed.emit();
636-}
637-
638-void DevicesSettings::SetDevicesOption(DevicesOption devices_option)
639-{
640- if (devices_option == devices_option_)
641- return;
642-
643- devices_option_ = devices_option;
644-
645- changed.emit();
646-}
647-
648-namespace {
649-
650-void on_settings_updated(GSettings* settings,
651- const gchar* key,
652- DevicesSettings* self)
653-{
654- if (settings and key) {
655- self->Changed(key);
656- }
657-}
658-
659-} // anonymous namespace
660-
661+#include <list>
662+
663+#include <gio/gio.h>
664+#include <NuxCore/Logger.h>
665+
666+#include "DevicesSettingsImp.h"
667+#include <UnityCore/GLibSignal.h>
668+#include <UnityCore/GLibWrapper.h>
669+
670+namespace unity
671+{
672+namespace launcher
673+{
674+namespace
675+{
676+
677+nux::logging::Logger logger("unity.device.settings");
678+
679+const std::string SETTINGS_NAME = "com.canonical.Unity.Devices";
680+const std::string KEY_NAME = "blacklist";
681+
682+}
683+
684+//
685+// Start private implementation
686+//
687+class DevicesSettingsImp::Impl
688+{
689+public:
690+ Impl(DevicesSettingsImp* parent)
691+ : parent_(parent)
692+ , settings_(g_settings_new(SETTINGS_NAME.c_str()))
693+ {
694+ DownloadBlacklist();
695+ ConnectSignals();
696+ }
697+
698+ void ConnectSignals()
699+ {
700+ settings_changed_signal_.Connect(settings_, "changed::" + KEY_NAME, [this] (GSettings*, gchar*) {
701+ DownloadBlacklist();
702+ parent_->changed.emit();
703+ });
704+ }
705+
706+ void DownloadBlacklist()
707+ {
708+ std::shared_ptr<gchar*> downloaded_blacklist(g_settings_get_strv(settings_, KEY_NAME.c_str()), g_strfreev);
709+
710+ blacklist_.clear();
711+
712+ auto downloaded_blacklist_raw = downloaded_blacklist.get();
713+ for (int i = 0; downloaded_blacklist_raw[i]; ++i)
714+ blacklist_.push_back(downloaded_blacklist_raw[i]);
715+ }
716+
717+ void UploadBlacklist()
718+ {
719+ const int size = blacklist_.size();
720+ const char* blacklist_to_be_uploaded[size+1];
721+
722+ int index = 0;
723+ for (auto item : blacklist_)
724+ blacklist_to_be_uploaded[index++] = item.c_str();
725+ blacklist_to_be_uploaded[index] = nullptr;
726+
727+ if (!g_settings_set_strv(settings_, KEY_NAME.c_str(), blacklist_to_be_uploaded))
728+ {
729+ LOG_WARNING(logger) << "Saving blacklist failed.";
730+ }
731+ }
732+
733+ bool IsABlacklistedDevice(std::string const& uuid) const
734+ {
735+ auto begin = std::begin(blacklist_);
736+ auto end = std::end(blacklist_);
737+ return std::find(begin, end, uuid) != end;
738+ }
739+
740+ void TryToBlacklist(std::string const& uuid)
741+ {
742+ if (uuid.empty() || IsABlacklistedDevice(uuid))
743+ return;
744+
745+ blacklist_.push_back(uuid);
746+ UploadBlacklist();
747+ }
748+
749+ void TryToUnblacklist(std::string const& uuid)
750+ {
751+ if (uuid.empty() || !IsABlacklistedDevice(uuid))
752+ return;
753+
754+ blacklist_.remove(uuid);
755+ UploadBlacklist();
756+ }
757+
758+ DevicesSettingsImp* parent_;
759+ glib::Object<GSettings> settings_;
760+ std::list<std::string> blacklist_;
761+ glib::Signal<void, GSettings*, gchar*> settings_changed_signal_;
762+
763+};
764+
765+//
766+// End private implementation
767+//
768+
769+DevicesSettingsImp::DevicesSettingsImp()
770+ : pimpl(new Impl(this))
771+{}
772+
773+DevicesSettingsImp::~DevicesSettingsImp()
774+{}
775+
776+bool DevicesSettingsImp::IsABlacklistedDevice(std::string const& uuid) const
777+{
778+ return pimpl->IsABlacklistedDevice(uuid);
779+}
780+
781+void DevicesSettingsImp::TryToBlacklist(std::string const& uuid)
782+{
783+ pimpl->TryToBlacklist(uuid);
784+}
785+
786+void DevicesSettingsImp::TryToUnblacklist(std::string const& uuid)
787+{
788+ pimpl->TryToUnblacklist(uuid);
789+}
790+
791+} // namespace launcher
792 } // namespace unity
793
794=== added file 'launcher/DevicesSettingsImp.h'
795--- launcher/DevicesSettingsImp.h 1970-01-01 00:00:00 +0000
796+++ launcher/DevicesSettingsImp.h 2012-08-29 08:24:20 +0000
797@@ -0,0 +1,50 @@
798+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
799+/*
800+ * Copyright (C) 2012 Canonical Ltd
801+ *
802+ * This program is free software: you can redistribute it and/or modify
803+ * it under the terms of the GNU General Public License version 3 as
804+ * published by the Free Software Foundation.
805+ *
806+ * This program is distributed in the hope that it will be useful,
807+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
808+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
809+ * GNU General Public License for more details.
810+ *
811+ * You should have received a copy of the GNU General Public License
812+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
813+ *
814+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
815+ */
816+
817+#ifndef UNITYSHELL_DEVICES_SETTINGS_IMP_H
818+#define UNITYSHELL_DEVICES_SETTINGS_IMP_H
819+
820+#include "DevicesSettings.h"
821+
822+namespace unity
823+{
824+namespace launcher
825+{
826+
827+class DevicesSettingsImp : public DevicesSettings
828+{
829+public:
830+ typedef std::shared_ptr<DevicesSettingsImp> Ptr;
831+
832+ DevicesSettingsImp();
833+ virtual ~DevicesSettingsImp();
834+
835+ virtual bool IsABlacklistedDevice(std::string const& uuid) const;
836+ virtual void TryToBlacklist(std::string const& uuid);
837+ virtual void TryToUnblacklist(std::string const& uuid);
838+
839+private:
840+ class Impl;
841+ std::unique_ptr<Impl> pimpl;
842+};
843+
844+}
845+}
846+
847+#endif
848
849=== added file 'launcher/FileManagerOpener.h'
850--- launcher/FileManagerOpener.h 1970-01-01 00:00:00 +0000
851+++ launcher/FileManagerOpener.h 2012-08-29 08:24:20 +0000
852@@ -0,0 +1,45 @@
853+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
854+/*
855+ * Copyright (C) 2012 Canonical Ltd
856+ *
857+ * This program is free software: you can redistribute it and/or modify
858+ * it under the terms of the GNU General Public License version 3 as
859+ * published by the Free Software Foundation.
860+ *
861+ * This program is distributed in the hope that it will be useful,
862+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
863+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
864+ * GNU General Public License for more details.
865+ *
866+ * You should have received a copy of the GNU General Public License
867+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
868+ *
869+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
870+ */
871+
872+#ifndef UNITYSHELL_FILEMANAGER_OPENER_H
873+#define UNITYSHELL_FILEMANAGER_OPENER_H
874+
875+#include <boost/noncopyable.hpp>
876+#include <memory>
877+#include <string>
878+
879+namespace unity
880+{
881+namespace launcher
882+{
883+
884+class FileManagerOpener : private boost::noncopyable
885+{
886+public:
887+ typedef std::shared_ptr<FileManagerOpener> Ptr;
888+
889+ virtual ~FileManagerOpener() {}
890+
891+ virtual void Open(std::string const& uri) = 0;
892+};
893+
894+}
895+}
896+
897+#endif
898
899=== added file 'launcher/FileManagerOpenerImp.cpp'
900--- launcher/FileManagerOpenerImp.cpp 1970-01-01 00:00:00 +0000
901+++ launcher/FileManagerOpenerImp.cpp 2012-08-29 08:24:20 +0000
902@@ -0,0 +1,35 @@
903+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
904+/*
905+ * Copyright (C) 2012 Canonical Ltd
906+ *
907+ * This program is free software: you can redistribute it and/or modify
908+ * it under the terms of the GNU General Public License version 3 as
909+ * published by the Free Software Foundation.
910+ *
911+ * This program is distributed in the hope that it will be useful,
912+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
913+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
914+ * GNU General Public License for more details.
915+ *
916+ * You should have received a copy of the GNU General Public License
917+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
918+ *
919+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
920+ */
921+
922+#include <gio/gio.h>
923+
924+#include "FileManagerOpenerImp.h"
925+
926+namespace unity
927+{
928+namespace launcher
929+{
930+
931+void FileManagerOpenerImp::Open(std::string const& uri)
932+{
933+ g_app_info_launch_default_for_uri(uri. c_str(), nullptr, nullptr);
934+}
935+
936+}
937+}
938
939=== added file 'launcher/FileManagerOpenerImp.h'
940--- launcher/FileManagerOpenerImp.h 1970-01-01 00:00:00 +0000
941+++ launcher/FileManagerOpenerImp.h 2012-08-29 08:24:20 +0000
942@@ -0,0 +1,39 @@
943+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
944+/*
945+ * Copyright (C) 2012 Canonical Ltd
946+ *
947+ * This program is free software: you can redistribute it and/or modify
948+ * it under the terms of the GNU General Public License version 3 as
949+ * published by the Free Software Foundation.
950+ *
951+ * This program is distributed in the hope that it will be useful,
952+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
953+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
954+ * GNU General Public License for more details.
955+ *
956+ * You should have received a copy of the GNU General Public License
957+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
958+ *
959+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
960+ */
961+
962+#ifndef UNITYSHELL_FILEMANAGER_OPENER_IMP_H
963+#define UNITYSHELL_FILEMANAGER_OPENER_IMP_H
964+
965+#include "FileManagerOpener.h"
966+
967+namespace unity
968+{
969+namespace launcher
970+{
971+
972+class FileManagerOpenerImp : public FileManagerOpener
973+{
974+public:
975+ virtual void Open(std::string const& uri);
976+};
977+
978+}
979+}
980+
981+#endif
982
983=== modified file 'launcher/Launcher.cpp'
984--- launcher/Launcher.cpp 2012-08-21 17:45:42 +0000
985+++ launcher/Launcher.cpp 2012-08-29 08:24:20 +0000
986@@ -1719,6 +1719,11 @@
987 return _model;
988 }
989
990+void Launcher::SetDevicesSettings(DevicesSettings::Ptr devices_settings)
991+{
992+ devices_settings_ = devices_settings;
993+}
994+
995 void Launcher::EnsureIconOnScreen(AbstractLauncherIcon::Ptr selection)
996 {
997 nux::Geometry const& geo = GetGeometry();
998@@ -2581,7 +2586,7 @@
999
1000 for (auto it : _dnd_data.Uris())
1001 {
1002- if (g_str_has_suffix(it.c_str(), ".desktop"))
1003+ if (g_str_has_suffix(it.c_str(), ".desktop") || g_str_has_prefix(it.c_str(), "device://"))
1004 {
1005 _steal_drag = true;
1006 break;
1007@@ -2686,7 +2691,7 @@
1008 // see if the launcher wants this one
1009 for (auto it : _dnd_data.Uris())
1010 {
1011- if (g_str_has_suffix(it.c_str(), ".desktop"))
1012+ if (g_str_has_suffix(it.c_str(), ".desktop") || g_str_has_prefix(it.c_str(), "device://"))
1013 {
1014 _steal_drag = true;
1015 break;
1016@@ -2824,6 +2829,11 @@
1017 g_free(path);
1018 }
1019 }
1020+ else if (devices_settings_ && g_str_has_prefix(it.c_str(), "device://"))
1021+ {
1022+ const gchar* uuid = it.c_str() + 9;
1023+ devices_settings_->TryToUnblacklist(uuid);
1024+ }
1025 }
1026 }
1027 else if (_dnd_hovered_icon && _drag_action != nux::DNDACTION_NONE)
1028
1029=== modified file 'launcher/Launcher.h'
1030--- launcher/Launcher.h 2012-08-21 17:45:42 +0000
1031+++ launcher/Launcher.h 2012-08-29 08:24:20 +0000
1032@@ -30,6 +30,7 @@
1033 #include "PointerBarrier.h"
1034 #include "unity-shared/AbstractIconRenderer.h"
1035 #include "unity-shared/BackgroundEffectHelper.h"
1036+#include "DevicesSettings.h"
1037 #include "DNDCollectionWindow.h"
1038 #include "DndData.h"
1039 #include "EdgeBarrierController.h"
1040@@ -82,6 +83,8 @@
1041 void SetModel(LauncherModel::Ptr model);
1042 LauncherModel::Ptr GetModel() const;
1043
1044+ void SetDevicesSettings(DevicesSettings::Ptr devices_settings);
1045+
1046 void StartKeyShowLauncher();
1047 void EndKeyShowLauncher();
1048
1049@@ -393,6 +396,8 @@
1050 ui::AbstractIconRenderer::Ptr icon_renderer;
1051 BackgroundEffectHelper bg_effect_helper_;
1052
1053+ DevicesSettings::Ptr devices_settings_;
1054+
1055 UBusManager ubus_;
1056 glib::SourceManager sources_;
1057
1058
1059=== modified file 'launcher/LauncherController.cpp'
1060--- launcher/LauncherController.cpp 2012-08-27 03:00:42 +0000
1061+++ launcher/LauncherController.cpp 2012-08-29 08:24:20 +0000
1062@@ -29,7 +29,7 @@
1063 #include "LauncherOptions.h"
1064 #include "BamfLauncherIcon.h"
1065 #include "DesktopLauncherIcon.h"
1066-#include "DeviceLauncherIcon.h"
1067+#include "VolumeLauncherIcon.h"
1068 #include "FavoriteStore.h"
1069 #include "HudLauncherIcon.h"
1070 #include "LauncherController.h"
1071@@ -95,7 +95,8 @@
1072 , model_(new LauncherModel())
1073 , sort_priority_(0)
1074 , volume_monitor_(new VolumeMonitorWrapper)
1075- , device_section_(volume_monitor_)
1076+ , devices_settings_(new DevicesSettingsImp)
1077+ , device_section_(volume_monitor_, devices_settings_)
1078 , show_desktop_icon_(false)
1079 , display_(display)
1080 , matcher_(bamf_matcher_get_default())
1081@@ -267,6 +268,7 @@
1082 launcher->monitor = monitor;
1083 launcher->options = parent_->options();
1084 launcher->SetModel(model_);
1085+ launcher->SetDevicesSettings(devices_settings_);
1086
1087 nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION);
1088 layout->AddView(launcher, 1);
1089@@ -424,10 +426,10 @@
1090 }
1091 case AbstractLauncherIcon::IconType::DEVICE:
1092 {
1093- DeviceLauncherIcon* device_icon = dynamic_cast<DeviceLauncherIcon*>(icon.GetPointer());
1094+ auto device_icon = dynamic_cast<VolumeLauncherIcon*>(icon.GetPointer());
1095
1096 if (device_icon && device_icon->CanEject())
1097- device_icon->Eject();
1098+ device_icon->EjectAndShowNotification();
1099 else if (device_icon && device_icon->CanStop())
1100 device_icon->StopDrive();
1101
1102
1103=== modified file 'launcher/LauncherController.h'
1104--- launcher/LauncherController.h 2012-07-27 19:32:41 +0000
1105+++ launcher/LauncherController.h 2012-08-29 08:24:20 +0000
1106@@ -32,6 +32,7 @@
1107 {
1108 namespace launcher
1109 {
1110+
1111 class AbstractLauncherIcon;
1112 class Launcher;
1113 class LauncherModel;
1114
1115=== modified file 'launcher/LauncherControllerPrivate.h'
1116--- launcher/LauncherControllerPrivate.h 2012-07-25 13:42:41 +0000
1117+++ launcher/LauncherControllerPrivate.h 2012-08-29 08:24:20 +0000
1118@@ -27,6 +27,7 @@
1119
1120 #include "AbstractLauncherIcon.h"
1121 #include "DeviceLauncherSection.h"
1122+#include "DevicesSettingsImp.h"
1123 #include "EdgeBarrierController.h"
1124 #include "LauncherController.h"
1125 #include "Launcher.h"
1126@@ -126,6 +127,7 @@
1127 nux::ObjectPtr<Launcher> keyboard_launcher_;
1128 int sort_priority_;
1129 AbstractVolumeMonitorWrapper::Ptr volume_monitor_;
1130+ DevicesSettingsImp::Ptr devices_settings_;
1131 DeviceLauncherSection device_section_;
1132 LauncherEntryRemoteModel remote_model_;
1133 AbstractLauncherIcon::Ptr expo_icon_;
1134
1135=== added file 'launcher/Volume.h'
1136--- launcher/Volume.h 1970-01-01 00:00:00 +0000
1137+++ launcher/Volume.h 2012-08-29 08:24:20 +0000
1138@@ -0,0 +1,62 @@
1139+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1140+/*
1141+ * Copyright (C) 2012 Canonical Ltd
1142+ *
1143+ * This program is free software: you can redistribute it and/or modify
1144+ * it under the terms of the GNU General Public License version 3 as
1145+ * published by the Free Software Foundation.
1146+ *
1147+ * This program is distributed in the hope that it will be useful,
1148+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1149+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1150+ * GNU General Public License for more details.
1151+ *
1152+ * You should have received a copy of the GNU General Public License
1153+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1154+ *
1155+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1156+ */
1157+
1158+#ifndef UNITYSHELL_VOLUME_H
1159+#define UNITYSHELL_VOLUME_H
1160+
1161+#include <boost/noncopyable.hpp>
1162+#include <memory>
1163+#include <sigc++/signal.h>
1164+#include <sigc++/trackable.h>
1165+#include <string>
1166+
1167+namespace unity
1168+{
1169+namespace launcher
1170+{
1171+
1172+class Volume : private boost::noncopyable, public sigc::trackable
1173+{
1174+public:
1175+ typedef std::shared_ptr<Volume> Ptr;
1176+
1177+ virtual ~Volume() {}
1178+
1179+ virtual bool CanBeEjected() const = 0;
1180+ virtual bool CanBeRemoved() const = 0;
1181+ virtual bool CanBeStopped() const = 0;
1182+ virtual std::string GetName() const = 0;
1183+ virtual std::string GetIconName() const = 0;
1184+ virtual std::string GetIdentifier() const = 0;
1185+ virtual bool HasSiblings() const = 0;
1186+ virtual bool IsMounted() const = 0;
1187+
1188+ virtual void EjectAndShowNotification() = 0;
1189+ virtual void MountAndOpenInFileManager() = 0;
1190+ virtual void StopDrive() = 0;
1191+ virtual void Unmount() = 0;
1192+
1193+ sigc::signal<void> changed;
1194+ sigc::signal<void> removed;
1195+};
1196+
1197+}
1198+}
1199+
1200+#endif
1201
1202=== added file 'launcher/VolumeImp.cpp'
1203--- launcher/VolumeImp.cpp 1970-01-01 00:00:00 +0000
1204+++ launcher/VolumeImp.cpp 2012-08-29 08:24:20 +0000
1205@@ -0,0 +1,294 @@
1206+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1207+/*
1208+ * Copyright (C) 2012 Canonical Ltd
1209+ *
1210+ * This program is free software: you can redistribute it and/or modify
1211+ * it under the terms of the GNU General Public License version 3 as
1212+ * published by the Free Software Foundation.
1213+ *
1214+ * This program is distributed in the hope that it will be useful,
1215+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1216+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1217+ * GNU General Public License for more details.
1218+ *
1219+ * You should have received a copy of the GNU General Public License
1220+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1221+ *
1222+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1223+ */
1224+
1225+#include <gio/gio.h>
1226+#include <gtk/gtk.h>
1227+#include <UnityCore/GLibSignal.h>
1228+
1229+#include "VolumeImp.h"
1230+
1231+namespace unity
1232+{
1233+namespace launcher
1234+{
1235+
1236+//
1237+// Start private implementation
1238+//
1239+
1240+class VolumeImp::Impl
1241+{
1242+public:
1243+ Impl(glib::Object<GVolume> const& volume,
1244+ FileManagerOpener::Ptr const& file_manager_opener,
1245+ DeviceNotificationDisplay::Ptr const& device_notification_display,
1246+ VolumeImp* parent)
1247+ : parent_(parent)
1248+ , cancellable_(g_cancellable_new())
1249+ , volume_(volume)
1250+ , file_manager_opener_(file_manager_opener)
1251+ , device_notification_display_(device_notification_display)
1252+ {
1253+ signal_volume_changed_.Connect(volume_, "changed", [this] (GVolume*) {
1254+ parent_->changed.emit();
1255+ });
1256+
1257+ signal_volume_removed_.Connect(volume_, "removed", [this] (GVolume*) {
1258+ parent_->removed.emit();
1259+ });
1260+ }
1261+
1262+ ~Impl()
1263+ {
1264+ g_cancellable_cancel(cancellable_);
1265+ }
1266+
1267+ bool CanBeEjected() const
1268+ {
1269+ return g_volume_can_eject(volume_) != FALSE;
1270+ }
1271+
1272+ bool CanBeRemoved() const
1273+ {
1274+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
1275+ return drive && g_drive_is_media_removable(drive) != FALSE;
1276+ }
1277+
1278+ bool CanBeStopped() const
1279+ {
1280+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
1281+ return drive && g_drive_can_stop(drive) != FALSE;
1282+ }
1283+
1284+ std::string GetName() const
1285+ {
1286+ return glib::String(g_volume_get_name(volume_)).Str();
1287+ }
1288+
1289+ std::string GetIconName() const
1290+ {
1291+ glib::Object<GIcon> icon(g_volume_get_icon(volume_));
1292+ return glib::String(g_icon_to_string(icon)).Str();
1293+ }
1294+
1295+ std::string GetIdentifier() const
1296+ {
1297+ return glib::String(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID)).Str();
1298+ }
1299+
1300+ bool HasSiblings() const
1301+ {
1302+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
1303+
1304+ if (!drive)
1305+ return false;
1306+
1307+ GList* volumes = g_drive_get_volumes(drive);
1308+ bool has_sibilings = volumes && volumes->next;
1309+
1310+ if (volumes)
1311+ g_list_free_full(volumes, g_object_unref);
1312+
1313+ return has_sibilings;
1314+ }
1315+
1316+ bool IsMounted() const
1317+ {
1318+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
1319+ return static_cast<bool>(mount);
1320+ }
1321+
1322+ void EjectAndShowNotification()
1323+ {
1324+ if (!CanBeEjected())
1325+ return;
1326+
1327+ glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(nullptr));
1328+
1329+ g_volume_eject_with_operation(volume_,
1330+ (GMountUnmountFlags)0,
1331+ mount_op,
1332+ nullptr,
1333+ (GAsyncReadyCallback)OnEjectReady,
1334+ this);
1335+ }
1336+
1337+ static void OnEjectReady(GObject* object, GAsyncResult* result, Impl* self)
1338+ {
1339+ if (g_volume_eject_with_operation_finish(self->volume_, result, nullptr))
1340+ {
1341+ self->device_notification_display_->Display(self->GetIconName(), self->GetName());
1342+ }
1343+ }
1344+
1345+ void MountAndOpenInFileManager()
1346+ {
1347+ if (!IsMounted())
1348+ MountAndOnFinishOpenInFileManager();
1349+ else
1350+ OpenInFileManager();
1351+ }
1352+
1353+ void MountAndOnFinishOpenInFileManager()
1354+ {
1355+ g_volume_mount(volume_,
1356+ (GMountMountFlags) 0,
1357+ nullptr,
1358+ nullptr,
1359+ (GAsyncReadyCallback) &Impl::OnMountFinish,
1360+ this);
1361+ }
1362+
1363+ static void OnMountFinish(GObject* object,
1364+ GAsyncResult* result,
1365+ Impl* self)
1366+ {
1367+ if (g_volume_mount_finish(self->volume_, result, nullptr))
1368+ self->OpenInFileManager();
1369+ }
1370+
1371+ void OpenInFileManager()
1372+ {
1373+ file_manager_opener_->Open(GetUri());
1374+ }
1375+
1376+ std::string GetUri()
1377+ {
1378+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
1379+ glib::Object<GFile> root(g_mount_get_root(mount));
1380+
1381+ if (root.IsType(G_TYPE_FILE))
1382+ return glib::String(g_file_get_uri(root)).Str();
1383+ else
1384+ return std::string();
1385+ }
1386+
1387+ void StopDrive()
1388+ {
1389+ if (!CanBeStopped())
1390+ return;
1391+
1392+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
1393+ glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
1394+
1395+ g_drive_stop(drive,
1396+ (GMountUnmountFlags)0,
1397+ mount_op,
1398+ nullptr, nullptr, nullptr);
1399+ }
1400+
1401+ void Unmount()
1402+ {
1403+ if (!IsMounted())
1404+ return;
1405+
1406+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
1407+ glib::Object<GMountOperation> op(gtk_mount_operation_new(nullptr));
1408+
1409+ g_mount_unmount_with_operation(mount,
1410+ (GMountUnmountFlags)0,
1411+ op,
1412+ nullptr, nullptr, nullptr);
1413+ }
1414+
1415+ VolumeImp* parent_;
1416+ glib::Object<GCancellable> cancellable_;
1417+ glib::Object<GVolume> volume_;
1418+ FileManagerOpener::Ptr file_manager_opener_;
1419+ DeviceNotificationDisplay::Ptr device_notification_display_;
1420+
1421+ glib::Signal<void, GVolume*> signal_volume_changed_;
1422+ glib::Signal<void, GVolume*> signal_volume_removed_;
1423+};
1424+
1425+//
1426+// End private implementation
1427+//
1428+
1429+VolumeImp::VolumeImp(glib::Object<GVolume> const& volume,
1430+ FileManagerOpener::Ptr const& file_manager_opener,
1431+ DeviceNotificationDisplay::Ptr const& device_notification_display)
1432+ : pimpl(new Impl(volume, file_manager_opener, device_notification_display, this))
1433+{}
1434+
1435+VolumeImp::~VolumeImp()
1436+{}
1437+
1438+bool VolumeImp::CanBeEjected() const
1439+{
1440+ return pimpl->CanBeEjected();
1441+}
1442+
1443+bool VolumeImp::CanBeRemoved() const
1444+{
1445+ return pimpl->CanBeRemoved();
1446+}
1447+
1448+bool VolumeImp::CanBeStopped() const
1449+{
1450+ return pimpl->CanBeStopped();
1451+}
1452+
1453+std::string VolumeImp::GetName() const
1454+{
1455+ return pimpl->GetName();
1456+}
1457+
1458+std::string VolumeImp::GetIconName() const
1459+{
1460+ return pimpl->GetIconName();
1461+}
1462+
1463+std::string VolumeImp::GetIdentifier() const
1464+{
1465+ return pimpl->GetIdentifier();
1466+}
1467+
1468+bool VolumeImp::HasSiblings() const
1469+{
1470+ return pimpl->HasSiblings();
1471+}
1472+
1473+bool VolumeImp::IsMounted() const
1474+{
1475+ return pimpl->IsMounted();
1476+}
1477+
1478+void VolumeImp::MountAndOpenInFileManager()
1479+{
1480+ pimpl->MountAndOpenInFileManager();
1481+}
1482+
1483+void VolumeImp::EjectAndShowNotification()
1484+{
1485+ pimpl->EjectAndShowNotification();
1486+}
1487+
1488+void VolumeImp::StopDrive()
1489+{
1490+ pimpl->StopDrive();
1491+}
1492+
1493+void VolumeImp::Unmount()
1494+{
1495+ pimpl->Unmount();
1496+}
1497+
1498+} // namespace launcher
1499+} // namespace unity
1500
1501=== added file 'launcher/VolumeImp.h'
1502--- launcher/VolumeImp.h 1970-01-01 00:00:00 +0000
1503+++ launcher/VolumeImp.h 2012-08-29 08:24:20 +0000
1504@@ -0,0 +1,68 @@
1505+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1506+/*
1507+ * Copyright (C) 2012 Canonical Ltd
1508+ *
1509+ * This program is free software: you can redistribute it and/or modify
1510+ * it under the terms of the GNU General Public License version 3 as
1511+ * published by the Free Software Foundation.
1512+ *
1513+ * This program is distributed in the hope that it will be useful,
1514+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1515+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1516+ * GNU General Public License for more details.
1517+ *
1518+ * You should have received a copy of the GNU General Public License
1519+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1520+ *
1521+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
1522+ */
1523+
1524+#ifndef UNITYSHELL_VOLUME_IMP_H
1525+#define UNITYSHELL_VOLUME_IMP_H
1526+
1527+#include <memory>
1528+
1529+#include <UnityCore/GLibWrapper.h>
1530+
1531+#include "DeviceNotificationDisplay.h"
1532+#include "FileManagerOpener.h"
1533+#include "Volume.h"
1534+
1535+namespace unity
1536+{
1537+namespace launcher
1538+{
1539+
1540+class VolumeImp : public Volume
1541+{
1542+public:
1543+ typedef std::shared_ptr<VolumeImp> Ptr;
1544+
1545+ VolumeImp(glib::Object<GVolume> const& volume,
1546+ FileManagerOpener::Ptr const& file_manager_opener,
1547+ DeviceNotificationDisplay::Ptr const& device_notification_display);
1548+ virtual ~VolumeImp();
1549+
1550+ virtual bool CanBeEjected() const;
1551+ virtual bool CanBeRemoved() const;
1552+ virtual bool CanBeStopped() const;
1553+ virtual std::string GetName() const;
1554+ virtual std::string GetIconName() const;
1555+ virtual std::string GetIdentifier() const;
1556+ virtual bool HasSiblings() const;
1557+ virtual bool IsMounted() const;
1558+
1559+ virtual void EjectAndShowNotification();
1560+ virtual void MountAndOpenInFileManager();
1561+ virtual void StopDrive();
1562+ virtual void Unmount();
1563+
1564+private:
1565+ class Impl;
1566+ std::unique_ptr<Impl> pimpl;
1567+};
1568+
1569+}
1570+}
1571+
1572+#endif
1573
1574=== renamed file 'launcher/DeviceLauncherIcon.cpp' => 'launcher/VolumeLauncherIcon.cpp'
1575--- launcher/DeviceLauncherIcon.cpp 2012-08-21 17:50:55 +0000
1576+++ launcher/VolumeLauncherIcon.cpp 2012-08-29 08:24:20 +0000
1577@@ -15,21 +15,17 @@
1578 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1579 *
1580 * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1581+ * Andrea Azzarone <andrea.azzarone@canonical.com>
1582 */
1583
1584-#include "DeviceLauncherIcon.h"
1585-
1586-#include <algorithm>
1587-#include <list>
1588
1589 #include <glib/gi18n-lib.h>
1590-#include <libnotify/notify.h>
1591 #include <NuxCore/Logger.h>
1592+#include <UnityCore/GLibSignal.h>
1593
1594 #include "DevicesSettings.h"
1595-#include "unity-shared/IconLoader.h"
1596-#include "unity-shared/ubus-server.h"
1597-#include "unity-shared/UBusMessages.h"
1598+#include "Volume.h"
1599+#include "VolumeLauncherIcon.h"
1600
1601 namespace unity
1602 {
1603@@ -44,381 +40,265 @@
1604
1605 }
1606
1607-DeviceLauncherIcon::DeviceLauncherIcon(glib::Object<GVolume> const& volume)
1608+//
1609+// Start private implementation
1610+//
1611+class VolumeLauncherIcon::Impl
1612+{
1613+public:
1614+ typedef glib::Signal<void, DbusmenuMenuitem*, int> ItemSignal;
1615+
1616+ Impl(Volume::Ptr const& volume,
1617+ DevicesSettings::Ptr const& devices_settings,
1618+ VolumeLauncherIcon* parent)
1619+ : parent_(parent)
1620+ , volume_(volume)
1621+ , devices_settings_(devices_settings)
1622+ {
1623+ UpdateIcon();
1624+ UpdateVisibility();
1625+ ConnectSignals();
1626+ }
1627+
1628+ ~Impl()
1629+ {
1630+ volume_changed_conn_.disconnect();
1631+ volume_removed_conn_.disconnect();
1632+ settings_changed_conn_.disconnect();
1633+ }
1634+
1635+ void UpdateIcon()
1636+ {
1637+ parent_->tooltip_text = volume_->GetName();
1638+ parent_->icon_name = volume_->GetIconName();
1639+
1640+ parent_->SetQuirk(Quirk::RUNNING, false);
1641+ }
1642+
1643+ void UpdateVisibility()
1644+ {
1645+ UpdateKeepInLauncher();
1646+ parent_->SetQuirk(Quirk::VISIBLE, keep_in_launcher_);
1647+ }
1648+
1649+ void UpdateKeepInLauncher()
1650+ {
1651+ auto identifier = volume_->GetIdentifier();
1652+ keep_in_launcher_ = !devices_settings_->IsABlacklistedDevice(identifier);
1653+ }
1654+
1655+ void ConnectSignals()
1656+ {
1657+ volume_changed_conn_ = volume_->changed.connect(sigc::mem_fun(this, &Impl::OnVolumeChanged));
1658+ volume_removed_conn_ = volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved));
1659+ settings_changed_conn_ = devices_settings_->changed.connect(sigc::mem_fun(this, &Impl::OnSettingsChanged));
1660+ }
1661+
1662+ void OnVolumeChanged()
1663+ {
1664+ UpdateIcon();
1665+ }
1666+
1667+ void OnVolumeRemoved()
1668+ {
1669+ if (devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier()))
1670+ devices_settings_->TryToUnblacklist(volume_->GetIdentifier());
1671+
1672+ parent_->Remove();
1673+ }
1674+
1675+ void OnSettingsChanged()
1676+ {
1677+ UpdateVisibility();
1678+ }
1679+
1680+ bool CanEject() const
1681+ {
1682+ return volume_->CanBeEjected();
1683+ }
1684+
1685+ void EjectAndShowNotification()
1686+ {
1687+ return volume_->EjectAndShowNotification();
1688+ }
1689+
1690+ bool CanStop() const
1691+ {
1692+ return volume_->CanBeStopped();
1693+ }
1694+
1695+ void StopDrive()
1696+ {
1697+ volume_->StopDrive();
1698+ }
1699+
1700+ void ActivateLauncherIcon(ActionArg arg)
1701+ {
1702+ parent_->SimpleLauncherIcon::ActivateLauncherIcon(arg);
1703+ volume_->MountAndOpenInFileManager();
1704+ }
1705+
1706+ MenuItemsVector GetMenus()
1707+ {
1708+ MenuItemsVector result;
1709+
1710+ AppendUnlockFromLauncherItem(result);
1711+ AppendOpenItem(result);
1712+ AppendEjectItem(result);
1713+ AppendSafelyRemoveItem(result);
1714+ AppendUnmountItem(result);
1715+
1716+ return result;
1717+ }
1718+
1719+ void AppendUnlockFromLauncherItem(MenuItemsVector& menu)
1720+ {
1721+ if (volume_->GetIdentifier().empty())
1722+ return;
1723+
1724+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
1725+
1726+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unlock from Launcher"));
1727+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1728+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1729+
1730+ gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1731+ auto identifier = volume_->GetIdentifier();
1732+ devices_settings_->TryToBlacklist(identifier);
1733+ }));
1734+
1735+ menu.push_back(menu_item);
1736+ }
1737+
1738+ void AppendOpenItem(MenuItemsVector& menu)
1739+ {
1740+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
1741+
1742+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Open"));
1743+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1744+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1745+
1746+ gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1747+ volume_->MountAndOpenInFileManager();
1748+ }));
1749+
1750+ menu.push_back(menu_item);
1751+ }
1752+
1753+ void AppendEjectItem(MenuItemsVector& menu)
1754+ {
1755+ if (!volume_->CanBeEjected())
1756+ return;
1757+
1758+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
1759+
1760+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, volume_->HasSiblings() ? _("Eject parent drive") : _("Eject"));
1761+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1762+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1763+
1764+ gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1765+ volume_->EjectAndShowNotification();
1766+ }));
1767+
1768+ menu.push_back(menu_item);
1769+ }
1770+
1771+ void AppendSafelyRemoveItem(MenuItemsVector& menu)
1772+ {
1773+ if (!volume_->CanBeStopped())
1774+ return;
1775+
1776+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
1777+
1778+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, volume_->HasSiblings() ? _("Safely remove parent drive") : _("Safely remove"));
1779+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1780+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1781+
1782+ gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1783+ volume_->StopDrive();
1784+ }));
1785+
1786+ menu.push_back(menu_item);
1787+ }
1788+
1789+ void AppendUnmountItem(MenuItemsVector& menu)
1790+ {
1791+ if (!volume_->IsMounted() || volume_->CanBeEjected() || volume_->CanBeStopped())
1792+ return;
1793+
1794+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
1795+
1796+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unmount"));
1797+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1798+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1799+
1800+ gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1801+ volume_->Unmount();
1802+ }));
1803+
1804+ menu.push_back(menu_item);
1805+ }
1806+
1807+ VolumeLauncherIcon* parent_;
1808+ bool keep_in_launcher_;
1809+ Volume::Ptr volume_;
1810+ DevicesSettings::Ptr devices_settings_;
1811+
1812+ glib::SignalManager gsignals_;
1813+ sigc::connection settings_changed_conn_;
1814+ sigc::connection volume_changed_conn_;
1815+ sigc::connection volume_removed_conn_;
1816+};
1817+
1818+//
1819+// End private implementation
1820+//
1821+
1822+VolumeLauncherIcon::VolumeLauncherIcon(Volume::Ptr const& volume,
1823+ DevicesSettings::Ptr const& devices_settings)
1824 : SimpleLauncherIcon(IconType::DEVICE)
1825- , volume_(volume)
1826-{
1827- gsignals_.Add<void, GVolume*>(volume, "changed", sigc::mem_fun(this, &DeviceLauncherIcon::OnVolumeChanged));
1828- DevicesSettings::GetDefault().changed.connect(sigc::mem_fun(this, &DeviceLauncherIcon::OnSettingsChanged));
1829-
1830- // Checks if in favorites!
1831- glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
1832- DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
1833- DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
1834-
1835- keep_in_launcher_ = pos != favorites.end();
1836-
1837- UpdateDeviceIcon();
1838- UpdateVisibility();
1839-}
1840-
1841-void DeviceLauncherIcon::OnVolumeChanged(GVolume* volume)
1842-{
1843- if (!G_IS_VOLUME(volume))
1844- return;
1845-
1846- changed_timeout_.reset(new glib::Timeout(volume_changed_timeout, [this]() {
1847- UpdateDeviceIcon();
1848- UpdateVisibility();
1849- return false;
1850- }));
1851-}
1852-
1853-void DeviceLauncherIcon::UpdateVisibility()
1854-{
1855- switch (DevicesSettings::GetDefault().GetDevicesOption())
1856- {
1857- case DevicesSettings::NEVER:
1858- SetQuirk(Quirk::VISIBLE, false);
1859- break;
1860- case DevicesSettings::ONLY_MOUNTED:
1861- if (keep_in_launcher_)
1862- {
1863- SetQuirk(Quirk::VISIBLE, true);
1864- }
1865- else
1866- {
1867- glib::Object<GMount> mount(g_volume_get_mount(volume_));
1868- SetQuirk(Quirk::VISIBLE, mount);
1869- }
1870- break;
1871- case DevicesSettings::ALWAYS:
1872- SetQuirk(Quirk::VISIBLE, true);
1873- break;
1874- }
1875-}
1876-
1877-void DeviceLauncherIcon::UpdateDeviceIcon()
1878-{
1879- name_ = glib::String(g_volume_get_name(volume_)).Str();
1880-
1881- glib::Object<GIcon> icon(g_volume_get_icon(volume_));
1882- glib::String icon_string(g_icon_to_string(icon));
1883-
1884- tooltip_text = name_;
1885- icon_name = icon_string.Str();
1886-
1887- SetQuirk(Quirk::RUNNING, false);
1888-}
1889-
1890-bool
1891-DeviceLauncherIcon::CanEject()
1892-{
1893- return g_volume_can_eject(volume_);
1894-}
1895-
1896-bool
1897-DeviceLauncherIcon::CanStop()
1898-{
1899- return g_drive_can_stop(g_volume_get_drive(volume_));
1900-}
1901-
1902-AbstractLauncherIcon::MenuItemsVector DeviceLauncherIcon::GetMenus()
1903-{
1904- MenuItemsVector result;
1905- glib::Object<DbusmenuMenuitem> menu_item;
1906- glib::Object<GDrive> drive(g_volume_get_drive(volume_));
1907- typedef glib::Signal<void, DbusmenuMenuitem*, int> ItemSignal;
1908-
1909- // "Lock to Launcher"/"Unlock from Launcher" item
1910- if (DevicesSettings::GetDefault().GetDevicesOption() == DevicesSettings::ONLY_MOUNTED
1911- && drive && !g_drive_is_media_removable (drive))
1912- {
1913- menu_item = dbusmenu_menuitem_new();
1914-
1915- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, !keep_in_launcher_ ? _("Lock to Launcher") : _("Unlock from Launcher"));
1916- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1917- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1918-
1919- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
1920- sigc::mem_fun(this, &DeviceLauncherIcon::OnTogglePin)));
1921- result.push_back(menu_item);
1922- }
1923-
1924- // "Open" item
1925- menu_item = dbusmenu_menuitem_new();
1926-
1927- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Open"));
1928- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1929- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1930-
1931- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1932- ActivateLauncherIcon(ActionArg(ActionArg::OTHER, 0));
1933- }));
1934-
1935- result.push_back(menu_item);
1936-
1937- // "Eject" item
1938- if (drive && g_drive_can_eject(drive))
1939- {
1940- menu_item = dbusmenu_menuitem_new();
1941-
1942- GList *list = g_drive_get_volumes(drive);
1943- if (list)
1944- {
1945- if (!list->next) // If the list has only one item
1946- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Eject"));
1947- else
1948- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Eject parent drive"));
1949-
1950- g_list_free_full(list, g_object_unref);
1951- }
1952-
1953- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1954- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1955-
1956- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1957- Eject();
1958- }));
1959-
1960- result.push_back(menu_item);
1961- }
1962-
1963- // "Safely remove" item
1964- if (drive && g_drive_can_stop(drive))
1965- {
1966- menu_item = dbusmenu_menuitem_new();
1967-
1968- GList *list = g_drive_get_volumes(drive);
1969- if (list)
1970- {
1971- if (!list->next) // If the list has only one item
1972- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Safely remove"));
1973- else
1974- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Safely remove parent drive"));
1975-
1976- g_list_free_full(list, g_object_unref);
1977- }
1978-
1979- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
1980- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
1981-
1982- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
1983- StopDrive();
1984- }));
1985-
1986- result.push_back(menu_item);
1987- }
1988-
1989- // "Unmount" item
1990- if (!g_volume_can_eject(volume_)) // Don't need Unmount if can Eject
1991- {
1992- glib::Object<GMount> mount(g_volume_get_mount(volume_));
1993-
1994- if (mount && g_mount_can_unmount(mount))
1995- {
1996- menu_item = dbusmenu_menuitem_new();
1997-
1998- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unmount"));
1999- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2000- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2001-
2002- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2003- Unmount();
2004- }));
2005-
2006- result.push_back(menu_item);
2007- }
2008- }
2009-
2010- return result;
2011-}
2012-
2013-void DeviceLauncherIcon::ShowMount(GMount* mount)
2014-{
2015- if (G_IS_MOUNT(mount))
2016- {
2017- glib::Object<GFile> root(g_mount_get_root(mount));
2018-
2019- if (G_IS_FILE(root.RawPtr()))
2020- {
2021- glib::String uri(g_file_get_uri(root));
2022- glib::Error error;
2023-
2024- g_app_info_launch_default_for_uri(uri.Value(), NULL, &error);
2025-
2026- if (error)
2027- {
2028- LOG_WARNING(logger) << "Cannot open volume '" << name_
2029- << "': Unable to show " << uri
2030- << ": " << error;
2031- }
2032- }
2033- else
2034- {
2035- LOG_WARNING(logger) << "Cannot open volume '" << name_
2036- << "': Mount has no root";
2037- }
2038- }
2039- else
2040- {
2041- LOG_WARNING(logger) << "Cannot open volume '" << name_
2042- << "': Mount-point is invalid";
2043- }
2044-}
2045-
2046-void DeviceLauncherIcon::ActivateLauncherIcon(ActionArg arg)
2047-{
2048- SimpleLauncherIcon::ActivateLauncherIcon(arg);
2049- SetQuirk(Quirk::STARTING, true);
2050-
2051- glib::Object<GMount> mount(g_volume_get_mount(volume_));
2052-
2053- if (G_IS_MOUNT(mount.RawPtr()))
2054- ShowMount(mount);
2055- else
2056- g_volume_mount(volume_,
2057- (GMountMountFlags)0,
2058- NULL,
2059- NULL,
2060- (GAsyncReadyCallback)&DeviceLauncherIcon::OnMountReady,
2061- this);
2062-}
2063-
2064-void DeviceLauncherIcon::OnMountReady(GObject* object,
2065- GAsyncResult* result,
2066- DeviceLauncherIcon* self)
2067-{
2068- glib::Error error;
2069-
2070- if (g_volume_mount_finish(self->volume_, result, &error))
2071- {
2072- glib::Object<GMount> mount(g_volume_get_mount(self->volume_));
2073- self->ShowMount(mount);
2074- }
2075- else
2076- {
2077- LOG_WARNING(logger) << "Cannot open volume '" << self->name_ << "' : " <<
2078- (error ? error.Message() : "Mount operation failed");
2079- }
2080-}
2081-
2082-void DeviceLauncherIcon::OnEjectReady(GObject* object,
2083- GAsyncResult* result,
2084- DeviceLauncherIcon* self)
2085-{
2086- if (g_volume_eject_with_operation_finish(self->volume_, result, NULL))
2087- {
2088- IconLoader::GetDefault().LoadFromGIconString(self->icon_name(), 48,
2089- sigc::bind(sigc::mem_fun(self, &DeviceLauncherIcon::ShowNotification), self->name_));
2090- }
2091-}
2092-
2093-void DeviceLauncherIcon::ShowNotification(std::string const& icon_name,
2094- unsigned size,
2095- glib::Object<GdkPixbuf> const& pixbuf,
2096- std::string const& name)
2097-{
2098- glib::Object<NotifyNotification> notification(notify_notification_new(name.c_str(),
2099- _("The drive has been successfully ejected"),
2100- NULL));
2101-
2102- notify_notification_set_hint(notification,
2103- "x-canonical-private-synchronous",
2104- g_variant_new_boolean(TRUE));
2105-
2106- if (GDK_IS_PIXBUF(pixbuf.RawPtr()))
2107- notify_notification_set_image_from_pixbuf(notification, pixbuf);
2108-
2109- notify_notification_show(notification, NULL);
2110-}
2111-
2112-void DeviceLauncherIcon::Eject()
2113-{
2114- glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
2115-
2116- g_volume_eject_with_operation(volume_,
2117- (GMountUnmountFlags)0,
2118- mount_op,
2119- NULL,
2120- (GAsyncReadyCallback)OnEjectReady,
2121- this);
2122-}
2123-
2124-void DeviceLauncherIcon::OnTogglePin(DbusmenuMenuitem* item, int time)
2125-{
2126- glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
2127-
2128- keep_in_launcher_ = !keep_in_launcher_;
2129-
2130- if (!keep_in_launcher_)
2131- {
2132- // If the volume is not mounted hide the icon
2133- glib::Object<GMount> mount(g_volume_get_mount(volume_));
2134-
2135- if (!mount)
2136- SetQuirk(Quirk::VISIBLE, false);
2137-
2138- // Remove from favorites
2139- if (!uuid.Str().empty())
2140- DevicesSettings::GetDefault().RemoveFavorite(uuid.Str());
2141- }
2142- else
2143- {
2144- if (!uuid.Str().empty())
2145- DevicesSettings::GetDefault().AddFavorite(uuid.Str());
2146- }
2147-}
2148-
2149-void DeviceLauncherIcon::OnUnmountReady(GObject* object,
2150- GAsyncResult* result,
2151- DeviceLauncherIcon* self)
2152-{
2153- if (G_IS_MOUNT(object))
2154- g_mount_unmount_with_operation_finish(G_MOUNT(object), result, NULL);
2155-}
2156-
2157-void DeviceLauncherIcon::Unmount()
2158-{
2159- glib::Object<GMount> mount(g_volume_get_mount(volume_));
2160-
2161- if (mount)
2162- {
2163- glib::Object<GMountOperation> op(gtk_mount_operation_new(NULL));
2164-
2165- g_mount_unmount_with_operation(mount, (GMountUnmountFlags)0, op, NULL,
2166- (GAsyncReadyCallback)OnUnmountReady, this);
2167- }
2168-}
2169-
2170-void DeviceLauncherIcon::OnRemoved()
2171-{
2172- Remove();
2173-}
2174-
2175-void DeviceLauncherIcon::StopDrive()
2176-{
2177- glib::Object<GDrive> drive(g_volume_get_drive(volume_));
2178- glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
2179-
2180- g_drive_stop(drive, (GMountUnmountFlags)0, mount_op, NULL, NULL, NULL);
2181-}
2182-
2183-void DeviceLauncherIcon::OnSettingsChanged()
2184-{
2185- // Checks if in favourites!
2186- glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
2187- DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
2188- DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
2189-
2190- keep_in_launcher_ = pos != favorites.end();
2191-
2192- UpdateVisibility();
2193-}
2194-
2195-std::string DeviceLauncherIcon::GetName() const
2196-{
2197- return "DeviceLauncherIcon";
2198+ , pimpl_(new Impl(volume, devices_settings, this))
2199+{}
2200+
2201+VolumeLauncherIcon::~VolumeLauncherIcon()
2202+{}
2203+
2204+bool VolumeLauncherIcon::CanEject() const
2205+{
2206+ return pimpl_->CanEject();
2207+}
2208+
2209+void VolumeLauncherIcon::EjectAndShowNotification()
2210+{
2211+ pimpl_->EjectAndShowNotification();
2212+}
2213+
2214+bool VolumeLauncherIcon::CanStop() const
2215+{
2216+ return pimpl_->CanStop();
2217+}
2218+
2219+void VolumeLauncherIcon::StopDrive()
2220+{
2221+ return pimpl_->StopDrive();
2222+}
2223+
2224+void VolumeLauncherIcon::ActivateLauncherIcon(ActionArg arg)
2225+{
2226+ pimpl_->ActivateLauncherIcon(arg);
2227+}
2228+
2229+AbstractLauncherIcon::MenuItemsVector VolumeLauncherIcon::GetMenus()
2230+{
2231+ return pimpl_->GetMenus();
2232+}
2233+
2234+//
2235+// Introspection
2236+//
2237+std::string VolumeLauncherIcon::GetName() const
2238+{
2239+ return "VolumeLauncherIcon";
2240 }
2241
2242 } // namespace launcher
2243
2244=== renamed file 'launcher/DeviceLauncherIcon.h' => 'launcher/VolumeLauncherIcon.h'
2245--- launcher/DeviceLauncherIcon.h 2012-08-21 17:59:29 +0000
2246+++ launcher/VolumeLauncherIcon.h 2012-08-29 08:24:20 +0000
2247@@ -15,15 +15,14 @@
2248 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2249 *
2250 * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2251+ * Andrea Azzarone <andrea.azzarone@canonical.com>
2252 */
2253
2254-#ifndef _DEVICE_LAUNCHER_ICON_H__H
2255-#define _DEVICE_LAUNCHER_ICON_H__H
2256-
2257-#include <gio/gio.h>
2258-#include <UnityCore/GLibWrapper.h>
2259-#include <UnityCore/GLibSignal.h>
2260-
2261+#ifndef UNITYSHELL_VOLUME_LAUNCHER_ICON_H
2262+#define UNITYSHELL_VOLUME_LAUNCHER_ICON_H
2263+
2264+#include "Volume.h"
2265+#include "DevicesSettings.h"
2266 #include "SimpleLauncherIcon.h"
2267
2268 namespace unity
2269@@ -31,48 +30,33 @@
2270 namespace launcher
2271 {
2272
2273-class DeviceLauncherIcon : public SimpleLauncherIcon
2274+class VolumeLauncherIcon : public SimpleLauncherIcon
2275 {
2276 public:
2277- typedef nux::ObjectPtr<DeviceLauncherIcon> Ptr;
2278-
2279- DeviceLauncherIcon(glib::Object<GVolume> const& volume);
2280-
2281- void OnRemoved();
2282- bool CanEject();
2283- bool CanStop();
2284- void Eject();
2285+ typedef nux::ObjectPtr<VolumeLauncherIcon> Ptr;
2286+
2287+ VolumeLauncherIcon(Volume::Ptr const& volume,
2288+ DevicesSettings::Ptr const& devices_settings);
2289+ virtual ~VolumeLauncherIcon();
2290+
2291+ bool CanEject() const; // TODO: rename to public virtual bool IsTrashable();
2292+ void EjectAndShowNotification(); // TODO: rename to private virtual void DoDropToTrash();
2293+ bool CanStop() const;
2294 void StopDrive();
2295+ MenuItemsVector GetMenus();
2296
2297 protected:
2298- MenuItemsVector GetMenus();
2299- std::string GetName() const;
2300-
2301-private:
2302- void UpdateVisibility();
2303- void UpdateDeviceIcon();
2304- void ActivateLauncherIcon(ActionArg arg);
2305- void ShowMount(GMount* mount);
2306- void Unmount();
2307- void OnTogglePin(DbusmenuMenuitem* item, int time);
2308- void OnSettingsChanged();
2309- void ShowNotification(std::string const&, unsigned, glib::Object<GdkPixbuf> const&, std::string const&);
2310- void OnVolumeChanged(GVolume* volume);
2311- static void OnChanged(GVolume* volume, DeviceLauncherIcon* self);
2312- static void OnMountReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
2313- static void OnEjectReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
2314- static void OnUnmountReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
2315-
2316-private:
2317- glib::Source::UniquePtr changed_timeout_;
2318- glib::Object<GVolume> volume_;
2319- glib::SignalManager gsignals_;
2320-
2321- std::string name_;
2322- bool keep_in_launcher_;
2323+ virtual void ActivateLauncherIcon(ActionArg arg);
2324+
2325+ // Introspection
2326+ virtual std::string GetName() const;
2327+
2328+private:
2329+ class Impl;
2330+ std::shared_ptr<Impl> pimpl_;
2331 };
2332
2333 }
2334-} // namespace unity
2335+}
2336
2337-#endif // _DEVICE_LAUNCHER_ICON_H__H
2338+#endif
2339
2340=== modified file 'plugins/unityshell/src/unityshell.cpp'
2341--- plugins/unityshell/src/unityshell.cpp 2012-08-27 19:08:38 +0000
2342+++ plugins/unityshell/src/unityshell.cpp 2012-08-29 08:24:20 +0000
2343@@ -29,7 +29,6 @@
2344 #include "Launcher.h"
2345 #include "LauncherIcon.h"
2346 #include "LauncherController.h"
2347-#include "DevicesSettings.h"
2348 #include "PluginAdapter.h"
2349 #include "QuicklistManager.h"
2350 #include "StartupNotifyService.h"
2351@@ -281,7 +280,6 @@
2352 optionSetIconSizeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2353 optionSetAutohideAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2354 optionSetDashBlurExperimentalNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2355- optionSetDevicesOptionNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2356 optionSetShortcutOverlayNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2357 optionSetShowDesktopIconNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
2358 optionSetShowLauncherInitiate(boost::bind(&UnityScreen::showLauncherKeyInitiate, this, _1, _2, _3));
2359@@ -2925,9 +2923,6 @@
2360 case UnityshellOptions::AutomaximizeValue:
2361 PluginAdapter::Default()->SetCoverageAreaBeforeAutomaximize(optionGetAutomaximizeValue() / 100.0f);
2362 break;
2363- case UnityshellOptions::DevicesOption:
2364- unity::DevicesSettings::GetDefault().SetDevicesOption((unity::DevicesSettings::DevicesOption) optionGetDevicesOption());
2365- break;
2366 case UnityshellOptions::AltTabTimeout:
2367 switcher_controller_->detail_on_timeout = optionGetAltTabTimeout();
2368 case UnityshellOptions::AltTabBiasViewport:
2369
2370=== modified file 'plugins/unityshell/unityshell.xml.in'
2371--- plugins/unityshell/unityshell.xml.in 2012-08-07 10:41:46 +0000
2372+++ plugins/unityshell/unityshell.xml.in 2012-08-29 08:24:20 +0000
2373@@ -394,26 +394,6 @@
2374 <default>75</default>
2375 </option>
2376
2377- <option name="devices_option" type="int">
2378- <_short>Show Devices</_short>
2379- <_long>Show devices in the launcher</_long>
2380- <min>0</min>
2381- <max>2</max>
2382- <default>1</default>
2383- <desc>
2384- <value>0</value>
2385- <_name>Never</_name>
2386- </desc>
2387- <desc>
2388- <value>1</value>
2389- <_name>Only Mounted</_name>
2390- </desc>
2391- <desc>
2392- <value>2</value>
2393- <_name>Always</_name>
2394- </desc>
2395- </option>
2396-
2397 <option name="shortcut_overlay" type="bool">
2398 <_short>Enable Shortcut Hints Overlay</_short>
2399 <_long>Enable Shortcut Hints Overlay</_long>
2400
2401=== modified file 'po/POTFILES.in'
2402--- po/POTFILES.in 2012-08-23 06:15:27 +0000
2403+++ po/POTFILES.in 2012-08-29 08:24:20 +0000
2404@@ -11,11 +11,12 @@
2405 launcher/BFBLauncherIcon.cpp
2406 launcher/BamfLauncherIcon.cpp
2407 launcher/DesktopLauncherIcon.cpp
2408-launcher/DeviceLauncherIcon.cpp
2409+launcher/DeviceNotificationShowerImp.cpp
2410 launcher/LauncherController.cpp
2411 launcher/SoftwareCenterLauncherIcon.cpp
2412 launcher/SpacerLauncherIcon.cpp
2413 launcher/TrashLauncherIcon.cpp
2414+launcher/VolumeLauncherIcon.cpp
2415 panel/PanelMenuView.cpp
2416 plugins/networkarearegion/networkarearegion.xml.in
2417 plugins/unity-mt-grab-handles/unitymtgrabhandles.xml.in
2418
2419=== modified file 'tests/CMakeLists.txt'
2420--- tests/CMakeLists.txt 2012-08-28 12:23:15 +0000
2421+++ tests/CMakeLists.txt 2012-08-29 08:24:20 +0000
2422@@ -227,6 +227,9 @@
2423 test_switcher_model.cpp
2424 test_texture_cache.cpp
2425 test_thumbnail_generator.cpp
2426+ test_volume_imp.cpp
2427+ test_volume_launcher_icon.cpp
2428+ gmockmount.c
2429 gmockvolume.c
2430 ${CMAKE_SOURCE_DIR}/dash/AbstractPlacesGroup.cpp
2431 ${CMAKE_SOURCE_DIR}/dash/DashViewPrivate.cpp
2432@@ -258,14 +261,15 @@
2433 ${CMAKE_SOURCE_DIR}/launcher/DNDCollectionWindow.cpp
2434 ${CMAKE_SOURCE_DIR}/launcher/Decaymulator.cpp
2435 ${CMAKE_SOURCE_DIR}/launcher/DesktopLauncherIcon.cpp
2436- ${CMAKE_SOURCE_DIR}/launcher/DeviceLauncherIcon.cpp
2437 ${CMAKE_SOURCE_DIR}/launcher/DeviceLauncherSection.cpp
2438- ${CMAKE_SOURCE_DIR}/launcher/DevicesSettings.cpp
2439+ ${CMAKE_SOURCE_DIR}/launcher/DeviceNotificationDisplayImp.cpp
2440+ ${CMAKE_SOURCE_DIR}/launcher/DevicesSettingsImp.cpp
2441 ${CMAKE_SOURCE_DIR}/launcher/DndData.cpp
2442 ${CMAKE_SOURCE_DIR}/launcher/EdgeBarrierController.cpp
2443 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStore.cpp
2444 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStoreGSettings.cpp
2445 ${CMAKE_SOURCE_DIR}/launcher/FavoriteStorePrivate.cpp
2446+ ${CMAKE_SOURCE_DIR}/launcher/FileManagerOpenerImp.cpp
2447 ${CMAKE_SOURCE_DIR}/launcher/HudLauncherIcon.cpp
2448 ${CMAKE_SOURCE_DIR}/launcher/Launcher.cpp
2449 ${CMAKE_SOURCE_DIR}/launcher/LauncherController.cpp
2450@@ -296,6 +300,8 @@
2451 ${CMAKE_SOURCE_DIR}/launcher/SwitcherView.cpp
2452 ${CMAKE_SOURCE_DIR}/launcher/Tooltip.cpp
2453 ${CMAKE_SOURCE_DIR}/launcher/TrashLauncherIcon.cpp
2454+ ${CMAKE_SOURCE_DIR}/launcher/VolumeImp.cpp
2455+ ${CMAKE_SOURCE_DIR}/launcher/VolumeLauncherIcon.cpp
2456 ${CMAKE_SOURCE_DIR}/launcher/VolumeMonitorWrapper.cpp
2457 ${CMAKE_SOURCE_DIR}/unity-shared/Animator.cpp
2458 ${CMAKE_SOURCE_DIR}/unity-shared/BackgroundEffectHelper.cpp
2459
2460=== added file 'tests/gmockmount.c'
2461--- tests/gmockmount.c 1970-01-01 00:00:00 +0000
2462+++ tests/gmockmount.c 2012-08-29 08:24:20 +0000
2463@@ -0,0 +1,167 @@
2464+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2465+/*
2466+ * Copyright 2012 Canonical Ltd.
2467+ *
2468+ * This program is free software: you can redistribute it and/or modify it
2469+ * under the terms of the GNU Lesser General Public License version 3, as
2470+ * published by the Free Software Foundation.
2471+ *
2472+ * This program is distributed in the hope that it will be useful, but
2473+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2474+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
2475+ * PURPOSE. See the applicable version of the GNU Lesser General Public
2476+ * License for more details.
2477+ *
2478+ * You should have received a copy of both the GNU Lesser General Public
2479+ * License version 3 along with this program. If not, see
2480+ * <http://www.gnu.org/licenses/>
2481+ *
2482+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
2483+ *
2484+ */
2485+
2486+#include <glib.h>
2487+
2488+#include "gmockmount.h"
2489+
2490+static void g_mock_mount_iface_init (GMountIface *iface);
2491+
2492+G_DEFINE_TYPE_WITH_CODE (GMockMount, g_mock_mount, G_TYPE_OBJECT,
2493+ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
2494+ g_mock_mount_iface_init))
2495+
2496+static void
2497+g_mock_mount_finalize (GObject *object)
2498+{
2499+ G_OBJECT_CLASS (g_mock_mount_parent_class)->finalize (object);
2500+}
2501+
2502+static void
2503+g_mock_mount_dispose (GObject *object)
2504+{
2505+ G_OBJECT_CLASS (g_mock_mount_parent_class)->dispose (object);
2506+}
2507+
2508+
2509+static void
2510+g_mock_mount_class_init (GMockMountClass *klass)
2511+{
2512+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2513+
2514+ gobject_class->finalize = g_mock_mount_finalize;
2515+ gobject_class->dispose = g_mock_mount_dispose;
2516+}
2517+
2518+static void
2519+g_mock_mount_init (GMockMount *mock_mount)
2520+{}
2521+
2522+GMockMount *
2523+g_mock_mount_new ()
2524+{
2525+ GMockMount *mount;
2526+
2527+ mount = g_object_new (G_TYPE_MOCK_MOUNT, NULL);
2528+
2529+ return mount;
2530+}
2531+
2532+static GFile *
2533+g_mock_mount_get_root (GMount *mount)
2534+{
2535+ return g_file_new_for_path (ROOT_FILE_PATH);
2536+}
2537+
2538+static GIcon *
2539+g_mock_mount_get_icon (GMount *mount)
2540+{
2541+ return NULL;
2542+}
2543+
2544+static char *
2545+g_mock_mount_get_uuid (GMount *mount)
2546+{
2547+ return g_strdup ("");
2548+}
2549+
2550+static char *
2551+g_mock_mount_get_name (GMount *mount)
2552+{
2553+ return g_strdup ("");
2554+}
2555+
2556+static GDrive *
2557+g_mock_mount_get_drive (GMount *mount)
2558+{
2559+ return NULL;
2560+}
2561+
2562+static GVolume *
2563+g_mock_mount_get_volume (GMount *mount)
2564+{
2565+ return NULL;
2566+}
2567+
2568+static gboolean
2569+g_mock_mount_can_unmount (GMount *mount)
2570+{
2571+ return TRUE;
2572+}
2573+
2574+static gboolean
2575+g_mock_mount_can_eject (GMount *mount)
2576+{
2577+ return FALSE;
2578+}
2579+
2580+static void
2581+g_mock_mount_unmount (GMount *mount,
2582+ GMountUnmountFlags flags,
2583+ GCancellable *cancellable,
2584+ GAsyncReadyCallback callback,
2585+ gpointer user_data)
2586+{
2587+}
2588+
2589+static gboolean
2590+g_mock_mount_unmount_finish (GMount *mount,
2591+ GAsyncResult *result,
2592+ GError **error)
2593+{
2594+ return TRUE;
2595+}
2596+
2597+static void
2598+g_mock_mount_eject (GMount *mount,
2599+ GMountUnmountFlags flags,
2600+ GCancellable *cancellable,
2601+ GAsyncReadyCallback callback,
2602+ gpointer user_data)
2603+{
2604+}
2605+
2606+static gboolean
2607+g_mock_mount_eject_finish (GMount *mount,
2608+ GAsyncResult *result,
2609+ GError **error)
2610+{
2611+ return TRUE;
2612+}
2613+
2614+
2615+static void
2616+g_mock_mount_iface_init (GMountIface *iface)
2617+{
2618+ iface->get_root = g_mock_mount_get_root;
2619+ iface->get_name = g_mock_mount_get_name;
2620+ iface->get_icon = g_mock_mount_get_icon;
2621+ iface->get_uuid = g_mock_mount_get_uuid;
2622+ iface->get_drive = g_mock_mount_get_drive;
2623+ iface->get_volume = g_mock_mount_get_volume;
2624+ iface->can_unmount = g_mock_mount_can_unmount;
2625+ iface->can_eject = g_mock_mount_can_eject;
2626+ iface->unmount = g_mock_mount_unmount;
2627+ iface->unmount_finish = g_mock_mount_unmount_finish;
2628+ iface->eject = g_mock_mount_eject;
2629+ iface->eject_finish = g_mock_mount_eject_finish;
2630+}
2631
2632=== added file 'tests/gmockmount.h'
2633--- tests/gmockmount.h 1970-01-01 00:00:00 +0000
2634+++ tests/gmockmount.h 2012-08-29 08:24:20 +0000
2635@@ -0,0 +1,55 @@
2636+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2637+/*
2638+ * Copyright 2012 Canonical Ltd.
2639+ *
2640+ * This program is free software: you can redistribute it and/or modify it
2641+ * under the terms of the GNU Lesser General Public License version 3, as
2642+ * published by the Free Software Foundation.
2643+ *
2644+ * This program is distributed in the hope that it will be useful, but
2645+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2646+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
2647+ * PURPOSE. See the applicable version of the GNU Lesser General Public
2648+ * License for more details.
2649+ *
2650+ * You should have received a copy of both the GNU Lesser General Public
2651+ * License version 3 along with this program. If not, see
2652+ * <http://www.gnu.org/licenses/>
2653+ *
2654+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
2655+ *
2656+ */
2657+
2658+#ifndef UNITYSHELL_G_MOCK_MOUNT_H
2659+#define UNITYSHELL_G_MOCK_MOUNT_H
2660+
2661+#include <gio/gio.h>
2662+
2663+G_BEGIN_DECLS
2664+
2665+#define ROOT_FILE_PATH "/some/directory/testfile"
2666+#define ROOT_FILE_URI "file://" ROOT_FILE_PATH
2667+
2668+#define G_TYPE_MOCK_MOUNT (g_mock_mount_get_type ())
2669+#define G_MOCK_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_MOCK_MOUNT, GMockMount))
2670+#define G_MOCK_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_MOCK_MOUNT, GMockMountClass))
2671+#define G_IS_MOCK_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_MOCK_MOUNT))
2672+#define G_IS_MOCK_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_MOCK_MOUNT))
2673+
2674+typedef struct _GMockMount GMockMount;
2675+typedef struct _GMockMountClass GMockMountClass;
2676+
2677+struct _GMockMount {
2678+ GObject parent;
2679+};
2680+
2681+struct _GMockMountClass {
2682+ GObjectClass parent_class;
2683+};
2684+
2685+GType g_mock_mount_get_type (void) G_GNUC_CONST;
2686+GMockMount * g_mock_mount_new ();
2687+
2688+G_END_DECLS
2689+
2690+#endif // UNITYSHELL_G_MOCK_MOUNT_H
2691
2692=== modified file 'tests/gmockvolume.c'
2693--- tests/gmockvolume.c 2012-07-18 22:47:34 +0000
2694+++ tests/gmockvolume.c 2012-08-29 08:24:20 +0000
2695@@ -22,13 +22,13 @@
2696
2697 #include <glib.h>
2698
2699+#include "gmockmount.h"
2700 #include "gmockvolume.h"
2701
2702-static void g_mock_volume_volume_iface_init (GVolumeIface *iface);
2703+static void g_mock_volume_iface_init (GVolumeIface *iface);
2704
2705 G_DEFINE_TYPE_WITH_CODE (GMockVolume, g_mock_volume, G_TYPE_OBJECT,
2706- G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
2707- g_mock_volume_volume_iface_init))
2708+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, g_mock_volume_iface_init))
2709
2710 static void
2711 g_mock_volume_finalize (GObject *object)
2712@@ -37,44 +37,119 @@
2713 }
2714
2715 static void
2716+g_mock_volume_dispose (GObject *object)
2717+{
2718+ GMockVolume *self = G_MOCK_VOLUME (object);
2719+
2720+ self->can_eject = FALSE;
2721+
2722+ if (self->name)
2723+ {
2724+ g_free(self->name);
2725+ self->name = NULL;
2726+ }
2727+
2728+ if (self->icon)
2729+ {
2730+ g_object_unref(self->icon);
2731+ self->icon = NULL;
2732+ }
2733+
2734+ if (self->uuid)
2735+ {
2736+ g_free(self->uuid);
2737+ self->uuid = NULL;
2738+ }
2739+
2740+ if (self->mount)
2741+ {
2742+ g_object_unref(self->mount);
2743+ self->mount = NULL;
2744+ }
2745+
2746+ G_OBJECT_CLASS (g_mock_volume_parent_class)->dispose (object);
2747+}
2748+
2749+
2750+static void
2751 g_mock_volume_class_init (GMockVolumeClass *klass)
2752 {
2753 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2754
2755 gobject_class->finalize = g_mock_volume_finalize;
2756+ gobject_class->dispose = g_mock_volume_dispose;
2757 }
2758
2759 static void
2760 g_mock_volume_init (GMockVolume *mock_volume)
2761 {
2762+ mock_volume->name = g_strdup("");
2763+ mock_volume->icon = g_icon_new_for_string("", NULL);
2764+ mock_volume->uuid = g_strdup("");
2765+ mock_volume->mount = NULL;
2766 }
2767
2768 GMockVolume *
2769 g_mock_volume_new ()
2770 {
2771 GMockVolume *volume;
2772-
2773+
2774 volume = g_object_new (G_TYPE_MOCK_VOLUME, NULL);
2775
2776 return volume;
2777 }
2778
2779+void
2780+g_mock_volume_set_name (GMockVolume *volume, const char* name)
2781+{
2782+ if (volume->name)
2783+ g_free(volume->name);
2784+
2785+ volume->name = g_strdup (name);
2786+}
2787+
2788 static char *
2789 g_mock_volume_get_name (GVolume *volume)
2790 {
2791- return g_strdup ("");
2792-}
2793+ GMockVolume *self = G_MOCK_VOLUME (volume);
2794+ return g_strdup (self->name);
2795+}
2796+
2797+void
2798+g_mock_volume_set_icon (GMockVolume *volume, GIcon *icon)
2799+{
2800+ if (volume->icon)
2801+ g_object_unref(volume->icon);
2802+
2803+ volume->icon = icon;
2804+}
2805+
2806
2807 static GIcon *
2808 g_mock_volume_get_icon (GVolume *volume)
2809 {
2810- return g_icon_new_for_string("", NULL);
2811+ GMockVolume *self = G_MOCK_VOLUME (volume);
2812+
2813+ if (self->icon)
2814+ return g_object_ref (self->icon);
2815+ else
2816+ return NULL;
2817+}
2818+
2819+void
2820+g_mock_volume_set_uuid (GMockVolume *volume, const char* uuid)
2821+{
2822+ if (volume->uuid)
2823+ g_free(volume->uuid);
2824+
2825+ volume->uuid = g_strdup (uuid);
2826 }
2827
2828 static char *
2829 g_mock_volume_get_uuid (GVolume *volume)
2830 {
2831- return NULL;
2832+ GMockVolume *self = G_MOCK_VOLUME (volume);
2833+ return g_strdup (self->uuid);
2834 }
2835
2836 static GDrive *
2837@@ -83,10 +158,23 @@
2838 return NULL;
2839 }
2840
2841+void
2842+g_mock_volume_set_mount (GMockVolume *volume, GMount *mount)
2843+{
2844+ if (volume->mount)
2845+ g_object_unref(volume->mount);
2846+
2847+ volume->mount = mount;
2848+}
2849+
2850 static GMount *
2851 g_mock_volume_get_mount (GVolume *volume)
2852 {
2853- return NULL;
2854+ GMockVolume *self = G_MOCK_VOLUME (volume);
2855+ if (self->mount)
2856+ return g_object_ref (self->mount);
2857+ else
2858+ return NULL;
2859 }
2860
2861 static gboolean
2862@@ -98,7 +186,14 @@
2863 static gboolean
2864 g_mock_volume_can_eject (GVolume *volume)
2865 {
2866- return FALSE;
2867+ GMockVolume *self = G_MOCK_VOLUME (volume);
2868+ return self->can_eject;
2869+}
2870+
2871+void
2872+g_mock_volume_set_can_eject (GMockVolume* mock_volume, gboolean can_eject)
2873+{
2874+ mock_volume->can_eject = can_eject;
2875 }
2876
2877 static gboolean
2878@@ -115,6 +210,11 @@
2879 GAsyncReadyCallback callback,
2880 gpointer user_data)
2881 {
2882+ g_mock_volume_set_mount(G_MOCK_VOLUME(volume), G_MOUNT(g_mock_mount_new()));
2883+
2884+ callback(NULL,
2885+ G_ASYNC_RESULT (g_simple_async_result_new (NULL, NULL, NULL, NULL)),
2886+ user_data);
2887 }
2888
2889 static gboolean
2890@@ -132,7 +232,10 @@
2891 GAsyncReadyCallback callback,
2892 gpointer user_data)
2893 {
2894-}
2895+
2896+ callback(NULL,
2897+ G_ASYNC_RESULT (g_simple_async_result_new (NULL, NULL, NULL, NULL)),
2898+ user_data);}
2899
2900 static gboolean
2901 g_mock_volume_eject_finish (GVolume *volume,
2902@@ -146,6 +249,11 @@
2903 g_mock_volume_get_identifier (GVolume *volume,
2904 const gchar *kind)
2905 {
2906+ GMockVolume *self = G_MOCK_VOLUME (volume);
2907+
2908+ if (!g_strcmp0 (kind, G_VOLUME_IDENTIFIER_KIND_UUID))
2909+ return g_strdup (self->uuid);
2910+
2911 return NULL;
2912 }
2913
2914@@ -156,7 +264,7 @@
2915 }
2916
2917 static void
2918-g_mock_volume_volume_iface_init (GVolumeIface *iface)
2919+g_mock_volume_iface_init (GVolumeIface *iface)
2920 {
2921 iface->get_name = g_mock_volume_get_name;
2922 iface->get_icon = g_mock_volume_get_icon;
2923@@ -173,4 +281,3 @@
2924 iface->get_identifier = g_mock_volume_get_identifier;
2925 iface->enumerate_identifiers = g_mock_volume_enumerate_identifiers;
2926 }
2927-
2928
2929=== modified file 'tests/gmockvolume.h'
2930--- tests/gmockvolume.h 2012-07-18 22:47:34 +0000
2931+++ tests/gmockvolume.h 2012-08-29 08:24:20 +0000
2932@@ -38,14 +38,26 @@
2933
2934 struct _GMockVolume {
2935 GObject parent;
2936+
2937+ gboolean can_eject;
2938+ char *name;
2939+ GIcon *icon;
2940+ char *uuid;
2941+ GMount *mount;
2942 };
2943
2944 struct _GMockVolumeClass {
2945 GObjectClass parent_class;
2946 };
2947
2948-GType g_mock_volume_get_type (void) G_GNUC_CONST;
2949-GMockVolume * g_mock_volume_new ();
2950+GType g_mock_volume_get_type (void) G_GNUC_CONST;
2951+GMockVolume * g_mock_volume_new ();
2952+
2953+void g_mock_volume_set_can_eject (GMockVolume* volume, gboolean can_eject);
2954+void g_mock_volume_set_name (GMockVolume *volume, const char *name);
2955+void g_mock_volume_set_icon (GMockVolume *volume, GIcon *icon);
2956+void g_mock_volume_set_uuid (GMockVolume *volume, const char *uuid);
2957+void g_mock_volume_set_mount (GMockVolume *volume, GMount *mount);
2958
2959 G_END_DECLS
2960
2961
2962=== modified file 'tests/test_device_launcher_section.cpp'
2963--- tests/test_device_launcher_section.cpp 2012-07-18 22:47:34 +0000
2964+++ tests/test_device_launcher_section.cpp 2012-08-29 08:24:20 +0000
2965@@ -24,6 +24,7 @@
2966 using namespace testing;
2967
2968 #include "DeviceLauncherSection.h"
2969+#include "DevicesSettings.h"
2970 #include "AbstractVolumeMonitorWrapper.h"
2971 using namespace unity;
2972 using namespace unity::launcher;
2973@@ -74,12 +75,20 @@
2974 glib::Object<GVolume> volume2;
2975 };
2976
2977+class MockDevicesSettings : public DevicesSettings
2978+{
2979+ MOCK_CONST_METHOD1(IsABlacklistedDevice, bool(std::string const& uuid));
2980+ MOCK_METHOD1(TryToBlacklist, void(std::string const& uuid));
2981+ MOCK_METHOD1(TryToUnblacklist, void(std::string const& uuid));
2982+};
2983+
2984 class TestDeviceLauncherSection : public Test
2985 {
2986 public:
2987 TestDeviceLauncherSection()
2988 : monitor_(new MockVolumeMonitorWrapper)
2989- , section_(monitor_)
2990+ , devices_settings_(new MockDevicesSettings)
2991+ , section_(monitor_, devices_settings_)
2992 {}
2993
2994 void SetUp()
2995@@ -89,6 +98,7 @@
2996 }
2997
2998 MockVolumeMonitorWrapper::Ptr monitor_;
2999+ DevicesSettings::Ptr devices_settings_;
3000 DeviceLauncherSection section_;
3001 };
3002
3003
3004=== added file 'tests/test_volume_imp.cpp'
3005--- tests/test_volume_imp.cpp 1970-01-01 00:00:00 +0000
3006+++ tests/test_volume_imp.cpp 2012-08-29 08:24:20 +0000
3007@@ -0,0 +1,163 @@
3008+/*
3009+ * Copyright 2012 Canonical Ltd.
3010+ *
3011+ * This program is free software: you can redistribute it and/or modify it
3012+ * under the terms of the GNU General Public License version 3, as published
3013+ * by the Free Software Foundation.
3014+ *
3015+ * This program is distributed in the hope that it will be useful, but
3016+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3017+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
3018+ * PURPOSE. See the GNU General Public License for more details.
3019+ *
3020+ * You should have received a copy of the GNU General Public License
3021+ * version 3 along with this program. If not, see
3022+ * <http://www.gnu.org/licenses/>
3023+ *
3024+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
3025+ */
3026+
3027+#include <memory>
3028+
3029+#include <gmock/gmock.h>
3030+using namespace testing;
3031+
3032+#include "gmockmount.h"
3033+#include "gmockvolume.h"
3034+#include "launcher/VolumeImp.h"
3035+#include "test_utils.h"
3036+using namespace unity;
3037+
3038+namespace
3039+{
3040+
3041+class MockFileManagerOpener : public launcher::FileManagerOpener
3042+{
3043+public:
3044+ typedef std::shared_ptr<MockFileManagerOpener> Ptr;
3045+
3046+ MOCK_METHOD1(Open, void(std::string const& uri));
3047+};
3048+
3049+class MockDeviceNotificationDisplay : public launcher::DeviceNotificationDisplay
3050+{
3051+public:
3052+ typedef std::shared_ptr<MockDeviceNotificationDisplay> Ptr;
3053+
3054+ MOCK_METHOD2(Display, void(std::string const& icon_name, std::string const& device_name));
3055+};
3056+
3057+class TestVolumeImp : public Test
3058+{
3059+public:
3060+ void SetUp()
3061+ {
3062+ gvolume_ = g_mock_volume_new();
3063+ file_manager_opener_.reset(new MockFileManagerOpener);
3064+ device_notification_display_.reset(new MockDeviceNotificationDisplay);
3065+ volume_.reset(new launcher::VolumeImp(glib::Object<GVolume>(G_VOLUME(gvolume_.RawPtr()), glib::AddRef()),
3066+ file_manager_opener_, device_notification_display_));
3067+ }
3068+
3069+ glib::Object<GMockVolume> gvolume_;
3070+ MockFileManagerOpener::Ptr file_manager_opener_;
3071+ MockDeviceNotificationDisplay::Ptr device_notification_display_;
3072+ launcher::VolumeImp::Ptr volume_;
3073+};
3074+
3075+TEST_F(TestVolumeImp, TestCtor)
3076+{
3077+ EXPECT_FALSE(volume_->IsMounted());
3078+}
3079+
3080+TEST_F(TestVolumeImp, TestCanBeEjected)
3081+{
3082+ EXPECT_FALSE(volume_->CanBeEjected());
3083+
3084+ g_mock_volume_set_can_eject(gvolume_, TRUE);
3085+ EXPECT_TRUE(volume_->CanBeEjected());
3086+}
3087+
3088+TEST_F(TestVolumeImp, TestGetName)
3089+{
3090+ std::string const volume_name("Test Device");
3091+
3092+ // g_mock_volume_set_name is equivalent to
3093+ // EXPECT_CALL(gvolume_, g_volume_get_name) ...
3094+ g_mock_volume_set_name(gvolume_, volume_name.c_str());
3095+ EXPECT_EQ(volume_->GetName(), volume_name);
3096+}
3097+
3098+TEST_F(TestVolumeImp, TestGetIconName)
3099+{
3100+ std::string const icon_name("gnome-dev-cdrom");
3101+
3102+ g_mock_volume_set_icon(gvolume_, g_icon_new_for_string(icon_name.c_str(), NULL));
3103+ EXPECT_EQ(volume_->GetIconName(), icon_name);
3104+}
3105+
3106+TEST_F(TestVolumeImp, TestGetIdentifier)
3107+{
3108+ std::string const uuid("0123456789abc");
3109+
3110+ g_mock_volume_set_uuid(gvolume_, uuid.c_str());
3111+ EXPECT_EQ(volume_->GetIdentifier(), uuid);
3112+}
3113+
3114+TEST_F(TestVolumeImp, TestIsMounted)
3115+{
3116+ g_mock_volume_set_mount(gvolume_, nullptr);
3117+ ASSERT_FALSE(volume_->IsMounted());
3118+
3119+ g_mock_volume_set_mount(gvolume_, G_MOUNT(g_mock_mount_new()));
3120+ EXPECT_TRUE(volume_->IsMounted());
3121+}
3122+
3123+TEST_F(TestVolumeImp, TestEjectAndShowNotification)
3124+{
3125+ g_mock_volume_set_can_eject(gvolume_, TRUE);
3126+
3127+ EXPECT_CALL(*device_notification_display_, Display(volume_->GetIconName(), volume_->GetName()))
3128+ .Times(1);
3129+
3130+ volume_->EjectAndShowNotification();
3131+}
3132+
3133+TEST_F(TestVolumeImp, TestMountAndOpenInFileManager)
3134+{
3135+ EXPECT_CALL(*file_manager_opener_, Open(ROOT_FILE_URI))
3136+ .Times(1);
3137+
3138+ volume_->MountAndOpenInFileManager();
3139+ EXPECT_TRUE(volume_->IsMounted());
3140+
3141+ EXPECT_CALL(*file_manager_opener_, Open(ROOT_FILE_URI))
3142+ .Times(1);
3143+
3144+ volume_->MountAndOpenInFileManager();
3145+ EXPECT_TRUE(volume_->IsMounted());
3146+}
3147+
3148+TEST_F(TestVolumeImp, TestChangedSignal)
3149+{
3150+ bool callback_called = false;
3151+ volume_->changed.connect([&]() {
3152+ callback_called = true;
3153+ });
3154+
3155+ g_signal_emit_by_name(gvolume_, "changed", nullptr);
3156+ Utils::WaitUntil(callback_called);
3157+}
3158+
3159+TEST_F(TestVolumeImp, TestRemovedSignal)
3160+{
3161+ bool callback_called = false;
3162+ volume_->removed.connect([&]() {
3163+ callback_called = true;
3164+ });
3165+
3166+ g_signal_emit_by_name(gvolume_, "removed", nullptr);
3167+ Utils::WaitUntil(callback_called);
3168+}
3169+
3170+}
3171
3172=== added file 'tests/test_volume_launcher_icon.cpp'
3173--- tests/test_volume_launcher_icon.cpp 1970-01-01 00:00:00 +0000
3174+++ tests/test_volume_launcher_icon.cpp 2012-08-29 08:24:20 +0000
3175@@ -0,0 +1,498 @@
3176+/*
3177+ * Copyright 2012 Canonical Ltd.
3178+ *
3179+ * This program is free software: you can redistribute it and/or modify it
3180+ * under the terms of the GNU General Public License version 3, as published
3181+ * by the Free Software Foundation.
3182+ *
3183+ * This program is distributed in the hope that it will be useful, but
3184+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3185+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
3186+ * PURPOSE. See the GNU General Public License for more details.
3187+ *
3188+ * You should have received a copy of the GNU General Public License
3189+ * version 3 along with this program. If not, see
3190+ * <http://www.gnu.org/licenses/>
3191+ *
3192+ * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com>
3193+ */
3194+
3195+#include <gmock/gmock.h>
3196+using namespace testing;
3197+
3198+#include "launcher/DevicesSettings.h"
3199+#include "launcher/Volume.h"
3200+#include "launcher/VolumeLauncherIcon.h"
3201+#include "test_utils.h"
3202+using namespace unity;
3203+using namespace unity::launcher;
3204+
3205+namespace
3206+{
3207+
3208+class MockVolume : public Volume
3209+{
3210+public:
3211+ typedef std::shared_ptr<MockVolume> Ptr;
3212+
3213+ MOCK_CONST_METHOD0(CanBeRemoved, bool(void));
3214+ MOCK_CONST_METHOD0(CanBeStopped, bool(void));
3215+ MOCK_CONST_METHOD0(GetName, std::string(void));
3216+ MOCK_CONST_METHOD0(GetIconName, std::string(void));
3217+ MOCK_CONST_METHOD0(GetIdentifier, std::string(void));
3218+ MOCK_CONST_METHOD0(HasSiblings, bool(void));
3219+ MOCK_CONST_METHOD0(CanBeEjected, bool(void));
3220+ MOCK_CONST_METHOD0(IsMounted, bool(void));
3221+
3222+ MOCK_METHOD0(EjectAndShowNotification, void(void));
3223+ MOCK_METHOD0(MountAndOpenInFileManager, void(void));
3224+ MOCK_METHOD0(StopDrive, void(void));
3225+ MOCK_METHOD0(Unmount, void(void));
3226+};
3227+
3228+class MockDevicesSettings : public DevicesSettings
3229+{
3230+public:
3231+ typedef std::shared_ptr<MockDevicesSettings> Ptr;
3232+
3233+ MOCK_CONST_METHOD1(IsABlacklistedDevice, bool(std::string const& uuid));
3234+ MOCK_METHOD1(TryToBlacklist, void(std::string const& uuid));
3235+ MOCK_METHOD1(TryToUnblacklist, void(std::string const& uuid));
3236+};
3237+
3238+
3239+class TestVolumeLauncherIcon : public Test
3240+{
3241+public:
3242+ virtual void SetUp()
3243+ {
3244+ volume_.reset(new MockVolume);
3245+ settings_.reset(new MockDevicesSettings);
3246+
3247+ SetupVolumeDefaultBehavior();
3248+ SetupSettingsDefaultBehavior();
3249+ }
3250+
3251+ void CreateIcon()
3252+ {
3253+ icon_ = new VolumeLauncherIcon(volume_, settings_);
3254+ }
3255+
3256+ void SetupSettingsDefaultBehavior()
3257+ {
3258+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3259+ .WillRepeatedly(Return(false));
3260+ }
3261+
3262+ void SetupVolumeDefaultBehavior()
3263+ {
3264+ EXPECT_CALL(*volume_, CanBeRemoved())
3265+ .WillRepeatedly(Return(false));
3266+
3267+ EXPECT_CALL(*volume_, CanBeStopped())
3268+ .WillRepeatedly(Return(false));
3269+
3270+ EXPECT_CALL(*volume_, GetName())
3271+ .WillRepeatedly(Return("Test Name"));
3272+
3273+ EXPECT_CALL(*volume_, GetIconName())
3274+ .WillRepeatedly(Return("Test Icon Name"));
3275+
3276+ EXPECT_CALL(*volume_, GetIdentifier())
3277+ .WillRepeatedly(Return("Test Identifier"));
3278+
3279+ EXPECT_CALL(*volume_, HasSiblings())
3280+ .WillRepeatedly(Return(false));
3281+
3282+ EXPECT_CALL(*volume_, CanBeEjected())
3283+ .WillRepeatedly(Return(false));
3284+
3285+ EXPECT_CALL(*volume_, IsMounted())
3286+ .WillRepeatedly(Return(true));
3287+ }
3288+
3289+ glib::Object<DbusmenuMenuitem> GetMenuItemAtIndex(int index)
3290+ {
3291+ auto menuitems = icon_->GetMenus();
3292+ auto menuitem = menuitems.begin();
3293+ std::advance(menuitem, index);
3294+
3295+ return *menuitem;
3296+ }
3297+
3298+ MockVolume::Ptr volume_;
3299+ MockDevicesSettings::Ptr settings_;
3300+ VolumeLauncherIcon::Ptr icon_;
3301+};
3302+
3303+TEST_F(TestVolumeLauncherIcon, TestIconType)
3304+{
3305+ CreateIcon();
3306+ EXPECT_EQ(icon_->GetIconType(), AbstractLauncherIcon::IconType::DEVICE);
3307+}
3308+
3309+TEST_F(TestVolumeLauncherIcon, TestQuirks)
3310+{
3311+ CreateIcon();
3312+
3313+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
3314+}
3315+
3316+TEST_F(TestVolumeLauncherIcon, TestTooltipText)
3317+{
3318+ CreateIcon();
3319+
3320+ ASSERT_EQ(icon_->tooltip_text, "Test Name");
3321+}
3322+
3323+TEST_F(TestVolumeLauncherIcon, TestIconName)
3324+{
3325+ CreateIcon();
3326+
3327+ ASSERT_EQ(icon_->icon_name, "Test Icon Name");
3328+}
3329+
3330+TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyMountedVolume)
3331+{
3332+ CreateIcon();
3333+
3334+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3335+}
3336+
3337+TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyMountedBlacklistedVolume)
3338+{
3339+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3340+ .WillRepeatedly(Return(true));
3341+
3342+ CreateIcon();
3343+
3344+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3345+}
3346+
3347+
3348+TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyUnmountedVolume)
3349+{
3350+ EXPECT_CALL(*volume_, IsMounted())
3351+ .WillRepeatedly(Return(false));
3352+
3353+ CreateIcon();
3354+
3355+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3356+}
3357+
3358+
3359+TEST_F(TestVolumeLauncherIcon, TestVisibility_InitiallyUnmountedBlacklistedVolume)
3360+{
3361+ EXPECT_CALL(*volume_, IsMounted())
3362+ .WillRepeatedly(Return(false));
3363+
3364+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3365+ .WillRepeatedly(Return(true));
3366+
3367+ CreateIcon();
3368+
3369+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3370+}
3371+
3372+TEST_F(TestVolumeLauncherIcon, TestSettingsChangedSignal)
3373+{
3374+ CreateIcon();
3375+
3376+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3377+ .WillRepeatedly(Return(true));
3378+ settings_->changed.emit();
3379+
3380+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3381+}
3382+
3383+TEST_F(TestVolumeLauncherIcon, TestVisibilityAfterUnmount)
3384+{
3385+ CreateIcon();
3386+
3387+ EXPECT_CALL(*volume_, IsMounted())
3388+ .WillRepeatedly(Return(false));
3389+
3390+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3391+ .Times(0);
3392+
3393+ volume_->changed.emit();
3394+ Utils::WaitForTimeout(1);
3395+
3396+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3397+}
3398+
3399+TEST_F(TestVolumeLauncherIcon, TestVisibilityAfterUnmount_BlacklistedVolume)
3400+{
3401+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3402+ .WillRepeatedly(Return(true));
3403+
3404+ CreateIcon();
3405+
3406+ EXPECT_CALL(*volume_, IsMounted())
3407+ .WillRepeatedly(Return(false));
3408+
3409+ EXPECT_CALL(*settings_, TryToUnblacklist(_))
3410+ .Times(0);
3411+
3412+ volume_->changed.emit();
3413+ Utils::WaitForTimeout(1);
3414+
3415+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3416+}
3417+
3418+TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdentifier)
3419+{
3420+ EXPECT_CALL(*volume_, GetIdentifier())
3421+ .WillRepeatedly(Return(""));
3422+
3423+ CreateIcon();
3424+
3425+ for (auto menuitem : icon_->GetMenus())
3426+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher");
3427+}
3428+
3429+TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Success)
3430+{
3431+ CreateIcon();
3432+
3433+ auto menuitem = GetMenuItemAtIndex(0);
3434+
3435+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher");
3436+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3437+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3438+
3439+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3440+ .Times(1);
3441+
3442+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3443+ .WillRepeatedly(Return(true));
3444+
3445+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3446+ settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal.
3447+ Utils::WaitForTimeout(1);
3448+
3449+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3450+}
3451+
3452+TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure)
3453+{
3454+ CreateIcon();
3455+
3456+ auto menuitem = GetMenuItemAtIndex(0);
3457+
3458+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher");
3459+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3460+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3461+
3462+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3463+ .Times(1);
3464+
3465+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3466+ Utils::WaitForTimeout(1);
3467+
3468+ ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
3469+}
3470+
3471+TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem)
3472+{
3473+ CreateIcon();
3474+
3475+ auto menuitem = GetMenuItemAtIndex(1);
3476+
3477+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Open");
3478+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3479+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3480+
3481+ EXPECT_CALL(*volume_, MountAndOpenInFileManager())
3482+ .Times(1);
3483+
3484+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3485+ Utils::WaitForTimeout(1);
3486+}
3487+
3488+TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem_NotEjectableVolume)
3489+{
3490+ CreateIcon();
3491+
3492+ for (auto menuitem : icon_->GetMenus())
3493+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Eject");
3494+}
3495+
3496+TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem)
3497+{
3498+ EXPECT_CALL(*volume_, CanBeEjected())
3499+ .WillRepeatedly(Return(true));
3500+
3501+ CreateIcon();
3502+
3503+ auto menuitem = GetMenuItemAtIndex(2);
3504+
3505+ EXPECT_CALL(*volume_, EjectAndShowNotification())
3506+ .Times(1);
3507+
3508+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Eject");
3509+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3510+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3511+
3512+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3513+ Utils::WaitForTimeout(1);
3514+}
3515+
3516+TEST_F(TestVolumeLauncherIcon, TestEjectMenuItem_NotStoppableVolume)
3517+{
3518+ CreateIcon();
3519+
3520+ for (auto menuitem : icon_->GetMenus())
3521+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Safely remove");
3522+}
3523+
3524+TEST_F(TestVolumeLauncherIcon, TestSafelyRemoveMenuItem)
3525+{
3526+ EXPECT_CALL(*volume_, CanBeStopped())
3527+ .WillRepeatedly(Return(true));
3528+
3529+ CreateIcon();
3530+
3531+ auto menuitem = GetMenuItemAtIndex(2);
3532+
3533+ EXPECT_CALL(*volume_, StopDrive())
3534+ .Times(1);
3535+
3536+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Safely remove");
3537+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3538+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3539+
3540+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3541+ Utils::WaitForTimeout(1);
3542+}
3543+
3544+TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem_UnmountedVolume)
3545+{
3546+ EXPECT_CALL(*volume_, IsMounted())
3547+ .WillRepeatedly(Return(false));
3548+
3549+ CreateIcon();
3550+
3551+ for (auto menuitem : icon_->GetMenus())
3552+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unmount");
3553+}
3554+
3555+
3556+TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem_EjectableVolume)
3557+{
3558+ EXPECT_CALL(*volume_, CanBeEjected())
3559+ .WillRepeatedly(Return(true));
3560+
3561+ EXPECT_CALL(*volume_, IsMounted())
3562+ .WillRepeatedly(Return(true));
3563+
3564+ CreateIcon();
3565+
3566+ for (auto menuitem : icon_->GetMenus())
3567+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unmount");
3568+}
3569+
3570+TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem_StoppableVolume)
3571+{
3572+ EXPECT_CALL(*volume_, CanBeStopped())
3573+ .WillRepeatedly(Return(true));
3574+
3575+ EXPECT_CALL(*volume_, IsMounted())
3576+ .WillRepeatedly(Return(true));
3577+
3578+ CreateIcon();
3579+
3580+ for (auto menuitem : icon_->GetMenus())
3581+ ASSERT_STRNE(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unmount");
3582+}
3583+
3584+TEST_F(TestVolumeLauncherIcon, TestUnmountMenuItem)
3585+{
3586+ EXPECT_CALL(*volume_, IsMounted())
3587+ .WillRepeatedly(Return(true));
3588+
3589+ CreateIcon();
3590+
3591+ auto menuitem = GetMenuItemAtIndex(2);
3592+
3593+ EXPECT_CALL(*volume_, Unmount())
3594+ .Times(1);
3595+
3596+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unmount");
3597+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
3598+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
3599+
3600+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3601+ Utils::WaitForTimeout(1);
3602+}
3603+
3604+TEST_F(TestVolumeLauncherIcon, TestCanBeEject)
3605+{
3606+ CreateIcon();
3607+
3608+ EXPECT_CALL(*volume_, CanBeEjected())
3609+ .WillRepeatedly(Return(true));
3610+ ASSERT_TRUE(icon_->CanEject());
3611+
3612+ EXPECT_CALL(*volume_, CanBeEjected())
3613+ .WillRepeatedly(Return(false));
3614+ ASSERT_FALSE(icon_->CanEject());
3615+
3616+}
3617+
3618+TEST_F(TestVolumeLauncherIcon, TestEject)
3619+{
3620+ EXPECT_CALL(*volume_, CanBeEjected())
3621+ .WillRepeatedly(Return(true));
3622+
3623+ CreateIcon();
3624+
3625+ EXPECT_CALL(*volume_, EjectAndShowNotification())
3626+ .Times(1);
3627+
3628+ icon_->EjectAndShowNotification();
3629+}
3630+
3631+TEST_F(TestVolumeLauncherIcon, OnRemoved)
3632+{
3633+ CreateIcon();
3634+
3635+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3636+ .Times(0);
3637+ EXPECT_CALL(*settings_, TryToUnblacklist(_))
3638+ .Times(0);
3639+
3640+ volume_->removed.emit();
3641+}
3642+
3643+TEST_F(TestVolumeLauncherIcon, OnRemoved_RemovabledVolume)
3644+{
3645+ EXPECT_CALL(*volume_, CanBeRemoved())
3646+ .WillRepeatedly(Return(true));
3647+ CreateIcon();
3648+
3649+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3650+ .Times(0);
3651+ EXPECT_CALL(*settings_, TryToUnblacklist(_))
3652+ .Times(0);
3653+
3654+ volume_->removed.emit();
3655+}
3656+
3657+TEST_F(TestVolumeLauncherIcon, OnRemoved_RemovableAndBlacklistedVolume)
3658+{
3659+ EXPECT_CALL(*volume_, CanBeRemoved())
3660+ .WillRepeatedly(Return(true));
3661+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
3662+ .WillRepeatedly(Return(true));
3663+ CreateIcon();
3664+
3665+ EXPECT_CALL(*settings_, TryToBlacklist(_))
3666+ .Times(0);
3667+ EXPECT_CALL(*settings_, TryToUnblacklist(_))
3668+ .Times(1);
3669+
3670+ volume_->removed.emit();
3671+}
3672+
3673+}