Merge lp:~nataliabidart/ubuntuone-control-panel/focus into lp:ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 285
Merged at revision: 279
Proposed branch: lp:~nataliabidart/ubuntuone-control-panel/focus
Merge into: lp:ubuntuone-control-panel
Diff against target: 1035 lines (+291/-254)
15 files modified
data/qt/controlpanel.ui (+4/-4)
data/qt/device.ui (+5/-2)
data/qt/device_remote.ui (+0/-50)
data/qt/devices.ui (+9/-3)
data/qt/preferences.ui (+40/-27)
data/qt/ubuntuone.qss (+88/-41)
ubuntuone/controlpanel/gui/qt/device.py (+30/-30)
ubuntuone/controlpanel/gui/qt/devices.py (+6/-21)
ubuntuone/controlpanel/gui/qt/folders.py (+17/-14)
ubuntuone/controlpanel/gui/qt/loadingoverlay.py (+1/-5)
ubuntuone/controlpanel/gui/qt/tests/__init__.py (+1/-0)
ubuntuone/controlpanel/gui/qt/tests/test_device.py (+35/-18)
ubuntuone/controlpanel/gui/qt/tests/test_devices.py (+15/-35)
ubuntuone/controlpanel/gui/qt/tests/test_folders.py (+22/-4)
ubuntuone/controlpanel/gui/tests/__init__.py (+18/-0)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-control-panel/focus
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Diego Sarmentero (community) Approve
Review via email: mp+96654@code.launchpad.net

Commit message

