Ubuntu One Control Panel

Merge lp:~diegosarmentero/ubuntuone-control-panel/checkwrap into lp:ubuntuone-control-panel

Proposed by Diego Sarmentero on 2012-04-16
Status: Merged
Approved by: Manuel de la Peña on 2012-04-18
Approved revision: 317
Merged at revision: 313
Proposed branch: lp:~diegosarmentero/ubuntuone-control-panel/checkwrap
Merge into: lp:ubuntuone-control-panel
Diff against target: 229 lines (+133/-14) 4 files modified
To merge this branch: bzr merge lp:~diegosarmentero/ubuntuone-control-panel/checkwrap
Reviewer Review Type Date Requested Status
Manuel de la Peña 2012-04-16 Approve on 2012-04-18
Roberto Alsina Approve on 2012-04-16
Review via email: mp+102152@code.launchpad.net

Commit Message

Adding a word_wrap function to use it in those cases where the widget don't implement a wrapping functionality.

To post a comment you must log in.
Diego Sarmentero (diegosarmentero) wrote :

I force the strings to be longer (repeating the text twice) and this is how it looks now with this code:

http://ubuntuone.com/6avGquAa62TNcSQ5GB7n7G

314. By Diego Sarmentero on 2012-04-16

Fixing lint issue.

315. By Diego Sarmentero on 2012-04-16

reverting code for example.

Manuel de la Peña (mandel) wrote :

I really thing we can get a much better algorithm here to calculate the wrapping a good example to do so is to read http://en.wikipedia.org/wiki/Word_wrap#Minimum_length and implement something similar that does not force us to have a loop inside an other.

review: Needs Fixing
Roberto Alsina (ralsina) wrote :

+1 and sharing mandel's algorithm caveat

review: Approve
316. By Diego Sarmentero on 2012-04-16

Improve wrapping algorithm, fix tests.

Diego Sarmentero (diegosarmentero) wrote :

> I really thing we can get a much better algorithm here to calculate the
> wrapping a good example to do so is to read
> http://en.wikipedia.org/wiki/Word_wrap#Minimum_length and implement something
> similar that does not force us to have a loop inside an other.

Done

Manuel de la Peña (mandel) wrote :

Two comments,

