Merge lp:~3v1n0/unity/dash-files-open into lp:unity/7.0
- dash-files-open
- Merge into 7.0
Status: | Work in progress |
---|---|
Proposed branch: | lp:~3v1n0/unity/dash-files-open |
Merge into: | lp:unity/7.0 |
Diff against target: |
596 lines (+172/-76) 12 files modified
UnityCore/Lens.cpp (+10/-2) dash/DashController.cpp (+1/-2) dash/DashView.cpp (+26/-12) dash/DashView.h (+5/-1) dash/StandaloneDash.cpp (+1/-3) tests/test_dash_view.cpp (+17/-3) tests/test_lens.cpp (+28/-10) tests/test_mock_filemanager.h (+4/-3) tests/test_service_lens.cpp (+14/-7) unity-shared/FileManager.h (+7/-3) unity-shared/GnomeFileManager.cpp (+51/-26) unity-shared/GnomeFileManager.h (+8/-4) |
To merge this branch: | bzr merge lp:~3v1n0/unity/dash-files-open |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Unity Team | Pending | ||
Review via email: mp+162008@code.launchpad.net |
Commit message
Lens: if a lens returns a "goto-uri" parameter, activate that instead of the activated uri
DashView: use FileManager to launch an activated location, in case opening it.
Description of the change
We use the "goto-uri" parameter that a Lens can return to activate the lens-parsed location, using FileManager with correct timestamp to open or launch files.
This depends on lp:~3v1n0/unity-lens-files/delegate-activation/+merge/162007
- 3318. By Marco Trevisan (Treviño)
-
TestDashView: use our beloved beef
- 3319. By Marco Trevisan (Treviño)
-
TestLensService: update to support goto-uri redirection
- 3320. By Marco Trevisan (Treviño)
-
TestLens: add activation redirection test
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3320
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unmerged revisions
- 3320. By Marco Trevisan (Treviño)
-
TestLens: add activation redirection test
- 3319. By Marco Trevisan (Treviño)
-
TestLensService: update to support goto-uri redirection
- 3318. By Marco Trevisan (Treviño)
-
TestDashView: use our beloved beef
- 3317. By Marco Trevisan (Treviño)
-
TestDashView: add tests for Filemanager Launch and Opening
- 3316. By Marco Trevisan (Treviño)
-
DashView: use FileManager to launch an activated location, in case opening it.
- 3315. By Marco Trevisan (Treviño)
-
Lens: if a lens returns a "goto-uri" parameter, activate that instead of the activated uri
- 3314. By Marco Trevisan (Treviño)
-
GnomeFileManager: add Launch Implementation, to launch a file with default handler
- 3313. By Marco Trevisan (Treviño)
-
GnomeFileManager: add Utility function to get the Launch Context
- 3312. By Marco Trevisan (Treviño)
-
GnomeFileManager: If the requested location is not mounted, we open the file-manager
If the requested position is not mounted, we open the file-manager waiting it to mount
the requested location. - 3311. By Marco Trevisan (Treviño)
-
FileManager: return a bool on Open methods.
Preview Diff
1 | === modified file 'UnityCore/Lens.cpp' | |||
2 | --- UnityCore/Lens.cpp 2013-03-21 19:11:44 +0000 | |||
3 | +++ UnityCore/Lens.cpp 2013-05-02 01:34:26 +0000 | |||
4 | @@ -509,7 +509,7 @@ | |||
5 | 509 | guint32 handled; | 509 | guint32 handled; |
6 | 510 | GVariant* hints_variant; | 510 | GVariant* hints_variant; |
7 | 511 | Hints hints; | 511 | Hints hints; |
9 | 512 | 512 | ||
10 | 513 | g_variant_get(parameters, "((su@a{sv}))", &uri, &handled, &hints_variant); | 513 | g_variant_get(parameters, "((su@a{sv}))", &uri, &handled, &hints_variant); |
11 | 514 | 514 | ||
12 | 515 | glib::Variant dict (hints_variant, glib::StealRef()); | 515 | glib::Variant dict (hints_variant, glib::StealRef()); |
13 | @@ -536,7 +536,15 @@ | |||
14 | 536 | } | 536 | } |
15 | 537 | else | 537 | else |
16 | 538 | { | 538 | { |
18 | 539 | owner_->activated.emit(uri.Str(), static_cast<HandledType>(handled), hints); | 539 | auto activated_uri = uri.Str(); |
19 | 540 | |||
20 | 541 | auto iter = hints.find("goto-uri"); | ||
21 | 542 | if (iter != hints.end()) | ||
22 | 543 | { | ||
23 | 544 | activated_uri = "goto-uri:" + iter->second.GetString(); | ||
24 | 545 | } | ||
25 | 546 | |||
26 | 547 | owner_->activated.emit(activated_uri, static_cast<HandledType>(handled), hints); | ||
27 | 540 | } | 548 | } |
28 | 541 | } | 549 | } |
29 | 542 | 550 | ||
30 | 543 | 551 | ||
31 | === modified file 'dash/DashController.cpp' | |||
32 | --- dash/DashController.cpp 2013-04-10 20:59:51 +0000 | |||
33 | +++ dash/DashController.cpp 2013-05-02 01:34:26 +0000 | |||
34 | @@ -23,7 +23,6 @@ | |||
35 | 23 | #include <Nux/HLayout.h> | 23 | #include <Nux/HLayout.h> |
36 | 24 | #include <UnityCore/GLibWrapper.h> | 24 | #include <UnityCore/GLibWrapper.h> |
37 | 25 | 25 | ||
38 | 26 | #include "ApplicationStarterImp.h" | ||
39 | 27 | #include "unity-shared/DashStyle.h" | 26 | #include "unity-shared/DashStyle.h" |
40 | 28 | #include "unity-shared/PanelStyle.h" | 27 | #include "unity-shared/PanelStyle.h" |
41 | 29 | #include "unity-shared/UBusMessages.h" | 28 | #include "unity-shared/UBusMessages.h" |
42 | @@ -140,7 +139,7 @@ | |||
43 | 140 | 139 | ||
44 | 141 | void Controller::SetupDashView() | 140 | void Controller::SetupDashView() |
45 | 142 | { | 141 | { |
47 | 143 | view_ = new DashView(std::make_shared<FilesystemLenses>(), std::make_shared<ApplicationStarterImp>()); | 142 | view_ = new DashView(std::make_shared<FilesystemLenses>()); |
48 | 144 | AddChild(view_); | 143 | AddChild(view_); |
49 | 145 | 144 | ||
50 | 146 | nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); | 145 | nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
51 | 147 | 146 | ||
52 | === modified file 'dash/DashView.cpp' | |||
53 | --- dash/DashView.cpp 2013-04-12 16:01:19 +0000 | |||
54 | +++ dash/DashView.cpp 2013-05-02 01:34:26 +0000 | |||
55 | @@ -20,6 +20,7 @@ | |||
56 | 20 | 20 | ||
57 | 21 | #include "DashView.h" | 21 | #include "DashView.h" |
58 | 22 | #include "DashViewPrivate.h" | 22 | #include "DashViewPrivate.h" |
59 | 23 | #include "ApplicationStarterImp.h" | ||
60 | 23 | #include "FilterExpanderLabel.h" | 24 | #include "FilterExpanderLabel.h" |
61 | 24 | 25 | ||
62 | 25 | #include <math.h> | 26 | #include <math.h> |
63 | @@ -31,6 +32,7 @@ | |||
64 | 31 | #include <UnityCore/GLibWrapper.h> | 32 | #include <UnityCore/GLibWrapper.h> |
65 | 32 | #include <UnityCore/RadioOptionFilter.h> | 33 | #include <UnityCore/RadioOptionFilter.h> |
66 | 33 | 34 | ||
67 | 35 | #include "unity-shared/GnomeFileManager.h" | ||
68 | 34 | #include "unity-shared/DashStyle.h" | 36 | #include "unity-shared/DashStyle.h" |
69 | 35 | #include "unity-shared/KeyboardUtil.h" | 37 | #include "unity-shared/KeyboardUtil.h" |
70 | 36 | #include "unity-shared/PreviewStyle.h" | 38 | #include "unity-shared/PreviewStyle.h" |
71 | @@ -56,6 +58,10 @@ | |||
72 | 56 | const int GROUP_HEADING_HEIGHT = 24; | 58 | const int GROUP_HEADING_HEIGHT = 24; |
73 | 57 | 59 | ||
74 | 58 | const int PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET = 10; | 60 | const int PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET = 10; |
75 | 61 | |||
76 | 62 | const std::string RESULT_APPLICATION_PREFIX = "application://"; | ||
77 | 63 | const std::string RESULT_RUNNER_PREFIX = "unity-runner://"; | ||
78 | 64 | const std::string RESULT_DIRECTORY_PREFIX = "directory://"; | ||
79 | 59 | } | 65 | } |
80 | 60 | 66 | ||
81 | 61 | // This is so we can access some protected members in nux::VLayout and | 67 | // This is so we can access some protected members in nux::VLayout and |
82 | @@ -109,11 +115,12 @@ | |||
83 | 109 | 115 | ||
84 | 110 | NUX_IMPLEMENT_OBJECT_TYPE(DashView); | 116 | NUX_IMPLEMENT_OBJECT_TYPE(DashView); |
85 | 111 | 117 | ||
87 | 112 | DashView::DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& application_starter) | 118 | DashView::DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& application_starter, FileManager::Ptr const& file_manager) |
88 | 113 | : nux::View(NUX_TRACKER_LOCATION) | 119 | : nux::View(NUX_TRACKER_LOCATION) |
89 | 114 | , lenses_(lenses) | 120 | , lenses_(lenses) |
90 | 115 | , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search your computer and online sources"))) | 121 | , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search your computer and online sources"))) |
92 | 116 | , application_starter_(application_starter) | 122 | , application_starter_(application_starter ? application_starter : std::make_shared<ApplicationStarterImp>()) |
93 | 123 | , file_manager_(file_manager ? file_manager : GnomeFileManager::Get()) | ||
94 | 117 | , preview_container_(nullptr) | 124 | , preview_container_(nullptr) |
95 | 118 | , preview_displaying_(false) | 125 | , preview_displaying_(false) |
96 | 119 | , preview_navigation_mode_(previews::Navigation::NONE) | 126 | , preview_navigation_mode_(previews::Navigation::NONE) |
97 | @@ -1380,18 +1387,25 @@ | |||
98 | 1380 | 1387 | ||
99 | 1381 | LOG_DEBUG(logger) << "Fallback activating " << uri; | 1388 | LOG_DEBUG(logger) << "Fallback activating " << uri; |
100 | 1382 | 1389 | ||
110 | 1383 | if (g_str_has_prefix(uri.c_str(), "application://")) | 1390 | if (uri.find(RESULT_APPLICATION_PREFIX) == 0) |
111 | 1384 | { | 1391 | { |
112 | 1385 | std::string const& appname = uri.substr(14); | 1392 | std::string const& appname = uri.substr(RESULT_APPLICATION_PREFIX.size()); |
113 | 1386 | return application_starter_->Launch(appname, last_activated_timestamp_); | 1393 | return application_starter_->Launch(appname, last_activated_timestamp_); |
114 | 1387 | } | 1394 | } |
115 | 1388 | else if (g_str_has_prefix(uri.c_str(), "unity-runner://")) | 1395 | else if (uri.find(RESULT_RUNNER_PREFIX) == 0) |
116 | 1389 | { | 1396 | { |
117 | 1390 | std::string const& appname = uri.substr(15); | 1397 | std::string const& appname = uri.substr(RESULT_RUNNER_PREFIX.size()); |
118 | 1391 | return application_starter_->Launch(appname, last_activated_timestamp_); | 1398 | return application_starter_->Launch(appname, last_activated_timestamp_); |
119 | 1399 | } | ||
120 | 1400 | else if (uri.find(RESULT_DIRECTORY_PREFIX) == 0) | ||
121 | 1401 | { | ||
122 | 1402 | std::string const& directory = uri.substr(RESULT_DIRECTORY_PREFIX.size()); | ||
123 | 1403 | return file_manager_->Open(directory, last_activated_timestamp_); | ||
124 | 1392 | } | 1404 | } |
125 | 1393 | else | 1405 | else |
127 | 1394 | return gtk_show_uri(NULL, uri.c_str(), last_activated_timestamp_, NULL); | 1406 | { |
128 | 1407 | return file_manager_->Launch(uri, last_activated_timestamp_); | ||
129 | 1408 | } | ||
130 | 1395 | 1409 | ||
131 | 1396 | return false; | 1410 | return false; |
132 | 1397 | } | 1411 | } |
133 | 1398 | 1412 | ||
134 | === modified file 'dash/DashView.h' | |||
135 | --- dash/DashView.h 2013-04-10 18:26:42 +0000 | |||
136 | +++ dash/DashView.h 2013-05-02 01:34:26 +0000 | |||
137 | @@ -37,6 +37,7 @@ | |||
138 | 37 | 37 | ||
139 | 38 | #include "unity-shared/BackgroundEffectHelper.h" | 38 | #include "unity-shared/BackgroundEffectHelper.h" |
140 | 39 | #include "unity-shared/BGHash.h" | 39 | #include "unity-shared/BGHash.h" |
141 | 40 | #include "unity-shared/FileManager.h" | ||
142 | 40 | #include "unity-shared/Introspectable.h" | 41 | #include "unity-shared/Introspectable.h" |
143 | 41 | #include "unity-shared/OverlayRenderer.h" | 42 | #include "unity-shared/OverlayRenderer.h" |
144 | 42 | #include "unity-shared/SearchBar.h" | 43 | #include "unity-shared/SearchBar.h" |
145 | @@ -59,7 +60,9 @@ | |||
146 | 59 | typedef std::map<std::string, nux::ObjectPtr<LensView>> LensViews; | 60 | typedef std::map<std::string, nux::ObjectPtr<LensView>> LensViews; |
147 | 60 | 61 | ||
148 | 61 | public: | 62 | public: |
150 | 62 | DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& application_starter); | 63 | DashView(Lenses::Ptr const& lenses, |
151 | 64 | ApplicationStarter::Ptr const& application_starter = nullptr, | ||
152 | 65 | FileManager::Ptr const& file_manager = nullptr); | ||
153 | 63 | ~DashView(); | 66 | ~DashView(); |
154 | 64 | 67 | ||
155 | 65 | void AboutToShow(); | 68 | void AboutToShow(); |
156 | @@ -139,6 +142,7 @@ | |||
157 | 139 | LensViews lens_views_; | 142 | LensViews lens_views_; |
158 | 140 | 143 | ||
159 | 141 | ApplicationStarter::Ptr application_starter_; | 144 | ApplicationStarter::Ptr application_starter_; |
160 | 145 | FileManager::Ptr file_manager_; | ||
161 | 142 | 146 | ||
162 | 143 | // View related | 147 | // View related |
163 | 144 | PreviewStateMachine preview_state_machine_; | 148 | PreviewStateMachine preview_state_machine_; |
164 | 145 | 149 | ||
165 | === modified file 'dash/StandaloneDash.cpp' | |||
166 | --- dash/StandaloneDash.cpp 2013-03-12 15:21:19 +0000 | |||
167 | +++ dash/StandaloneDash.cpp 2013-05-02 01:34:26 +0000 | |||
168 | @@ -28,7 +28,6 @@ | |||
169 | 28 | #include <NuxCore/AnimationController.h> | 28 | #include <NuxCore/AnimationController.h> |
170 | 29 | #include <NuxCore/Logger.h> | 29 | #include <NuxCore/Logger.h> |
171 | 30 | 30 | ||
172 | 31 | #include "ApplicationStarterImp.h" | ||
173 | 32 | #include "unity-shared/BGHash.h" | 31 | #include "unity-shared/BGHash.h" |
174 | 33 | #include "unity-shared/FontSettings.h" | 32 | #include "unity-shared/FontSettings.h" |
175 | 34 | #include "DashView.h" | 33 | #include "DashView.h" |
176 | @@ -65,8 +64,7 @@ | |||
177 | 65 | { | 64 | { |
178 | 66 | layout = new nux::HLayout(NUX_TRACKER_LOCATION); | 65 | layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
179 | 67 | 66 | ||
182 | 68 | DashView* view = new DashView(std::make_shared<unity::dash::FilesystemLenses>(), | 67 | DashView* view = new DashView(std::make_shared<unity::dash::FilesystemLenses>()); |
181 | 69 | std::make_shared<unity::ApplicationStarterImp>()); | ||
183 | 70 | view->DisableBlur(); | 68 | view->DisableBlur(); |
184 | 71 | view->SetMinMaxSize(WIDTH, HEIGHT); | 69 | view->SetMinMaxSize(WIDTH, HEIGHT); |
185 | 72 | layout->AddView (view, 1, nux::MINOR_POSITION_CENTER); | 70 | layout->AddView (view, 1, nux::MINOR_POSITION_CENTER); |
186 | 73 | 71 | ||
187 | === modified file 'tests/test_dash_view.cpp' | |||
188 | --- tests/test_dash_view.cpp 2013-03-12 21:45:58 +0000 | |||
189 | +++ tests/test_dash_view.cpp 2013-05-02 01:34:26 +0000 | |||
190 | @@ -20,11 +20,11 @@ | |||
191 | 20 | 20 | ||
192 | 21 | #include <UnityCore/Lenses.h> | 21 | #include <UnityCore/Lenses.h> |
193 | 22 | 22 | ||
194 | 23 | #include "ApplicationStarter.h" | ||
195 | 24 | #include "DashView.h" | 23 | #include "DashView.h" |
196 | 25 | #include "unity-shared/DashStyle.h" | 24 | #include "unity-shared/DashStyle.h" |
197 | 26 | #include "unity-shared/PanelStyle.h" | 25 | #include "unity-shared/PanelStyle.h" |
198 | 27 | #include "unity-shared/UnitySettings.h" | 26 | #include "unity-shared/UnitySettings.h" |
199 | 27 | #include "test_mock_filemanager.h" | ||
200 | 28 | 28 | ||
201 | 29 | #include "mock-lenses.h" | 29 | #include "mock-lenses.h" |
202 | 30 | 30 | ||
203 | @@ -43,7 +43,8 @@ | |||
204 | 43 | TestDashView() | 43 | TestDashView() |
205 | 44 | : lenses_(std::make_shared<testmocks::ThreeMockTestLenses>()) | 44 | : lenses_(std::make_shared<testmocks::ThreeMockTestLenses>()) |
206 | 45 | , application_starter_(std::make_shared<MockApplicationStarter>()) | 45 | , application_starter_(std::make_shared<MockApplicationStarter>()) |
208 | 46 | , dash_view_(new DashView(lenses_, application_starter_)) | 46 | , file_manager_(std::make_shared<NiceMock<unity::MockFileManager>>()) |
209 | 47 | , dash_view_(new DashView(lenses_, application_starter_, file_manager_)) | ||
210 | 47 | {} | 48 | {} |
211 | 48 | 49 | ||
212 | 49 | unity::Settings unity_settings_; | 50 | unity::Settings unity_settings_; |
213 | @@ -51,11 +52,12 @@ | |||
214 | 51 | unity::panel::Style panel_style; | 52 | unity::panel::Style panel_style; |
215 | 52 | Lenses::Ptr lenses_; | 53 | Lenses::Ptr lenses_; |
216 | 53 | MockApplicationStarter::Ptr application_starter_; | 54 | MockApplicationStarter::Ptr application_starter_; |
217 | 55 | unity::MockFileManager::Ptr file_manager_; | ||
218 | 54 | nux::ObjectPtr<DashView> dash_view_; | 56 | nux::ObjectPtr<DashView> dash_view_; |
219 | 55 | }; | 57 | }; |
220 | 56 | 58 | ||
221 | 57 | 59 | ||
223 | 58 | TEST_F(TestDashView, LensActivatedSignal) | 60 | TEST_F(TestDashView, LensActivatedApplication) |
224 | 59 | { | 61 | { |
225 | 60 | EXPECT_CALL(*application_starter_, Launch("uri", _)).Times(1); | 62 | EXPECT_CALL(*application_starter_, Launch("uri", _)).Times(1); |
226 | 61 | lenses_->GetLensAtIndex(0)->activated.emit("0xaabbcc:application://uri", NOT_HANDLED, Lens::Hints()); | 63 | lenses_->GetLensAtIndex(0)->activated.emit("0xaabbcc:application://uri", NOT_HANDLED, Lens::Hints()); |
227 | @@ -64,4 +66,16 @@ | |||
228 | 64 | lenses_->GetLensAtIndex(0)->activated.emit("0xaabbcc:unity-runner://uri", NOT_HANDLED, Lens::Hints()); | 66 | lenses_->GetLensAtIndex(0)->activated.emit("0xaabbcc:unity-runner://uri", NOT_HANDLED, Lens::Hints()); |
229 | 65 | } | 67 | } |
230 | 66 | 68 | ||
231 | 69 | TEST_F(TestDashView, LensActivatedDirectory) | ||
232 | 70 | { | ||
233 | 71 | EXPECT_CALL(*file_manager_, Open("file:///dir/file.ext", _)); | ||
234 | 72 | lenses_->GetLensAtIndex(0)->activated.emit("goto-uri:directory://file:///dir/file.ext", NOT_HANDLED, Lens::Hints()); | ||
235 | 73 | } | ||
236 | 74 | |||
237 | 75 | TEST_F(TestDashView, LensActivatedAny) | ||
238 | 76 | { | ||
239 | 77 | EXPECT_CALL(*file_manager_, Launch("file:///dir/file.ext", _)); | ||
240 | 78 | lenses_->GetLensAtIndex(0)->activated.emit("0xdeadbeef:file:///dir/file.ext", NOT_HANDLED, Lens::Hints()); | ||
241 | 79 | } | ||
242 | 80 | |||
243 | 67 | } | 81 | } |
244 | 68 | 82 | ||
245 | === modified file 'tests/test_lens.cpp' | |||
246 | --- tests/test_lens.cpp 2013-03-04 11:31:36 +0000 | |||
247 | +++ tests/test_lens.cpp 2013-05-02 01:34:26 +0000 | |||
248 | @@ -1,4 +1,3 @@ | |||
249 | 1 | #include <boost/lexical_cast.hpp> | ||
250 | 2 | #include <gtest/gtest.h> | 1 | #include <gtest/gtest.h> |
251 | 3 | #include <glib-object.h> | 2 | #include <glib-object.h> |
252 | 4 | 3 | ||
253 | @@ -66,13 +65,13 @@ | |||
254 | 66 | ASSERT_EQ(model->count(), n_rows); | 65 | ASSERT_EQ(model->count(), n_rows); |
255 | 67 | } | 66 | } |
256 | 68 | 67 | ||
258 | 69 | std::string PopulateAndGetFirstResultURI() | 68 | std::string PopulateAndGetFirstResultURI(bool redirect = false) |
259 | 70 | { | 69 | { |
260 | 71 | Results::Ptr results = lens_->results; | 70 | Results::Ptr results = lens_->results; |
261 | 72 | 71 | ||
263 | 73 | lens_->Search("Test Search String", nullptr); | 72 | lens_->Search(redirect ? "redirect" : "Test Search String", nullptr); |
264 | 74 | WaitForModel<Result>(results.get(), 5); | 73 | WaitForModel<Result>(results.get(), 5); |
266 | 75 | 74 | ||
267 | 76 | Result result = results->RowAtIndex(0); | 75 | Result result = results->RowAtIndex(0); |
268 | 77 | return result.uri; | 76 | return result.uri; |
269 | 78 | } | 77 | } |
270 | @@ -134,18 +133,18 @@ | |||
271 | 134 | 133 | ||
272 | 135 | for (unsigned int i = 0; i < 5; i++) | 134 | for (unsigned int i = 0; i < 5; i++) |
273 | 136 | { | 135 | { |
275 | 137 | std::string name("Test Search String" + boost::lexical_cast<std::string>(i)); | 136 | std::string name("Test Search String" + std::to_string(i)); |
276 | 138 | 137 | ||
277 | 139 | Result result = results->RowAtIndex(i); | 138 | Result result = results->RowAtIndex(i); |
278 | 140 | 139 | ||
279 | 141 | std::string uri = result.uri; | 140 | std::string uri = result.uri; |
281 | 142 | EXPECT_TRUE(uri.find("file:///test")); | 141 | EXPECT_TRUE(uri.find("file:///test/"+std::to_string(i))); |
282 | 143 | EXPECT_EQ(result.icon_hint, "gtk-apply"); | 142 | EXPECT_EQ(result.icon_hint, "gtk-apply"); |
283 | 144 | EXPECT_EQ(result.category_index, i); | 143 | EXPECT_EQ(result.category_index, i); |
284 | 145 | EXPECT_EQ(result.mimetype, "text/html"); | 144 | EXPECT_EQ(result.mimetype, "text/html"); |
285 | 146 | EXPECT_EQ(result.name, name); | 145 | EXPECT_EQ(result.name, name); |
286 | 147 | EXPECT_EQ(result.comment, "kamstrup likes ponies"); | 146 | EXPECT_EQ(result.comment, "kamstrup likes ponies"); |
288 | 148 | EXPECT_EQ(result.dnd_uri, "file:///test"); | 147 | EXPECT_EQ(result.dnd_uri, "file:///test/"+std::to_string(i)); |
289 | 149 | } | 148 | } |
290 | 150 | } | 149 | } |
291 | 151 | 150 | ||
292 | @@ -158,18 +157,18 @@ | |||
293 | 158 | 157 | ||
294 | 159 | for (unsigned int i = 0; i < 10; i++) | 158 | for (unsigned int i = 0; i < 10; i++) |
295 | 160 | { | 159 | { |
297 | 161 | std::string name("Test Global Search String" + boost::lexical_cast<std::string>(i)); | 160 | std::string name("Test Global Search String" + std::to_string(i)); |
298 | 162 | 161 | ||
299 | 163 | Result result = results->RowAtIndex(i); | 162 | Result result = results->RowAtIndex(i); |
300 | 164 | 163 | ||
301 | 165 | std::string uri = result.uri; | 164 | std::string uri = result.uri; |
303 | 166 | EXPECT_TRUE(uri.find("file:///test")); | 165 | EXPECT_TRUE(uri.find("file:///test/"+std::to_string(i))); |
304 | 167 | EXPECT_EQ(result.icon_hint, "gtk-apply"); | 166 | EXPECT_EQ(result.icon_hint, "gtk-apply"); |
305 | 168 | EXPECT_EQ(result.category_index, i); | 167 | EXPECT_EQ(result.category_index, i); |
306 | 169 | EXPECT_EQ(result.mimetype, "text/html"); | 168 | EXPECT_EQ(result.mimetype, "text/html"); |
307 | 170 | EXPECT_EQ(result.name, name); | 169 | EXPECT_EQ(result.name, name); |
308 | 171 | EXPECT_EQ(result.comment, "kamstrup likes ponies"); | 170 | EXPECT_EQ(result.comment, "kamstrup likes ponies"); |
310 | 172 | EXPECT_EQ(result.dnd_uri, "file:///test"); | 171 | EXPECT_EQ(result.dnd_uri, "file:///test/"+std::to_string(i)); |
311 | 173 | } | 172 | } |
312 | 174 | } | 173 | } |
313 | 175 | 174 | ||
314 | @@ -193,6 +192,25 @@ | |||
315 | 193 | Utils::WaitUntil(activated); | 192 | Utils::WaitUntil(activated); |
316 | 194 | } | 193 | } |
317 | 195 | 194 | ||
318 | 195 | TEST_F(TestLens, TestActivationRedirect) | ||
319 | 196 | { | ||
320 | 197 | std::string uri = PopulateAndGetFirstResultURI(true); | ||
321 | 198 | |||
322 | 199 | bool activated = false; | ||
323 | 200 | auto activated_cb = [&activated, &uri] (std::string const& uri_, | ||
324 | 201 | HandledType handled, | ||
325 | 202 | Lens::Hints const& hints) | ||
326 | 203 | { | ||
327 | 204 | EXPECT_EQ(uri_, "goto-uri:"+uri.substr(uri.find(":")+1)); | ||
328 | 205 | EXPECT_EQ(handled, HandledType::HIDE_DASH); | ||
329 | 206 | activated = true; | ||
330 | 207 | }; | ||
331 | 208 | lens_->activated.connect(activated_cb); | ||
332 | 209 | |||
333 | 210 | lens_->Activate(uri); | ||
334 | 211 | Utils::WaitUntil(activated); | ||
335 | 212 | } | ||
336 | 213 | |||
337 | 196 | TEST_F(TestLens, TestPreview) | 214 | TEST_F(TestLens, TestPreview) |
338 | 197 | { | 215 | { |
339 | 198 | std::string uri = PopulateAndGetFirstResultURI(); | 216 | std::string uri = PopulateAndGetFirstResultURI(); |
340 | 199 | 217 | ||
341 | === modified file 'tests/test_mock_filemanager.h' | |||
342 | --- tests/test_mock_filemanager.h 2013-03-29 17:44:12 +0000 | |||
343 | +++ tests/test_mock_filemanager.h 2013-05-02 01:34:26 +0000 | |||
344 | @@ -29,9 +29,10 @@ | |||
345 | 29 | { | 29 | { |
346 | 30 | typedef std::shared_ptr<MockFileManager> Ptr; | 30 | typedef std::shared_ptr<MockFileManager> Ptr; |
347 | 31 | 31 | ||
351 | 32 | MOCK_METHOD2(Open, void(std::string const& uri, unsigned long long time)); | 32 | MOCK_METHOD2(Open, bool(std::string const& uri, unsigned long long time)); |
352 | 33 | MOCK_METHOD2(OpenActiveChild, void(std::string const& uri, unsigned long long time)); | 33 | MOCK_METHOD2(OpenActiveChild, bool(std::string const& uri, unsigned long long time)); |
353 | 34 | MOCK_METHOD1(OpenTrash, void(unsigned long long time)); | 34 | MOCK_METHOD1(OpenTrash, bool(unsigned long long time)); |
354 | 35 | MOCK_METHOD2(Launch, bool(std::string const& uri, unsigned long long time)); | ||
355 | 35 | MOCK_METHOD1(EmptyTrash, void(unsigned long long time)); | 36 | MOCK_METHOD1(EmptyTrash, void(unsigned long long time)); |
356 | 36 | MOCK_CONST_METHOD0(OpenedLocations, std::vector<std::string>()); | 37 | MOCK_CONST_METHOD0(OpenedLocations, std::vector<std::string>()); |
357 | 37 | MOCK_CONST_METHOD1(IsPrefixOpened, bool(std::string const& uri)); | 38 | MOCK_CONST_METHOD1(IsPrefixOpened, bool(std::string const& uri)); |
358 | 38 | 39 | ||
359 | === modified file 'tests/test_service_lens.cpp' | |||
360 | --- tests/test_service_lens.cpp 2013-03-04 11:31:36 +0000 | |||
361 | +++ tests/test_service_lens.cpp 2013-05-02 01:34:26 +0000 | |||
362 | @@ -118,21 +118,22 @@ | |||
363 | 118 | int num_items = search_type == UNITY_SEARCH_TYPE_GLOBAL ? 10 : 5; | 118 | int num_items = search_type == UNITY_SEARCH_TYPE_GLOBAL ? 10 : 5; |
364 | 119 | 119 | ||
365 | 120 | DeeModel* model = (DeeModel*)unity_lens_search_get_results_model(search); | 120 | DeeModel* model = (DeeModel*)unity_lens_search_get_results_model(search); |
366 | 121 | bool redirect = (g_strcmp0(unity_lens_search_get_search_string(search), "redirect") == 0); | ||
367 | 122 | |||
368 | 123 | dee_model_clear(model); | ||
369 | 121 | 124 | ||
370 | 122 | for (i = 0; i < num_items; i++) | 125 | for (i = 0; i < num_items; i++) |
371 | 123 | { | 126 | { |
375 | 124 | gchar* name = g_strdup_printf("%s%d", | 127 | std::string name = unity_lens_search_get_search_string(search) + std::to_string(i); |
376 | 125 | unity_lens_search_get_search_string(search), | 128 | std::string uri = (redirect ? "file:///test/redirect/" : "file:///test/") + std::to_string(i); |
374 | 126 | i); | ||
377 | 127 | dee_model_append(model, | 129 | dee_model_append(model, |
379 | 128 | "file:///test", | 130 | uri.c_str(), |
380 | 129 | "gtk-apply", | 131 | "gtk-apply", |
381 | 130 | i, | 132 | i, |
382 | 131 | "text/html", | 133 | "text/html", |
384 | 132 | name, | 134 | name.c_str(), |
385 | 133 | "kamstrup likes ponies", | 135 | "kamstrup likes ponies", |
388 | 134 | "file:///test"); | 136 | uri.c_str()); |
387 | 135 | g_free(name); | ||
389 | 136 | } | 137 | } |
390 | 137 | 138 | ||
391 | 138 | unity_lens_search_finished (search); | 139 | unity_lens_search_finished (search); |
392 | @@ -140,11 +141,17 @@ | |||
393 | 140 | 141 | ||
394 | 141 | static UnityActivationResponse* on_activate_uri(UnityScope* scope, const char* uri, Lens* self) | 142 | static UnityActivationResponse* on_activate_uri(UnityScope* scope, const char* uri, Lens* self) |
395 | 142 | { | 143 | { |
396 | 144 | if (strstr(uri, "/redirect/")) | ||
397 | 145 | return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, uri); | ||
398 | 146 | |||
399 | 143 | return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, ""); | 147 | return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, ""); |
400 | 144 | } | 148 | } |
401 | 145 | 149 | ||
402 | 146 | static UnityActivationResponse* preview_action_activated(UnityPreviewAction* action, const char* uri) | 150 | static UnityActivationResponse* preview_action_activated(UnityPreviewAction* action, const char* uri) |
403 | 147 | { | 151 | { |
404 | 152 | if (strstr(uri, "/redirect/")) | ||
405 | 153 | return unity_activation_response_new(UNITY_HANDLED_TYPE_HIDE_DASH, uri); | ||
406 | 154 | |||
407 | 148 | return unity_activation_response_new(UNITY_HANDLED_TYPE_SHOW_DASH, ""); | 155 | return unity_activation_response_new(UNITY_HANDLED_TYPE_SHOW_DASH, ""); |
408 | 149 | } | 156 | } |
409 | 150 | 157 | ||
410 | 151 | 158 | ||
411 | === modified file 'unity-shared/FileManager.h' | |||
412 | --- unity-shared/FileManager.h 2013-04-10 22:13:44 +0000 | |||
413 | +++ unity-shared/FileManager.h 2013-05-02 01:34:26 +0000 | |||
414 | @@ -37,13 +37,17 @@ | |||
415 | 37 | FileManager() = default; | 37 | FileManager() = default; |
416 | 38 | virtual ~FileManager() {} | 38 | virtual ~FileManager() {} |
417 | 39 | 39 | ||
421 | 40 | virtual void Open(std::string const& uri, unsigned long long timestamp = 0) = 0; | 40 | virtual bool Open(std::string const& uri, unsigned long long timestamp = 0) = 0; |
422 | 41 | virtual void OpenActiveChild(std::string const& uri, unsigned long long timestamp = 0) = 0; | 41 | virtual bool OpenActiveChild(std::string const& uri, unsigned long long timestamp = 0) = 0; |
423 | 42 | virtual void OpenTrash(unsigned long long timestamp) = 0; | 42 | virtual bool OpenTrash(unsigned long long timestamp) = 0; |
424 | 43 | |||
425 | 44 | virtual bool Launch(std::string const& uri, unsigned long long timestamp = 0) = 0; | ||
426 | 45 | |||
427 | 43 | virtual std::vector<std::string> OpenedLocations() const = 0; | 46 | virtual std::vector<std::string> OpenedLocations() const = 0; |
428 | 44 | virtual bool IsPrefixOpened(std::string const& uri) const = 0; | 47 | virtual bool IsPrefixOpened(std::string const& uri) const = 0; |
429 | 45 | virtual bool IsTrashOpened() const = 0; | 48 | virtual bool IsTrashOpened() const = 0; |
430 | 46 | virtual bool IsDeviceOpened() const = 0; | 49 | virtual bool IsDeviceOpened() const = 0; |
431 | 50 | |||
432 | 47 | virtual void EmptyTrash(unsigned long long timestamp = 0) = 0; | 51 | virtual void EmptyTrash(unsigned long long timestamp = 0) = 0; |
433 | 48 | 52 | ||
434 | 49 | sigc::signal<void> locations_changed; | 53 | sigc::signal<void> locations_changed; |
435 | 50 | 54 | ||
436 | === modified file 'unity-shared/GnomeFileManager.cpp' | |||
437 | --- unity-shared/GnomeFileManager.cpp 2013-03-29 17:44:12 +0000 | |||
438 | +++ unity-shared/GnomeFileManager.cpp 2013-05-02 01:34:26 +0000 | |||
439 | @@ -36,6 +36,7 @@ | |||
440 | 36 | const std::string TRASH_URI = "trash:"; | 36 | const std::string TRASH_URI = "trash:"; |
441 | 37 | const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserDataDirectory() + "/Trash/files"; | 37 | const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserDataDirectory() + "/Trash/files"; |
442 | 38 | const std::string DEVICES_PREFIX = "file:///media/" + std::string(g_get_user_name()); | 38 | const std::string DEVICES_PREFIX = "file:///media/" + std::string(g_get_user_name()); |
443 | 39 | const std::string FOLDER_TYPE = "inode/directory"; | ||
444 | 39 | } | 40 | } |
445 | 40 | 41 | ||
446 | 41 | struct GnomeFileManager::Impl | 42 | struct GnomeFileManager::Impl |
447 | @@ -93,6 +94,15 @@ | |||
448 | 93 | return ""; | 94 | return ""; |
449 | 94 | } | 95 | } |
450 | 95 | 96 | ||
451 | 97 | static glib::Object<GAppLaunchContext> GetLaunchContext(long long timestamp) | ||
452 | 98 | { | ||
453 | 99 | GdkDisplay* display = gdk_display_get_default(); | ||
454 | 100 | glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); | ||
455 | 101 | gdk_app_launch_context_set_timestamp(context, timestamp); | ||
456 | 102 | |||
457 | 103 | return glib::object_cast<GAppLaunchContext>(context); | ||
458 | 104 | } | ||
459 | 105 | |||
460 | 96 | GnomeFileManager* parent_; | 106 | GnomeFileManager* parent_; |
461 | 97 | glib::DBusProxy filemanager_proxy_; | 107 | glib::DBusProxy filemanager_proxy_; |
462 | 98 | std::vector<std::string> opened_locations_; | 108 | std::vector<std::string> opened_locations_; |
463 | @@ -112,46 +122,67 @@ | |||
464 | 112 | GnomeFileManager::~GnomeFileManager() | 122 | GnomeFileManager::~GnomeFileManager() |
465 | 113 | {} | 123 | {} |
466 | 114 | 124 | ||
468 | 115 | void GnomeFileManager::Open(std::string const& uri, unsigned long long timestamp) | 125 | bool GnomeFileManager::Launch(std::string const& uri, unsigned long long timestamp) |
469 | 116 | { | 126 | { |
470 | 117 | if (uri.empty()) | 127 | if (uri.empty()) |
471 | 118 | { | 128 | { |
474 | 119 | LOG_ERROR(logger) << "Impossible to open an empty location"; | 129 | LOG_ERROR(logger) << "Impossible to launch the application for an empty location"; |
475 | 120 | return; | 130 | return false; |
476 | 121 | } | 131 | } |
477 | 122 | 132 | ||
478 | 123 | glib::Error error; | 133 | glib::Error error; |
486 | 124 | GdkDisplay* display = gdk_display_get_default(); | 134 | auto const& gcontext = Impl::GetLaunchContext(timestamp); |
480 | 125 | glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); | ||
481 | 126 | |||
482 | 127 | if (timestamp > 0) | ||
483 | 128 | gdk_app_launch_context_set_timestamp(context, timestamp); | ||
484 | 129 | |||
485 | 130 | auto const& gcontext = glib::object_cast<GAppLaunchContext>(context); | ||
487 | 131 | g_app_info_launch_default_for_uri(uri.c_str(), gcontext, &error); | 135 | g_app_info_launch_default_for_uri(uri.c_str(), gcontext, &error); |
488 | 132 | 136 | ||
489 | 133 | if (error) | 137 | if (error) |
490 | 134 | { | 138 | { |
496 | 135 | LOG_ERROR(logger) << "Impossible to open the location: " << error.Message(); | 139 | if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_NOT_MOUNTED)) |
497 | 136 | } | 140 | { |
498 | 137 | } | 141 | /* If the location is not mounted, then we open the file-manager to make |
499 | 138 | 142 | * it mount the requested position */ | |
500 | 139 | void GnomeFileManager::OpenActiveChild(std::string const& uri, unsigned long long timestamp) | 143 | return Open(uri, timestamp); |
501 | 144 | } | ||
502 | 145 | |||
503 | 146 | LOG_ERROR(logger) << "Impossible to launch the location: " << error; | ||
504 | 147 | return false; | ||
505 | 148 | } | ||
506 | 149 | |||
507 | 150 | return true; | ||
508 | 151 | } | ||
509 | 152 | |||
510 | 153 | bool GnomeFileManager::Open(std::string const& uri, unsigned long long timestamp) | ||
511 | 154 | { | ||
512 | 155 | glib::Error error; | ||
513 | 156 | glib::Object<GAppInfo> app_info(g_app_info_get_default_for_type(FOLDER_TYPE.c_str(), TRUE)); | ||
514 | 157 | std::shared_ptr<GList> uris(g_list_append(nullptr, const_cast<char*>(uri.c_str())), g_list_free); | ||
515 | 158 | |||
516 | 159 | g_app_info_launch_uris(app_info, uris.get(), Impl::GetLaunchContext(timestamp), &error); | ||
517 | 160 | |||
518 | 161 | if (error) | ||
519 | 162 | { | ||
520 | 163 | LOG_ERROR(logger) << "Impossible to open the location: " << error; | ||
521 | 164 | return false; | ||
522 | 165 | } | ||
523 | 166 | |||
524 | 167 | return true; | ||
525 | 168 | } | ||
526 | 169 | |||
527 | 170 | bool GnomeFileManager::OpenActiveChild(std::string const& uri, unsigned long long timestamp) | ||
528 | 140 | { | 171 | { |
529 | 141 | auto const& opened = impl_->GetOpenedPrefix(uri); | 172 | auto const& opened = impl_->GetOpenedPrefix(uri); |
530 | 142 | 173 | ||
532 | 143 | Open(opened.empty() ? uri : opened, timestamp); | 174 | return Open(opened.empty() ? uri : opened, timestamp); |
533 | 144 | } | 175 | } |
534 | 145 | 176 | ||
536 | 146 | void GnomeFileManager::OpenTrash(unsigned long long timestamp) | 177 | bool GnomeFileManager::OpenTrash(unsigned long long timestamp) |
537 | 147 | { | 178 | { |
538 | 148 | if (IsPrefixOpened(TRASH_PATH)) | 179 | if (IsPrefixOpened(TRASH_PATH)) |
539 | 149 | { | 180 | { |
541 | 150 | OpenActiveChild(TRASH_PATH, timestamp); | 181 | return OpenActiveChild(TRASH_PATH, timestamp); |
542 | 151 | } | 182 | } |
543 | 152 | else | 183 | else |
544 | 153 | { | 184 | { |
546 | 154 | OpenActiveChild(TRASH_URI, timestamp); | 185 | return OpenActiveChild(TRASH_URI, timestamp); |
547 | 155 | } | 186 | } |
548 | 156 | } | 187 | } |
549 | 157 | 188 | ||
550 | @@ -163,17 +194,11 @@ | |||
551 | 163 | 194 | ||
552 | 164 | if (app_info) | 195 | if (app_info) |
553 | 165 | { | 196 | { |
554 | 166 | GdkDisplay* display = gdk_display_get_default(); | ||
555 | 167 | glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display)); | ||
556 | 168 | |||
557 | 169 | if (timestamp > 0) | ||
558 | 170 | gdk_app_launch_context_set_timestamp(context, timestamp); | ||
559 | 171 | |||
560 | 172 | auto const& gcontext = glib::object_cast<GAppLaunchContext>(context); | ||
561 | 173 | auto proxy = std::make_shared<glib::DBusProxy>("org.gnome.NautilusApplication", | 197 | auto proxy = std::make_shared<glib::DBusProxy>("org.gnome.NautilusApplication", |
562 | 174 | "/org/gnome/NautilusApplication", | 198 | "/org/gnome/NautilusApplication", |
563 | 175 | "org.gtk.Application"); | 199 | "org.gtk.Application"); |
564 | 176 | 200 | ||
565 | 201 | auto const& gcontext = Impl::GetLaunchContext(timestamp); | ||
566 | 177 | glib::String context_string(g_app_launch_context_get_startup_notify_id(gcontext, app_info, nullptr)); | 202 | glib::String context_string(g_app_launch_context_get_startup_notify_id(gcontext, app_info, nullptr)); |
567 | 178 | 203 | ||
568 | 179 | if (context_string && g_utf8_validate(context_string, -1, nullptr)) | 204 | if (context_string && g_utf8_validate(context_string, -1, nullptr)) |
569 | 180 | 205 | ||
570 | === modified file 'unity-shared/GnomeFileManager.h' | |||
571 | --- unity-shared/GnomeFileManager.h 2013-03-29 17:44:12 +0000 | |||
572 | +++ unity-shared/GnomeFileManager.h 2013-05-02 01:34:26 +0000 | |||
573 | @@ -32,15 +32,19 @@ | |||
574 | 32 | static FileManager::Ptr Get(); | 32 | static FileManager::Ptr Get(); |
575 | 33 | ~GnomeFileManager(); | 33 | ~GnomeFileManager(); |
576 | 34 | 34 | ||
581 | 35 | void Open(std::string const& uri, unsigned long long timestamp); | 35 | bool Open(std::string const& uri, unsigned long long timestamp); |
582 | 36 | void OpenActiveChild(std::string const& uri, unsigned long long timestamp); | 36 | bool OpenActiveChild(std::string const& uri, unsigned long long timestamp); |
583 | 37 | void OpenTrash(unsigned long long timestamp); | 37 | bool OpenTrash(unsigned long long timestamp); |
584 | 38 | void EmptyTrash(unsigned long long timestamp); | 38 | |
585 | 39 | bool Launch(std::string const& uri, unsigned long long timestamp); | ||
586 | 40 | |||
587 | 39 | std::vector<std::string> OpenedLocations() const; | 41 | std::vector<std::string> OpenedLocations() const; |
588 | 40 | bool IsPrefixOpened(std::string const& uri) const; | 42 | bool IsPrefixOpened(std::string const& uri) const; |
589 | 41 | bool IsTrashOpened() const; | 43 | bool IsTrashOpened() const; |
590 | 42 | bool IsDeviceOpened() const; | 44 | bool IsDeviceOpened() const; |
591 | 43 | 45 | ||
592 | 46 | void EmptyTrash(unsigned long long timestamp); | ||
593 | 47 | |||
594 | 44 | private: | 48 | private: |
595 | 45 | GnomeFileManager(); | 49 | GnomeFileManager(); |
596 | 46 | void Activate(unsigned long long timestamp); | 50 | void Activate(unsigned long long timestamp); |
PASSED: Continuous integration, rev:3317 jenkins. qa.ubuntu. com/job/ unity-7. 0-ci/6/ jenkins. qa.ubuntu. com/job/ unity-7. 0-raring- amd64-ci/ 6 jenkins. qa.ubuntu. com/job/ unity-7. 0-raring- armhf-ci/ 6 jenkins. qa.ubuntu. com/job/ unity-7. 0-raring- i386-ci/ 7
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-7. 0-ci/6/ rebuild
http://