- Apply new specification for tabbing navigation and tabbing style
  (LP: #942020).
- Make the "Explore" buttons for folders be disabled (style-wise) when the folder
  is not synched (LP: #949035).

To post a comment you must log in.
283. By Natalia Bidart

Less changes against trunk.

284. By Natalia Bidart

Restoring hack for tabs.

285. By Natalia Bidart

No need for controlpanel help buttons to be enabled/disabled for the style.

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

+1

review: Approve
Revision history for this message
Roberto Alsina (ralsina) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/qt/controlpanel.ui'
2--- data/qt/controlpanel.ui 2012-03-02 13:53:24 +0000
3+++ data/qt/controlpanel.ui 2012-03-08 21:13:18 +0000
4@@ -329,8 +329,8 @@
5 </property>
6 <property name="maximumSize">
7 <size>
8- <width>16</width>
9- <height>16</height>
10+ <width>20</width>
11+ <height>20</height>
12 </size>
13 </property>
14 <property name="cursor">
15@@ -352,8 +352,8 @@
16 </property>
17 <property name="maximumSize">
18 <size>
19- <width>16</width>
20- <height>16</height>
21+ <width>20</width>
22+ <height>20</height>
23 </size>
24 </property>
25 <property name="cursor">
26
27=== modified file 'data/qt/device.ui'
28--- data/qt/device.ui 2012-02-22 15:35:13 +0000
29+++ data/qt/device.ui 2012-03-08 21:13:18 +0000
30@@ -6,14 +6,17 @@
31 <rect>
32 <x>0</x>
33 <y>0</y>
34- <width>233</width>
35- <height>36</height>
36+ <width>430</width>
37+ <height>27</height>
38 </rect>
39 </property>
40 <property name="windowTitle">
41 <string notr="true">Form</string>
42 </property>
43 <layout class="QHBoxLayout" name="horizontalLayout">
44+ <property name="margin">
45+ <number>0</number>
46+ </property>
47 <item>
48 <widget class="QLabel" name="device_icon_label">
49 <property name="pixmap">
50
51=== removed file 'data/qt/device_remote.ui'
52--- data/qt/device_remote.ui 2012-02-22 14:58:25 +0000
53+++ data/qt/device_remote.ui 1970-01-01 00:00:00 +0000
54@@ -1,50 +0,0 @@
55-<?xml version="1.0" encoding="UTF-8"?>
56-<ui version="4.0">
57- <class>Form</class>
58- <widget class="QWidget" name="Form">
59- <property name="geometry">
60- <rect>
61- <x>0</x>
62- <y>0</y>
63- <width>264</width>
64- <height>45</height>
65- </rect>
66- </property>
67- <property name="windowTitle">
68- <string notr="true">Form</string>
69- </property>
70- <layout class="QHBoxLayout" name="horizontalLayout">
71- <item>
72- <widget class="QLabel" name="device_icon_label">
73- <property name="pixmap">
74- <pixmap resource="images.qrc">:/computer.png</pixmap>
75- </property>
76- </widget>
77- </item>
78- <item>
79- <widget class="QLabel" name="device_name_label">
80- <property name="text">
81- <string notr="true">Non local device</string>
82- </property>
83- </widget>
84- </item>
85- <item>
86- <spacer name="horizontalSpacer">
87- <property name="orientation">
88- <enum>Qt::Horizontal</enum>
89- </property>
90- <property name="sizeHint" stdset="0">
91- <size>
92- <width>217</width>
93- <height>20</height>
94- </size>
95- </property>
96- </spacer>
97- </item>
98- </layout>
99- </widget>
100- <resources>
101- <include location="images.qrc"/>
102- </resources>
103- <connections/>
104-</ui>
105
106=== modified file 'data/qt/devices.ui'
107--- data/qt/devices.ui 2012-03-02 13:53:24 +0000
108+++ data/qt/devices.ui 2012-03-08 21:13:18 +0000
109@@ -21,16 +21,16 @@
110 <number>0</number>
111 </property>
112 <item>
113- <widget class="QGroupBox" name="local_device">
114+ <widget class="QGroupBox" name="local_device_box">
115 <property name="title">
116 <string notr="true">This device</string>
117 </property>
118- <layout class="QVBoxLayout" name="verticalLayout">
119+ <layout class="QVBoxLayout" name="local_device_layout">
120 <property name="margin">
121 <number>0</number>
122 </property>
123 <item>
124- <layout class="QVBoxLayout" name="local_device_box"/>
125+ <widget class="DeviceWidget" name="local_device" native="true"/>
126 </item>
127 </layout>
128 </widget>
129@@ -120,6 +120,12 @@
130 <extends>QPushButton</extends>
131 <header>ubuntuone.controlpanel.gui.qt.gotoweb</header>
132 </customwidget>
133+ <customwidget>
134+ <class>DeviceWidget</class>
135+ <extends>QWidget</extends>
136+ <header>ubuntuone.controlpanel.gui.qt.device</header>
137+ <container>1</container>
138+ </customwidget>
139 </customwidgets>
140 <resources>
141 <include location="images.qrc"/>
142
143=== modified file 'data/qt/preferences.ui'
144--- data/qt/preferences.ui 2012-03-02 19:42:17 +0000
145+++ data/qt/preferences.ui 2012-03-08 21:13:18 +0000
146@@ -6,8 +6,8 @@
147 <rect>
148 <x>0</x>
149 <y>0</y>
150- <width>512</width>
151- <height>328</height>
152+ <width>520</width>
153+ <height>342</height>
154 </rect>
155 </property>
156 <property name="windowTitle">
157@@ -53,14 +53,27 @@
158 </property>
159 </widget>
160 </item>
161- <item row="2" column="0">
162+ <item row="0" column="3">
163+ <spacer name="horizontalSpacer_2">
164+ <property name="orientation">
165+ <enum>Qt::Horizontal</enum>
166+ </property>
167+ <property name="sizeHint" stdset="0">
168+ <size>
169+ <width>40</width>
170+ <height>20</height>
171+ </size>
172+ </property>
173+ </spacer>
174+ </item>
175+ <item row="1" column="0">
176 <widget class="QCheckBox" name="limit_downloads_checkbox">
177 <property name="text">
178 <string notr="true">Limit download speed to</string>
179 </property>
180 </widget>
181 </item>
182- <item row="2" column="1">
183+ <item row="1" column="1">
184 <widget class="QSpinBox" name="download_speed_spinbox">
185 <property name="minimum">
186 <number>-1</number>
187@@ -70,17 +83,17 @@
188 </property>
189 </widget>
190 </item>
191- <item row="2" column="2">
192+ <item row="1" column="2">
193 <widget class="QLabel" name="kbps_label_2">
194 <property name="text">
195 <string notr="true">Kilobits per second</string>
196 </property>
197 </widget>
198 </item>
199- <item row="0" column="3">
200- <spacer name="horizontalSpacer_2">
201+ <item row="2" column="0">
202+ <spacer name="verticalSpacer_2">
203 <property name="orientation">
204- <enum>Qt::Horizontal</enum>
205+ <enum>Qt::Vertical</enum>
206 </property>
207 <property name="sizeHint" stdset="0">
208 <size>
209@@ -90,7 +103,7 @@
210 </property>
211 </spacer>
212 </item>
213- <item row="4" column="0" colspan="3">
214+ <item row="3" column="0" colspan="3">
215 <widget class="QLabel" name="label_2">
216 <property name="text">
217 <string notr="true">Please note that your files will not sync if you set bandwidth to 0</string>
218@@ -103,19 +116,6 @@
219 </property>
220 </widget>
221 </item>
222- <item row="3" column="0">
223- <spacer name="verticalSpacer_2">
224- <property name="orientation">
225- <enum>Qt::Vertical</enum>
226- </property>
227- <property name="sizeHint" stdset="0">
228- <size>
229- <width>40</width>
230- <height>20</height>
231- </size>
232- </property>
233- </spacer>
234- </item>
235 </layout>
236 </widget>
237 </item>
238@@ -124,32 +124,45 @@
239 <property name="title">
240 <string notr="true">File Sync Settings</string>
241 </property>
242- <layout class="QVBoxLayout" name="verticalLayout_1">
243+ <layout class="QGridLayout" name="gridLayout_2">
244 <property name="margin">
245 <number>0</number>
246 </property>
247- <item>
248+ <item row="0" column="0">
249 <widget class="QCheckBox" name="autoconnect_checkbox">
250 <property name="text">
251 <string notr="true">Connect automatically when computer starts</string>
252 </property>
253 </widget>
254 </item>
255- <item>
256+ <item row="0" column="1">
257+ <spacer name="horizontalSpacer_3">
258+ <property name="orientation">
259+ <enum>Qt::Horizontal</enum>
260+ </property>
261+ <property name="sizeHint" stdset="0">
262+ <size>
263+ <width>40</width>
264+ <height>20</height>
265+ </size>
266+ </property>
267+ </spacer>
268+ </item>
269+ <item row="1" column="0">
270 <widget class="QCheckBox" name="udf_autosubscribe_checkbox">
271 <property name="text">
272 <string notr="true">Automatically sync all new cloud folders to this computer</string>
273 </property>
274 </widget>
275 </item>
276- <item>
277+ <item row="2" column="0">
278 <widget class="QCheckBox" name="share_autosubscribe_checkbox">
279 <property name="text">
280 <string notr="true">Automatically sync all folders shared with me to this computer</string>
281 </property>
282 </widget>
283 </item>
284- <item>
285+ <item row="3" column="0">
286 <widget class="QCheckBox" name="show_all_notifications_checkbox">
287 <property name="text">
288 <string notr="true">Allow all notifications to this device</string>
289
290=== modified file 'data/qt/ubuntuone.qss'
291--- data/qt/ubuntuone.qss 2012-03-02 17:33:38 +0000
292+++ data/qt/ubuntuone.qss 2012-03-08 21:13:18 +0000
293@@ -1,3 +1,11 @@
294+/* Common colours:
295+
296+orange: #dd4814
297+dark grey: #333333
298+light grey: #aea79f
299+
300+*/
301+
302 QMainWindow {
303 background-color: #aea79f;
304 }
305@@ -77,6 +85,18 @@
306 border-width: 1px;
307 }
308
309+QPushButton:focus {
310+ border-width: 2px;
311+ /* reduce the padding since we have a 2px border now */
312+ padding: 5px;
313+ padding-left: 19px;
314+ padding-right: 19px;
315+ /* hack to make the mild-orange focused box dissapear */
316+ padding-top: 20px;
317+ padding-bottom: 20px;
318+ /* end of hack */
319+}
320+
321 QPushButton:disabled {
322 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
323 stop: 0 #eaeaea, stop: 1.0 #cacaca);
324@@ -91,19 +111,18 @@
325 border-color: #999999;
326 }
327
328-QPushButton:enabled:focus,
329+QPushButton:enabled:focus {
330+ border-color: #dd4814;
331+}
332+
333 QPushButton:enabled:hover {
334 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
335 stop: 0 #ffffff,stop: 1.0 #ededed);
336- color: #333333;
337- border-color: #999999;
338 }
339
340 QPushButton:enabled:pressed {
341 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
342 stop: 0 #d9d9d9,stop: 1.0 #fefefe);
343- color: #333333;
344- border-color: #999999;
345 }
346
347 QPushButton:default:enabled {
348@@ -113,55 +132,69 @@
349 border-color: #999999;
350 }
351
352-QPushButton:default:enabled:focus,
353+QPushButton:default:enabled:focus {
354+ border-color: #333333;
355+}
356+
357 QPushButton:default:enabled:hover {
358 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
359 stop: 0 #ffb19c,stop: 1.0 #dd4814);
360- color: white;
361- border-color: #999999;
362 }
363
364 QPushButton:default:enabled:pressed {
365 background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
366 stop: 0 #b93f14,stop: 1.0 #dd4814);
367- color: white;
368- border-color: #999999;
369-}
370-
371-QPushButton#help_button {
372- background: transparent;
373- border: none;
374- color: white;
375- text-decoration: underline;
376- padding: 0px;
377-}
378-
379-QPushButton#explore_folder_button {
380- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
381- stop: 0 #fbfbfb, stop: 1.0 #e6e6e6);
382- height: 15px;
383- border-radius: 7px;
384- border-color: #908e8d;
385- color: #595959;
386- padding-left: 10px;
387- padding-right: 10px;
388+}
389+
390+ExploreFolderButton {
391 margin-top: 5px;
392 margin-bottom: 5px;
393 margin-right: 20px;
394 margin-left: 20px;
395 }
396
397+ExploreFolderButton:enabled {
398+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
399+ stop: 0 #fbfbfb, stop: 1.0 #e6e6e6);
400+ border-color: #908e8d;
401+ color: #595959;
402+}
403+
404 QPushButton#twitter_button,
405 QPushButton#facebook_button {
406+ background: transparent;
407+}
408+
409+QPushButton#twitter_button:focus,
410+QPushButton#facebook_button:focus {
411+ border: 2px solid #dd4814;
412+}
413+
414+GoToWebButton#help_button {
415+ padding: 2px;
416+}
417+
418+GoToWebButton#share_publish_button,
419+GoToWebButton#help_button {
420+ background: transparent;
421 border: none;
422+ text-decoration: underline;
423 }
424
425-GoToWebButton#forgot_password_button,
426 GoToWebButton#share_publish_button {
427- background: transparent;
428- border: none;
429 color: #dd4814;
430- text-decoration: underline;
431+}
432+
433+GoToWebButton#help_button {
434+ color: white;
435+}
436+
437+GoToWebButton#share_publish_button:focus {
438+ border: 2px solid #aea79f;
439+}
440+
441+GoToWebButton#help_button:focus {
442+ border: 2px solid #dd4814;
443 }
444
445 QTabBar::tab {
446@@ -192,12 +225,7 @@
447 border-width: 1px;
448 }
449
450-QTabBar::tab:first:!selected {
451- border-left-color: #939389;
452- border-left-color: #939389;
453-}
454-
455-QTabBar::tab:first:selected {
456+QTabBar::tab:first {
457 border-left-color: #939389;
458 }
459
460@@ -205,13 +233,21 @@
461 border-left-color: #e4e0dd;
462 }
463
464+QTabBar::tab:last:!selected {
465+ border-left-color: #e4e0dd;
466+}
467+
468 QTabBar::tab:hover {
469 background: #f6f6f6;
470 text-decoration: underline;
471 }
472
473-QTabBar::tab:last:!selected {
474- border-left-color: #e4e0dd;
475+QTabBar::tab:focus {
476+ text-decoration: underline;
477+ /* hack to make the mild-orange focused box dissapear */
478+ padding-left: 1000px;
479+ padding-right: 1000px;
480+ /* end of hack */
481 }
482
483 QTabWidget {
484@@ -259,6 +295,12 @@
485 min-height: 48px;
486 }
487
488+QGroupBox#local_device_box,
489+QListWidget#list_devices::item {
490+ padding-left: 9px;
491+ padding-right: 9px;
492+}
493+
494 QLabel[OverQuota="false"] {
495 color: #333333;
496 }
497@@ -301,3 +343,8 @@
498 alternate-background-color: #f7f6f5;
499 background: #efedec;
500 }
501+
502+QCheckBox:focus {
503+ border-radius: 5px;
504+ border: 2px solid #dd4814;
505+}
506
507=== modified file 'ubuntuone/controlpanel/gui/qt/device.py'
508--- ubuntuone/controlpanel/gui/qt/device.py 2012-02-22 17:04:28 +0000
509+++ ubuntuone/controlpanel/gui/qt/device.py 2012-03-08 21:13:18 +0000
510@@ -34,7 +34,7 @@
511 handle_errors,
512 pixmap_from_name,
513 )
514-from ubuntuone.controlpanel.gui.qt.ui import device_ui, device_remote_ui
515+from ubuntuone.controlpanel.gui.qt.ui import device_ui
516 from ubuntuone.controlpanel.logger import setup_logging
517
518 COMPUTER_ICON = "computer"
519@@ -61,27 +61,35 @@
520
521
522 class DeviceWidget(cache.Cache, QtGui.QWidget):
523- """The widget for each device in the control panel."""
524+ """The widget for a local device in the control panel."""
525
526 removed = QtCore.pyqtSignal()
527 removeCanceled = QtCore.pyqtSignal()
528
529- def __init__(self, device_id, *args, **kwargs):
530+ def __init__(self, device_id=None, *args, **kwargs):
531 """Initialize the UI of the widget."""
532 super(DeviceWidget, self).__init__(*args, **kwargs)
533 self.ui = device_ui.Ui_Form()
534 self.ui.setupUi(self)
535
536- # The following is a hack to avoid having the faked self.ui failing
537- # with AttributeError in the tests. We need to improve the fake so we
538- # don't leak this to the production code.
539- if getattr(self.ui, 'remove_device_button', None) is not None:
540- self.ui.remove_device_button.setText(REMOVE_BUTTON)
541-
542+ self.ui.remove_device_button.setText(REMOVE_BUTTON)
543+ self._id = None
544 self.id = device_id
545
546+ def _get_id(self):
547+ """Return this device's id."""
548+ return self._id
549+
550+ def _set_id(self, new_id):
551+ """Set this device's id."""
552+ self._id = new_id
553+ self.ui.remove_device_button.setEnabled(self._id is not None)
554+
555+ id = property(fget=_get_id, fset=_set_id)
556+
557 def update_device_info(self, device_info):
558 """Update the device info."""
559+ self.id = device_info["device_id"]
560 self.ui.device_name_label.setText(device_info["name"])
561 icon_name = icon_name_from_type(device_info["type"])
562 pixmap = pixmap_from_name(icon_name)
563@@ -102,28 +110,20 @@
564 else:
565 self.removeCanceled.emit()
566
567-
568-class DeviceRemoteWidget(QtGui.QWidget):
569-
570- """Remote Device widget for Devices List."""
571-
572- def __init__(self, device_info):
573- super(DeviceRemoteWidget, self).__init__()
574- self.ui = device_remote_ui.Ui_Form()
575- self.ui.setupUi(self)
576-
577- text = device_info["name"]
578- icon_name = icon_name_from_type(device_info["type"])
579- pixmap = pixmap_from_name(icon_name)
580- self.ui.device_icon_label.setPixmap(pixmap)
581- self.ui.device_name_label.setText(text)
582-
583 def text(self):
584 """Return the text displayed in the Widget."""
585 return self.ui.device_name_label.text()
586
587-
588-def get_device_for_list_widget(device_info):
589- """Return a DeviceRemoteWidget with device proper info."""
590- item = DeviceRemoteWidget(device_info)
591- return item
592+ def clear(self):
593+ """Clear this widget's info."""
594+ self.id = None
595+ self.ui.device_name_label.setText('')
596+
597+
598+class RemoteDeviceWidget(DeviceWidget):
599+
600+ """Remote device widget."""
601+
602+ def __init__(self, *args, **kwargs):
603+ super(RemoteDeviceWidget, self).__init__(*args, **kwargs)
604+ self.ui.remove_device_button.hide()
605
606=== modified file 'ubuntuone/controlpanel/gui/qt/devices.py'
607--- ubuntuone/controlpanel/gui/qt/devices.py 2012-02-22 15:35:13 +0000
608+++ ubuntuone/controlpanel/gui/qt/devices.py 2012-03-08 21:13:18 +0000
609@@ -50,7 +50,7 @@
610 def _setup(self):
611 """Do some extra setupping for the UI."""
612 super(DevicesPanel, self)._setup()
613- self.ui.local_device.setTitle(DEVICES_LOCAL_LABEL)
614+ self.ui.local_device_box.setTitle(DEVICES_LOCAL_LABEL)
615 self.ui.other_devices.setTitle(DEVICES_REMOTE_LABEL)
616 self.ui.manage_devices_button.setText(DEVICES_MANAGE_LABEL)
617 self.ui.manage_devices_button.uri = EDIT_DEVICES_LINK
618@@ -66,7 +66,6 @@
619 @log_call(logger.debug)
620 def process_info(self, info):
621 """Process and display the devices info."""
622- self.clear_device_info(self.ui.local_device_box)
623 self.ui.list_devices.clear()
624
625 for device_info in info:
626@@ -76,21 +75,9 @@
627
628 def on_local_device_removed(self):
629 """When the local device is removed, clear the box and emit signal."""
630- self.clear_device_info(self.ui.local_device_box)
631+ self.ui.local_device.clear()
632 self.localDeviceRemoved.emit()
633
634- def clear_device_info(self, box):
635- """Clear all the device info."""
636- children = box.count()
637- # we need to reverse the index list to remove children because:
638- # "Items are numbered consecutively from 0. If an item is deleted,
639- # other items will be renumbered."
640- # http://doc.qt.nokia.com/latest/qlayout.html#itemAt
641- for i in reversed(range(children)):
642- widget = box.itemAt(i).widget()
643- box.removeWidget(widget)
644- widget.deleteLater()
645-
646 def update_device_info(self, device_info):
647 """Update one device."""
648 if device_info["is_local"]:
649@@ -100,15 +87,13 @@
650
651 def update_local_device(self, device_info):
652 """Update the info for the local device."""
653- device_widget = device.DeviceWidget(device_id=device_info['device_id'])
654- device_widget.update_device_info(device_info)
655- device_widget.removed.connect(self.on_local_device_removed)
656-
657- self.ui.local_device_box.addWidget(device_widget)
658+ self.ui.local_device.update_device_info(device_info)
659+ self.ui.local_device.removed.connect(self.on_local_device_removed)
660
661 def create_remote_device(self, device_info):
662 """Add a remote device to the list."""
663- widget = device.get_device_for_list_widget(device_info)
664+ widget = device.RemoteDeviceWidget()
665+ widget.update_device_info(device_info)
666 item = QtGui.QListWidgetItem()
667
668 self.ui.list_devices.addItem(item)
669
670=== modified file 'ubuntuone/controlpanel/gui/qt/folders.py'
671--- ubuntuone/controlpanel/gui/qt/folders.py 2012-02-28 17:48:23 +0000
672+++ ubuntuone/controlpanel/gui/qt/folders.py 2012-03-08 21:13:18 +0000
673@@ -61,6 +61,21 @@
674 YES = QtGui.QMessageBox.Yes
675
676
677+class ExploreFolderButton(QtGui.QPushButton):
678+ """A specialized button for the folder listing."""
679+
680+ def __init__(self, folder_path, parent=None):
681+ super(ExploreFolderButton, self).__init__(parent=parent)
682+ self.folder_path = folder_path
683+ self.setText(FOLDERS_COLUMN_EXPLORE)
684+ self.clicked.connect(self.on_clicked)
685+
686+ def on_clicked(self):
687+ """Open the folder_path in the default file manager."""
688+ uri = unicode(QtCore.QUrl.fromLocalFile(self.folder_path).toString())
689+ uri_hook(uri)
690+
691+
692 class FoldersPanel(UbuntuOneBin):
693 """The Folders Tab Panel widget"""
694
695@@ -180,21 +195,9 @@
696
697 # attach a third item with a button to explore the folder
698 model_index = self.ui.folders.indexFromItem(child, EXPLORE_COL)
699- button = QtGui.QPushButton(parent=self.ui.folders)
700- button.setFlat(True)
701- button.setText(FOLDERS_COLUMN_EXPLORE)
702- button.setObjectName('explore_folder_button')
703- policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
704- QtGui.QSizePolicy.Fixed)
705- button.setSizePolicy(policy)
706+ button = ExploreFolderButton(folder_path=child.volume_path,
707+ parent=self.ui.folders)
708 button.setEnabled(bool(volume[u'subscribed']))
709-
710- # Operator not preceded by a space
711- # pylint: disable=C0322
712- cb = lambda checked, item=child: \
713- self.on_folders_itemActivated(item)
714- # pylint: enable=C0322
715- button.clicked.connect(cb)
716 self.ui.folders.setIndexWidget(model_index, button)
717
718 self.ui.folders.expandAll()
719
720=== modified file 'ubuntuone/controlpanel/gui/qt/loadingoverlay.py'
721--- ubuntuone/controlpanel/gui/qt/loadingoverlay.py 2012-02-22 17:04:28 +0000
722+++ ubuntuone/controlpanel/gui/qt/loadingoverlay.py 2012-03-08 21:13:18 +0000
723@@ -45,11 +45,7 @@
724 self.counter = 0
725 self.orientation = False
726
727- # The following is a hack to avoid having the faked self.ui failing
728- # with AttributeError in the tests. We need to improve the fake so we
729- # don't leak this to the production code.
730- if getattr(self.ui, 'label', None) is not None:
731- self.ui.label.setText(LOADING_OVERLAY)
732+ self.ui.label.setText(LOADING_OVERLAY)
733
734 # Invalid name "paintEvent"
735 # pylint: disable=C0103
736
737=== modified file 'ubuntuone/controlpanel/gui/qt/tests/__init__.py'
738--- ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-03-02 13:53:24 +0000
739+++ ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-03-08 21:13:18 +0000
740@@ -96,6 +96,7 @@
741 """A fake Ui object."""
742
743 exposed_methods = ['setupUi']
744+ raise_attr_error = False
745
746
747 class FakedControlPanelBackend(FakedObject):
748
749=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_device.py'
750--- ubuntuone/controlpanel/gui/qt/tests/test_device.py 2012-03-01 22:05:51 +0000
751+++ ubuntuone/controlpanel/gui/qt/tests/test_device.py 2012-03-08 21:13:18 +0000
752@@ -1,8 +1,6 @@
753 # -*- coding: utf-8 -*-
754-
755-# Author: Alejandro J. Cura <alecu@canonical.com>
756 #
757-# Copyright 2011 Canonical Ltd.
758+# Copyright 2011-2012 Canonical Ltd.
759 #
760 # This program is free software: you can redistribute it and/or modify it
761 # under the terms of the GNU General Public License version 3, as published
762@@ -36,7 +34,7 @@
763
764
765 class DeviceWidgetTestCase(BaseTestCase):
766- """Test the qt control panel."""
767+ """Test the DeviceWidget class."""
768
769 innerclass_ui = gui.device_ui
770 innerclass_name = "Ui_Form"
771@@ -46,9 +44,28 @@
772 logger = gui.logger
773
774 def test_has_id(self):
775- """The device as an id, None by default."""
776+ """The device as an id accepted as creation param."""
777 self.assertEqual(self.ui.id, self.device_id)
778
779+ def test_id_can_be_none(self):
780+ """The device id is None by default."""
781+ ui = self.class_ui()
782+ self.assertEqual(ui.id, None)
783+
784+ def test_setting_id_to_none_disables_remove_button(self):
785+ """If the id is set to None, the remove button is disabled."""
786+ self.ui.id = None
787+ self.assertFalse(self.ui.ui.remove_device_button.isEnabled())
788+
789+ def test_setting_id_to_not_none_enables_remove_button(self):
790+ """If the id is set to not None, the remove button is enabled."""
791+ self.ui.id = 'not None'
792+ self.assertTrue(self.ui.ui.remove_device_button.isEnabled())
793+
794+ def test_remove_button(self):
795+ """The remove button is visible."""
796+ self.assertTrue(self.ui.ui.remove_device_button.isVisible())
797+
798 def test_update_device_info(self):
799 """The widget is updated with the info."""
800 info = SAMPLE_COMPUTER_INFO
801@@ -68,7 +85,7 @@
802 self.assertIconMatchesType(gui.DEVICE_TYPE_PHONE, gui.PHONE_ICON)
803 self.assertIconMatchesType("other random type", gui.COMPUTER_ICON)
804
805- def _test_update_device_info_sets_right_icon(self, info):
806+ def assert_update_device_info_sets_right_icon(self, info):
807 """The widget is updated with the right icon."""
808 self.ui.update_device_info(info)
809 pixmap_name = gui.icon_name_from_type(info["type"])
810@@ -78,21 +95,11 @@
811
812 def test_update_device_info_sets_computer_icon(self):
813 """The computer icon is set."""
814- self._test_update_device_info_sets_right_icon(SAMPLE_COMPUTER_INFO)
815+ self.assert_update_device_info_sets_right_icon(SAMPLE_COMPUTER_INFO)
816
817 def test_update_device_info_sets_phone_icon(self):
818 """The phone icon is set."""
819- self._test_update_device_info_sets_right_icon(SAMPLE_PHONE_INFO)
820-
821- def test_get_device_for_list_widget(self):
822- """The the item list values returned."""
823- info = SAMPLE_COMPUTER_INFO
824- item = gui.get_device_for_list_widget(info)
825- self.assertEqual(item.text(), info["name"])
826-
827- info = SAMPLE_PHONE_INFO
828- item = gui.get_device_for_list_widget(info)
829- self.assertEqual(item.text(), info["name"])
830+ self.assert_update_device_info_sets_right_icon(SAMPLE_PHONE_INFO)
831
832
833 class RemoveDeviceTestCase(DeviceWidgetTestCase):
834@@ -161,3 +168,13 @@
835 yield self.ui.ui.remove_device_button.click()
836
837 self.assertTrue(self.memento.check_exception(CrashyBackendException))
838+
839+
840+class RemoteDeviceWidgetTestCase(DeviceWidgetTestCase):
841+ """Test the RemoteDeviceWidget class."""
842+
843+ class_ui = gui.RemoteDeviceWidget
844+
845+ def test_remove_button(self):
846+ """The remove button is hidden."""
847+ self.assertFalse(self.ui.ui.remove_device_button.isVisible())
848
849=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_devices.py'
850--- ubuntuone/controlpanel/gui/qt/tests/test_devices.py 2012-03-01 22:05:51 +0000
851+++ ubuntuone/controlpanel/gui/qt/tests/test_devices.py 2012-03-08 21:13:18 +0000
852@@ -1,8 +1,6 @@
853 # -*- coding: utf-8 -*-
854-
855-# Author: Alejandro J. Cura <alecu@canonical.com>
856 #
857-# Copyright 2011 Canonical Ltd.
858+# Copyright 2011-2012 Canonical Ltd.
859 #
860 # This program is free software: you can redistribute it and/or modify it
861 # under the terms of the GNU General Public License version 3, as published
862@@ -63,7 +61,6 @@
863 def test_no_devices_at_startup(self):
864 """The UI is reset at startup."""
865 self.assertEqual(self.ui.ui.list_devices.count(), 0)
866- self.assertEqual(self.ui.ui.local_device_box.count(), 0)
867
868 def test_process_info(self):
869 """The widget is updated with the info."""
870@@ -71,10 +68,8 @@
871
872 local, remote = SAMPLE_DEVICES_INFO[0], SAMPLE_DEVICES_INFO[1:]
873
874- self.assertEqual(self.ui.ui.local_device_box.count(), 1)
875- local_device = self.ui.ui.local_device_box.itemAt(0).widget()
876- self.assertEqual(local_device.ui.device_name_label.text(),
877- local['name'])
878+ local_device = self.ui.ui.local_device
879+ self.assertEqual(local_device.text(), local['name'])
880 self.assertEqual(local_device.id, local['device_id'])
881
882 self.assertEqual(self.ui.ui.list_devices.count(),
883@@ -84,26 +79,12 @@
884 device = self.ui.ui.list_devices.itemWidget(item)
885 self.assertEqual(device.text(), remote_device['name'])
886
887- def test_remove_device_and_check_layout_state(self):
888- """Test if the widget is properly removed."""
889- self.ui.process_info(SAMPLE_DEVICES_INFO)
890- self.ui.show()
891-
892- self.assertEqual(self.ui.ui.local_device_box.count(), 1)
893- local_device = self.ui.ui.local_device_box.itemAt(0).widget()
894- self.executed = False
895-
896- def delete_later(reference=None):
897- """Fake delete later."""
898- self.executed = True
899- self.patch(local_device, "deleteLater", delete_later)
900- self.ui.clear_device_info(self.ui.ui.local_device_box)
901- self.ui.process_info(SAMPLE_DEVICES_INFO)
902- self.assertEqual(self.ui.ui.local_device_box.count(), 1)
903- local_device2 = self.ui.ui.local_device_box.itemAt(0).widget()
904- self.assertNotEqual(local_device, local_device2)
905- self.assertTrue(self.executed)
906- self.assertFalse(local_device.isVisible())
907+ def test_local_device(self):
908+ """Test if the local_device widget is properly packed."""
909+ self.ui.process_info(SAMPLE_DEVICES_INFO)
910+
911+ local_device = self.ui.ui.local_device_layout.itemAt(0).widget()
912+ self.assertIs(local_device, self.ui.ui.local_device)
913
914 def test_process_info_twice(self):
915 """The widget is updated with the info."""
916@@ -115,21 +96,20 @@
917 self.assert_uri_hook_called(self.ui.ui.manage_devices_button,
918 gui.EDIT_DEVICES_LINK)
919
920- def test_remove_device_widget_after_removal(self):
921- """When a device widget was deleted, remove it from the UI."""
922+ def test_local_device_removed_clears_the_widget(self):
923+ """When the local device was deleted, clear it."""
924 self.ui.process_info(SAMPLE_DEVICES_INFO)
925
926- local_device = self.ui.ui.local_device_box.itemAt(0).widget()
927- local_device.removed.emit()
928+ self.ui.ui.local_device.removed.emit()
929
930- self.assertTrue(self.ui.ui.local_device_box.itemAt(0) is None)
931+ self.assertEqual(self.ui.ui.local_device.text(), '')
932+ self.assertEqual(self.ui.ui.local_device.id, None)
933
934 def test_local_device_removed_signal(self):
935 """When the local device is removed, emit localDeviceRemoved signal."""
936 self.ui.localDeviceRemoved.connect(self._set_called)
937 self.ui.process_info(SAMPLE_DEVICES_INFO)
938
939- local_device = self.ui.ui.local_device_box.itemAt(0).widget()
940- local_device.removed.emit()
941+ self.ui.ui.local_device.removed.emit()
942
943 self.assertEqual(self._called, ((), {}))
944
945=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_folders.py'
946--- ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2012-03-02 16:56:10 +0000
947+++ ubuntuone/controlpanel/gui/qt/tests/test_folders.py 2012-03-08 21:13:18 +0000
948@@ -1,8 +1,6 @@
949 # -*- coding: utf-8 -*-
950-
951-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
952 #
953-# Copyright 2011 Canonical Ltd.
954+# Copyright 2011-2012 Canonical Ltd.
955 #
956 # This program is free software: you can redistribute it and/or modify it
957 # under the terms of the GNU General Public License version 3, as published
958@@ -33,6 +31,7 @@
959 )
960 from ubuntuone.controlpanel.gui.qt import folders as gui
961 from ubuntuone.controlpanel.gui.qt.tests import (
962+ BaseTestCase,
963 FakedDialog,
964 )
965 from ubuntuone.controlpanel.gui.qt.tests.test_ubuntuonebin import (
966@@ -54,6 +53,26 @@
967 return name
968
969
970+class ExploreFolderButtonTestCase(BaseTestCase):
971+ """Test the ExploreFolderButton widget."""
972+
973+ class_ui = gui.ExploreFolderButton
974+ kwargs = dict(folder_path=u'foo')
975+
976+ def test_text(self):
977+ """The button text is correct."""
978+ self.assertEqual(self.ui.text(), gui.FOLDERS_COLUMN_EXPLORE)
979+
980+ def test_clicked(self):
981+ """Clicking the button opens the folder in the default file manager."""
982+ self.patch(gui, 'uri_hook', self._set_called)
983+ self.ui.click()
984+
985+ url = gui.QtCore.QUrl.fromLocalFile(self.kwargs['folder_path'])
986+ expected = unicode(url.toString())
987+ self.assertEqual(self._called, ((expected,), {}))
988+
989+
990 class FoldersPanelTestCase(UbuntuOneBinTestCase):
991 """Test the qt cloud folders tab."""
992
993@@ -173,7 +192,6 @@
994 # explore button is in place
995 model_index = folders.indexFromItem(item, gui.EXPLORE_COL)
996 button = folders.indexWidget(model_index)
997- self.assertEqual(button.isFlat(), True)
998 self.assertEqual(button.isEnabled(),
999 bool(volume['subscribed']))
1000
1001
1002=== modified file 'ubuntuone/controlpanel/gui/tests/__init__.py'
1003--- ubuntuone/controlpanel/gui/tests/__init__.py 2012-03-02 21:21:03 +0000
1004+++ ubuntuone/controlpanel/gui/tests/__init__.py 2012-03-08 21:13:18 +0000
1005@@ -134,6 +134,7 @@
1006 next_result = None
1007 exposed_methods = []
1008 exposed_results = {}
1009+ raise_attr_error = True
1010
1011 def __init__(self, *args, **kwargs):
1012 self._args = args
1013@@ -142,6 +143,23 @@
1014 for i in self.exposed_methods:
1015 setattr(self, i, self._record_call(i))
1016
1017+ def __call__(self, *args, **kwargs):
1018+ """Skip."""
1019+
1020+ def __getattribute__(self, attr_name):
1021+ super_getattr = super(FakedObject, self).__getattribute__
1022+
1023+ try:
1024+ result = super_getattr(attr_name)
1025+ except AttributeError:
1026+ if super_getattr('raise_attr_error'):
1027+ raise
1028+ else:
1029+ result = FakedObject()
1030+ result.raise_attr_error = super_getattr('raise_attr_error')
1031+
1032+ return result
1033+
1034 def _record_call(self, func_name):
1035 """Store values when calling 'func_name'."""
1036

Subscribers

People subscribed via source and target branches