1. I have been told (I' not sure how official is this) that we should start making some move towards using python 3, due to that we should stop using the old string formating 'Hola %s' % 'gatox' to the new one 'Hola {0}'.format('gatox'). Can you please do that.

2. I'm not sure about the removal of the \n in the text.. In translations they do not care about the length of the string but they do care about the paragraph separations. What I mean is:

'This is a very long text, lets say I use more than one paragraph to separater ideas.\n\nThis is my new paragraph focusing on a diff idea.'

In these type of cases we are breaking the paragraph separation that is used by the translator with the intent to express to diff ideas. What I would do is not to remove \n and to check at in every word if we have a \n at the end (word[-1] is faster than endswith.) if that is the case we should set the size to be the full line size.

3. Since this is a very generic method (can be used in any possible widget) and there is no limit in the length of the strings to be wrapped I would assume the worst case scenario which is the case in which strings are very long. If that is the case using += to create the final text is probably not the best thing to do. Following the recommendations from http://wiki.python.org/moin/PythonSpeed/PerformanceTips#String_Concatenation I would at least move to .join instead of +=.

review: Needs Fixing
317. By Diego Sarmentero on 2012-04-17

Improving algorithm.

Diego Sarmentero (diegosarmentero) wrote :

> Two comments,
>
> 1. I have been told (I' not sure how official is this) that we should start
> making some move towards using python 3, due to that we should stop using the
> old string formating 'Hola %s' % 'gatox' to the new one 'Hola
> {0}'.format('gatox'). Can you please do that.
>

Stay as it is because we didn't decide how to use yet.

> 2. I'm not sure about the removal of the \n in the text.. In translations they
> do not care about the length of the string but they do care about the
> paragraph separations. What I mean is:
>
> 'This is a very long text, lets say I use more than one paragraph to separater
> ideas.\n\nThis is my new paragraph focusing on a diff idea.'
>
> In these type of cases we are breaking the paragraph separation that is used
> by the translator with the intent to express to diff ideas. What I would do is
> not to remove \n and to check at in every word if we have a \n at the end
> (word[-1] is faster than endswith.) if that is the case we should set the size
> to be the full line size.
>

Fixed, the '\n' is not needed because we are always providing the original string for the wrapping method.

> 3. Since this is a very generic method (can be used in any possible widget)
> and there is no limit in the length of the strings to be wrapped I would
> assume the worst case scenario which is the case in which strings are very
> long. If that is the case using += to create the final text is probably not
> the best thing to do. Following the recommendations from
> http://wiki.python.org/moin/PythonSpeed/PerformanceTips#String_Concatenation I
> would at least move to .join instead of +=.

Changed.

Manuel de la Peña (mandel) wrote :

Great!

review: Approve

Preview Diff

1=== modified file 'ubuntuone/controlpanel/gui/qt/__init__.py'
2--- ubuntuone/controlpanel/gui/qt/__init__.py 2012-03-27 12:52:17 +0000
3+++ ubuntuone/controlpanel/gui/qt/__init__.py 2012-04-17 18:12:18 +0000
4@@ -1,8 +1,6 @@
5 # -*- coding: utf-8 -*-
6-
7-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
8 #
9-# Copyright 2010 Canonical Ltd.
10+# Copyright 2010-2012 Canonical Ltd.
11 #
12 # This program is free software: you can redistribute it and/or modify it
13 # under the terms of the GNU General Public License version 3, as published
14@@ -33,6 +31,26 @@
15 )
16
17
18+def force_wordwrap(widget, size, text):
19+ """Set the text to the widget after word wrapping it."""
20+ font_metrics = QtGui.QFontMetrics(widget.font())
21+ text_width = font_metrics.width(text)
22+ if size > 0 and text_width > size:
23+ words = text.split(' ')
24+ text = ''
25+ size_left = size
26+ for word in words:
27+ word_size = font_metrics.width(word)
28+ if (size_left - word_size) > 0 or word_size > size:
29+ text = ''.join((text, '%s ' % word))
30+ size_left -= word_size
31+ else:
32+ text = ''.join((text, '\n%s ' % word))
33+ size_left = size - word_size
34+ text = text.rstrip()
35+ widget.setText(text)
36+
37+
38 def uri_hook(uri):
39 """Open an URI using the default browser/file manager."""
40 if uri.startswith(FILE_URI_PREFIX):
41
42=== modified file 'ubuntuone/controlpanel/gui/qt/preferences.py'
43--- ubuntuone/controlpanel/gui/qt/preferences.py 2012-03-28 12:06:28 +0000
44+++ ubuntuone/controlpanel/gui/qt/preferences.py 2012-04-17 18:12:18 +0000
45@@ -1,8 +1,6 @@
46 # -*- coding: utf-8 -*-
47-
48-# Authors: Alejandro J. Cura <alecu@canonical.com>
49 #
50-# Copyright 2011 Canonical Ltd.
51+# Copyright 2011-2012 Canonical Ltd.
52 #
53 # This program is free software: you can redistribute it and/or modify it
54 # under the terms of the GNU General Public License version 3, as published
55@@ -41,6 +39,7 @@
56 SETTINGS_SYNC_ALL_FOLDERS,
57 SETTINGS_SYNC_ALL_SHARES,
58 )
59+from ubuntuone.controlpanel.gui.qt import force_wordwrap
60 from ubuntuone.controlpanel.gui.qt.ubuntuonebin import UbuntuOneBin
61 from ubuntuone.controlpanel.gui.qt.ui import preferences_ui
62
63@@ -82,19 +81,12 @@
64 """Do some extra setupping for the UI."""
65 super(PreferencesPanel, self)._setup()
66 self.ui.apply_changes_button.setText(SETTINGS_BUTTON_APPLY)
67- self.ui.autoconnect_checkbox.setText(SETTINGS_AUTO_CONNECT)
68 self.ui.bandwidth_settings.setTitle(SETTINGS_BANDWIDTH)
69 self.ui.file_sync_settings.setTitle(SETTINGS_FILE_SYNC)
70 self.ui.kbps_label_1.setText(SETTINGS_KILOBITS_PER_SECOND)
71 self.ui.kbps_label_2.setText(SETTINGS_KILOBITS_PER_SECOND)
72 self.ui.label_2.setText(SETTINGS_BANDWIDTH_ZERO_WARNING)
73- self.ui.limit_uploads_checkbox.setText(SETTINGS_LIMIT_UPLOAD)
74- self.ui.limit_downloads_checkbox.setText(SETTINGS_LIMIT_DOWNLOAD)
75 self.ui.restore_defaults_button.setText(SETTINGS_BUTTON_DEFAULT)
76- self.ui.share_autosubscribe_checkbox.setText(SETTINGS_SYNC_ALL_FOLDERS)
77- self.ui.show_all_notifications_checkbox.setText(
78- SETTINGS_ALLOW_NOTIFICATIONS)
79- self.ui.udf_autosubscribe_checkbox.setText(SETTINGS_SYNC_ALL_SHARES)
80
81 # pylint: disable=E0202
82 @defer.inlineCallbacks
83@@ -192,3 +184,23 @@
84 settings = yield self.backend.file_sync_settings_info()
85
86 self.process_info(settings)
87+
88+ def resizeEvent(self, event):
89+ super(PreferencesPanel, self).resizeEvent(event)
90+ size_bandwidth = (self.ui.bandwidth_settings.width() -
91+ self.ui.upload_speed_spinbox.width() -
92+ self.ui.kbps_label_1.width())
93+ padding = 160 # Padding to allow shrinking
94+ size_sync = (self.ui.file_sync_settings.width() - padding)
95+ force_wordwrap(self.ui.limit_uploads_checkbox, size_bandwidth,
96+ SETTINGS_LIMIT_UPLOAD)
97+ force_wordwrap(self.ui.limit_downloads_checkbox, size_bandwidth,
98+ SETTINGS_LIMIT_DOWNLOAD)
99+ force_wordwrap(self.ui.autoconnect_checkbox, size_sync,
100+ SETTINGS_AUTO_CONNECT)
101+ force_wordwrap(self.ui.udf_autosubscribe_checkbox, size_sync,
102+ SETTINGS_SYNC_ALL_SHARES)
103+ force_wordwrap(self.ui.share_autosubscribe_checkbox, size_sync,
104+ SETTINGS_SYNC_ALL_FOLDERS)
105+ force_wordwrap(self.ui.show_all_notifications_checkbox, size_sync,
106+ SETTINGS_ALLOW_NOTIFICATIONS)
107
108=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_common.py'
109--- ubuntuone/controlpanel/gui/qt/tests/test_common.py 2012-03-26 21:00:47 +0000
110+++ ubuntuone/controlpanel/gui/qt/tests/test_common.py 2012-04-17 18:12:18 +0000
111@@ -28,13 +28,72 @@
112 GENERAL_ERROR_TITLE,
113 GENERAL_ERROR_MSG,
114 )
115-from ubuntuone.controlpanel.gui.qt import uri_hook, handle_errors
116+from ubuntuone.controlpanel.gui.qt import (
117+ force_wordwrap,
118+ handle_errors,
119+ uri_hook,
120+)
121 from ubuntuone.controlpanel.gui.qt.tests import (
122 BaseTestCase,
123 FakedDialog,
124 )
125
126
127+class ForceWordWrapTestCase(BaseTestCase):
128+ """The test suite for the force_wordwrap."""
129+
130+ @defer.inlineCallbacks
131+ def setUp(self):
132+ yield super(ForceWordWrapTestCase, self).setUp()
133+ self.check = QtGui.QCheckBox()
134+
135+ def test_small_text_no_wordwrap(self):
136+ """Set a small text, the widget shouldn't wordwrap."""
137+ text = u'small text'
138+ force_wordwrap(self.check, 1000, text)
139+ self.assertEqual(unicode(self.check.text()), text)
140+
141+ def test_size_invalid(self):
142+ """The text shouldn't change if the size is not valid."""
143+ text = u'small text' * 20
144+ force_wordwrap(self.check, 0, text)
145+ self.assertEqual(unicode(self.check.text()), text)
146+
147+ def test_size_too_small(self):
148+ """The text shouldn't change if the size is too small."""
149+ text = u'small text' * 20
150+ force_wordwrap(self.check, 10, text)
151+ self.assertEqual(unicode(self.check.text()), text)
152+
153+ def test_check_wrapping(self):
154+ """The text should be splitted in several lines."""
155+ text = u'small text ' * 20
156+ font_metrics = QtGui.QFontMetrics(self.check.font())
157+ size = font_metrics.width('small text')
158+ force_wordwrap(self.check, size, text)
159+ expected = u'small text \n' * 20
160+ expected = expected[:-1]
161+ self.assertEqual(unicode(self.check.text()), expected.rstrip())
162+
163+ def test_check_wrapping_in_the_middle_of_word(self):
164+ """The text should be splitted in several lines."""
165+ text = u'small text ' * 20
166+ font_metrics = QtGui.QFontMetrics(self.check.font())
167+ size = font_metrics.width('small text')
168+ force_wordwrap(self.check, size, text)
169+ expected = u'small text \n' * 20
170+ expected = expected[:-1]
171+ self.assertEqual(unicode(self.check.text()), expected.rstrip())
172+
173+ def test_no_word_wrap_valid(self):
174+ """If a not valid wrap place is found, the word wrap is not made."""
175+ text = u'smalltext ' * 20
176+ font_metrics = QtGui.QFontMetrics(self.check.font())
177+ size = font_metrics.averageCharWidth() * 5
178+ force_wordwrap(self.check, size, text)
179+ self.assertEqual(unicode(self.check.text()), text.rstrip())
180+
181+
182 class UriHookTestCase(BaseTestCase):
183 """The test suite for the uri_hook."""
184
185
186=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_preferences.py'
187--- ubuntuone/controlpanel/gui/qt/tests/test_preferences.py 2012-03-28 12:06:28 +0000
188+++ ubuntuone/controlpanel/gui/qt/tests/test_preferences.py 2012-04-17 18:12:18 +0000
189@@ -20,6 +20,8 @@
190
191 from __future__ import division
192
193+import operator
194+
195 from twisted.internet import defer
196
197 from ubuntuone.controlpanel.gui.qt import preferences as gui
198@@ -297,3 +299,31 @@
199 def test_tweak_speed_positive(self):
200 """Tweak speed properly: if param is positive, return kilobytes."""
201 self.assertEqual(123456 * gui.KILOBYTES, gui.tweak_speed(123456))
202+
203+ def test_resize_event(self):
204+ """Check that the QCheckBox widgets receive the proper texts."""
205+ wrap_calls = {}
206+ self.patch(gui, "force_wordwrap",
207+ lambda check, size, text: operator.setitem(
208+ wrap_calls, check, (size, text)))
209+ self.ui.setFixedWidth(1000)
210+ size_bandwidth = (self.ui.ui.bandwidth_settings.width() -
211+ self.ui.ui.upload_speed_spinbox.width() -
212+ self.ui.ui.kbps_label_1.width())
213+ padding = 160 # Left and Right Padding
214+ size_sync = (self.ui.ui.file_sync_settings.width() - padding)
215+ self.ui.show()
216+ self.addCleanup(self.ui.hide)
217+ self.assertEqual(wrap_calls[self.ui.ui.limit_uploads_checkbox],
218+ (size_bandwidth, gui.SETTINGS_LIMIT_UPLOAD))
219+ self.assertEqual(wrap_calls[self.ui.ui.limit_downloads_checkbox],
220+ (size_bandwidth, gui.SETTINGS_LIMIT_DOWNLOAD))
221+ self.assertEqual(wrap_calls[self.ui.ui.autoconnect_checkbox],
222+ (size_sync, gui.SETTINGS_AUTO_CONNECT))
223+ self.assertEqual(wrap_calls[self.ui.ui.udf_autosubscribe_checkbox],
224+ (size_sync, gui.SETTINGS_SYNC_ALL_SHARES))
225+ self.assertEqual(wrap_calls[self.ui.ui.share_autosubscribe_checkbox],
226+ (size_sync, gui.SETTINGS_SYNC_ALL_FOLDERS))
227+ self.assertEqual(
228+ wrap_calls[self.ui.ui.show_all_notifications_checkbox],
229+ (size_sync, gui.SETTINGS_ALLOW_NOTIFICATIONS))

Subscribers

People subscribed via source and target branches