Merge lp:~gabor-karsay/awn-extras/comics into lp:awn-extras

Proposed by Gabor Karsay
Status: Merged
Merged at revision: 1494
Proposed branch: lp:~gabor-karsay/awn-extras/comics
Merge into: lp:awn-extras
Diff against target: 3450 lines (+1084/-1555) (has conflicts)
43 files modified
applets/maintained/comics/Makefile.am (+3/-0)
applets/maintained/comics/comics.py (+78/-30)
applets/maintained/comics/comics_add.py (+150/-34)
applets/maintained/comics/comics_manage.py (+87/-45)
applets/maintained/comics/comics_view.py (+123/-84)
applets/maintained/comics/feed/__init__.py (+9/-8)
applets/maintained/comics/feed/basic.py (+94/-13)
applets/maintained/comics/feed/plugins/__init__.py (+18/-0)
applets/maintained/comics/feed/plugins/simple_screen_scraper.py (+112/-0)
applets/maintained/comics/feed/rss.py (+2/-2)
applets/maintained/comics/feeds/ben.feed (+7/-0)
applets/maintained/comics/feeds/buttersafe.feed (+3/-3)
applets/maintained/comics/feeds/calvinandhobbes.feed (+6/-0)
applets/maintained/comics/feeds/ferdnand.feed (+7/-0)
applets/maintained/comics/feeds/garfield.feed (+6/-0)
applets/maintained/comics/feeds/nancy.feed (+7/-0)
applets/maintained/comics/feeds/pcnp.feed (+7/-0)
applets/maintained/comics/feeds/peanuts.feed (+0/-2)
applets/maintained/comics/feeds/pearls.feed (+7/-5)
applets/maintained/comics/feeds/pickles.feed (+6/-0)
applets/maintained/comics/feeds/userfriendly.feed (+7/-0)
applets/maintained/comics/feeds/wizardofid.feed (+6/-3)
applets/maintained/comics/ui/add.ui (+281/-57)
applets/maintained/comics/ui/manage.ui (+58/-32)
applets/maintained/comics/ui/view.ui (+0/-154)
applets/unmaintained/comic/Makefile.am (+0/-24)
applets/unmaintained/comic/comic.desktop.in (+0/-11)
applets/unmaintained/comic/comic.py (+0/-226)
applets/unmaintained/comic/comicdialog.py (+0/-46)
applets/unmaintained/comic/getben.py (+0/-75)
applets/unmaintained/comic/getborn.py (+0/-75)
applets/unmaintained/comic/getdilbert.py (+0/-75)
applets/unmaintained/comic/getferdnand.py (+0/-75)
applets/unmaintained/comic/getgarfield.py (+0/-56)
applets/unmaintained/comic/getnancy.py (+0/-75)
applets/unmaintained/comic/getpcnp.py (+0/-75)
applets/unmaintained/comic/getpeanuts.py (+0/-75)
applets/unmaintained/comic/getpickles.py (+0/-75)
applets/unmaintained/comic/getwiz.py (+0/-75)
applets/unmaintained/comic/getxkcd.py (+0/-40)
debian/awn-applets-python-extras-trunk.install (+0/-3)
po/POTFILES.in (+0/-1)
po/POTFILES.skip (+0/-1)
Conflict: can't delete applets/unmaintained/comic because it is not empty.  Not deleting.
Conflict because applets/unmaintained/comic is not versioned, but has versioned children.  Versioned directory.
Contents conflict in applets/unmaintained/comic/getuf.py
To merge this branch: bzr merge lp:~gabor-karsay/awn-extras/comics
Reviewer Review Type Date Requested Status
Awn Extras Developers Pending
Review via email: mp+43374@code.launchpad.net

This proposal supersedes a proposal from 2010-10-11.

Description of the change

This brunch adds a plugin to Comics! applet, the SimpleScreenScraper. It indexes images on a web page, lets the user decide which one contains the comic and then shows this image by its index. No previous strips shown, just the one actually at display. This plugin is always used when there is no feed available.

All comics from old comic applet are included, except for "Born loser" – the URL doesn't exist anymore. The old applet is removed from source tree. Note that while the old comics can be viewed, the ones without a feed have less functionality: no going back in history; and showing a higher resolution strip isn't supported either.

The context menu changed: There is only one item "My comics" instead of the 2 items "Comics" and "Manage Comics". There are no "common" comics anymore (preinstalled comics that couldn't be removed).

Adding a comic can be done in two ways: selecting from a list of preconfigured comics or by adding an URL.

Restored the context menu for the strips (a regression at porting to 0.4)

Added an about window.

Fixes two rare crashes (admittedly I don't know the reason for one of them, bug #356334 , the crash is avoided in rev. 1432)

To post a comment you must log in.
Revision history for this message
Gabor Karsay (gabor-karsay) wrote : Posted in a previous version of this proposal

Argh, gocomics.com was o.k. last week, now they apparently changed something with the feed and it doesn't work anymore. The old feeds are not shown, new ones can't be added.

review: Needs Fixing
Revision history for this message
onox (onox) wrote : Posted in a previous version of this proposal

I'm not sure about the preinstalled comics. Best thing would be that the user could retrieve a list of comics (fetching the data from comics.com or some other website) and then choose which he/she would like to add. This way we can also avoid those "feature" requests from random users who want to see some random comic that nobody reads getting added :p

Revision history for this message
Gabor Karsay (gabor-karsay) wrote : Posted in a previous version of this proposal

Fixed the change in gocomics' feeds and a change in glade-3.

Referring to the preinstalled comics: I can't see a way to retrieve a list of comics automatically from gocomics.com (neither from comics.com, which requires registration and has very strict terms of use). So we'd probably have to create this list and maintain it ourselves - and that would be the same as preinstalling some of them (the user can still decide whether these comics are shown or not).

Actually users can add comics using the assistant. They only have to know the URL of the feed and then select the image showing the comic. It's as easy as copy & paste a backtrace to a bug report. That means: it might be way too difficult for some users ;-) That's why we have some preinstalled comics.

I agree that some of the preinstalled comics are not suited for a wide audience. I'm inclined to remove buttersafe and explosm because they are sort of weird. gocomics.com can sort its comics by popularity. I added Calvin & Hobbes because it's the most popular comic, Garfield is #3. wulffmorgenthaler was a user request, it is regularly updated and I like it (but some strips may be not suitable for children, lets say aged 12 or less).

review: Needs Resubmitting
Revision history for this message
onox (onox) wrote : Posted in a previous version of this proposal

Imho a -1 for Explosm and wulffmorgenthaler

Gabor, if you could fix lp bug #547154 in this branch, you would make moonbeam very happy :)

Revision history for this message
onox (onox) wrote : Posted in a previous version of this proposal

Oh, and +1 for removing old comic applet.

Revision history for this message
Gabor Karsay (gabor-karsay) wrote : Posted in a previous version of this proposal

I'll have a look at that bug, might take some time.

Revision history for this message
Gabor Karsay (gabor-karsay) wrote :

No comments? I'll merge this weekend then.

Revision history for this message
moonbeam (rcryderman) wrote :

Sounds good.

lp:~gabor-karsay/awn-extras/comics updated
1460. By Gabor Karsay

Update comics: Pearls before Swine new URL (old one not updated), gocomics.com changed image index

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'applets/maintained/comics/Makefile.am'
2--- applets/maintained/comics/Makefile.am 2010-01-26 03:46:15 +0000
3+++ applets/maintained/comics/Makefile.am 2011-01-09 09:07:16 +0000
4@@ -27,6 +27,9 @@
5 feedsdir = $(applet_datadir)/feeds
6 dist_feeds_DATA = $(wildcard feeds/*.feed)
7
8+pluginsdir = $(applet_datadir)/feed/plugins
9+dist_plugins_DATA = $(wildcard feed/plugins/*.py)
10+
11 uidir = $(applet_datadir)/ui
12 dist_ui_DATA = \
13 $(wildcard ui/*.svg) \
14
15=== modified file 'applets/maintained/comics/comics.py'
16--- applets/maintained/comics/comics.py 2010-09-10 01:21:59 +0000
17+++ applets/maintained/comics/comics.py 2011-01-09 09:07:16 +0000
18@@ -27,7 +27,7 @@
19 import os
20 import sys
21 import tempfile
22-from awn.extras import _
23+from awn.extras import _, awnlib
24
25 # Import Comics! modules, but check dependencies first
26 awn.check_dependencies(globals(), 'feedparser', 'pynotify')
27@@ -35,6 +35,7 @@
28
29 import comics_manage
30 import comics_view
31+from comics_add import ComicsAdder
32 from feed.settings import Settings
33 from feed import FeedContainer
34 from shared import (
35@@ -42,6 +43,8 @@
36 USER_DIR, USER_FEEDS_DIR)
37
38 APPLET_NAME = 'comics'
39+applet_display_name = _('Comics!')
40+applet_icon = os.path.join(ICONS_DIR, 'comics-icon.svg')
41
42
43 class BidirectionalIterator:
44@@ -79,6 +82,38 @@
45 return self.sequence[self.index]
46
47
48+class about_dialog(gtk.AboutDialog):
49+ def __init__(self):
50+ super(about_dialog, self).__init__()
51+ pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(applet_icon, 48, 48)
52+ self.set_name(applet_display_name)
53+ self.set_copyright('Copyright \xc2\xa9 2008 Moses Palmér')
54+ self.set_authors(['Moses Palmér',
55+ 'Sharkbaitbobby',
56+ 'Mark Lee',
57+ 'Kyle L. Huff',
58+ 'Gabor Karsay'])
59+ self.set_artists(['Moses Palmér'])
60+ self.set_comments(_("View your favourite comics on your desktop"))
61+ self.set_license("This program is free software; you can " + \
62+ "redistribute it and/or modify it under the terms of the GNU " + \
63+ "General Public License as published by the Free Software " + \
64+ "Foundation; either version 2 of the License, or (at your " + \
65+ "option) any later version.\n\n" + \
66+ "This program is distributed in the hope that it will be " + \
67+ "useful, but WITHOUT ANY WARRANTY; without even the implied " + \
68+ "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR " + \
69+ "PURPOSE. See the GNU General Public License for more " + \
70+ "details.\n\nYou should have received a copy of the GNU " + \
71+ "General Public License along with this program; if not, " + \
72+ "write to the Free Software Foundation, Inc., 51 Franklin St, " + \
73+ "Fifth Floor, Boston, MA 02110-1301, USA.")
74+ self.set_wrap_license(True)
75+ self.set_logo(pixbuf)
76+ self.set_icon_from_file(applet_icon)
77+ self.set_version(awn.extras.__version__)
78+
79+
80 class ComicApplet(awn.AppletSimple):
81 DIALOG_DURATION = 3000
82
83@@ -135,30 +170,19 @@
84 self.create_window(template=template)
85
86 def make_menu(self):
87- """Generate the menu listing the comics."""
88+ """Generate the context menu."""
89 # Generate comics menu
90 menu = self.create_default_menu()
91- feed_menu = gtk.Menu()
92- for feed in self.feeds.feeds:
93- label = gtk.Label()
94- label.set_markup(self.feeds.feeds[feed].name)
95- align = gtk.Alignment(xalign=0.0)
96- align.add(label)
97- menu_item = gtk.CheckMenuItem()
98- menu_item.data = feed
99- menu_item.add(align)
100- menu_item.set_active(len([w for w in self.windows
101- if w.feed_name == feed]) > 0)
102- menu_item.connect('toggled', self.on_comics_toggled)
103- feed_menu.append(menu_item)
104- feed_menu.show_all()
105- container = gtk.MenuItem(_('Comics'))
106- container.set_sensitive(len(self.feeds.feeds) > 0)
107- container.set_submenu(feed_menu)
108- menu.append(container)
109- manage_item = gtk.MenuItem(_('Manage Comics'))
110+ manage_item = gtk.MenuItem(_('My Comics'))
111 manage_item.connect("activate", self.on_manage_comics_activated)
112 menu.append(manage_item)
113+ about_item = gtk.ImageMenuItem(_("_About %s") % applet_display_name)
114+ if awnlib.is_required_version(gtk.gtk_version, (2, 16, 0)):
115+ about_item.props.always_show_image = True
116+ about_item.set_image(gtk.image_new_from_stock(gtk.STOCK_ABOUT,
117+ gtk.ICON_SIZE_MENU))
118+ menu.append(about_item)
119+ about_item.connect("activate", self.on_show_about_activated)
120 menu.show_all()
121 return menu
122
123@@ -176,7 +200,7 @@
124
125 self.set_icon_name('comics-icon')
126 # Initialise notifications
127- notify_init(_('Comics!'))
128+ notify_init(applet_display_name)
129 self.dialog = awn.Dialog(self)
130 self.dialog.connect('button-release-event',
131 self.on_dialog_button_press)
132@@ -197,6 +221,9 @@
133 self.windows = []
134 self.window_iterator = BidirectionalIterator(self.windows)
135 self.current_window = None
136+ self.manager = None
137+ self.adder = None
138+ self.about = None
139
140 try:
141 for filename in (f for f in os.listdir(STRIPS_DIR)
142@@ -209,24 +236,35 @@
143
144 def on_window_updated(self, widget, title):
145 msg = Notification(_('There is a new strip of %s!') % widget.feed_name,
146- None,
147- os.path.join(ICONS_DIR, 'comics-icon.svg'))
148+ None, applet_icon)
149 msg.show()
150
151 def on_window_removed(self, widget):
152 self.windows.remove(widget)
153+ if self.manager:
154+ if self.manager.on_screen():
155+ self.manager.load_feeds()
156
157 def on_destroy(self, widget):
158 for window in self.windows:
159 window.save_settings()
160
161 def on_button1_pressed(self, event):
162- self.set_visibility(not self.visible)
163+ if len(self.feeds.feeds) == 0:
164+ if self.adder and self.adder.on_screen():
165+ self.adder.present()
166+ else:
167+ self.adder = []
168+ self.adder = ComicsAdder(self)
169+ elif not self.windows:
170+ self.on_manage_comics_activated(None)
171+ else:
172+ self.set_visibility(not self.visible)
173
174 def on_button3_pressed(self, event):
175 menu = self.make_menu()
176 if menu:
177- self.popup_gtk_menu (menu, event.button, event.time)
178+ self.popup_gtk_menu(menu, event.button, event.time)
179
180 def on_button_press(self, widget, event):
181 if event.button == 1:
182@@ -255,9 +293,21 @@
183 self.toggle_feed(widget.data, widget.get_active())
184
185 def on_manage_comics_activated(self, widget):
186- manager = comics_manage.ComicsManager(self.feeds)
187- manager.show()
188+ if self.manager and self.manager.on_screen():
189+ self.manager.present()
190+ else:
191+ self.manager = []
192+ self.manager = comics_manage.ComicsManager(self)
193+ self.manager.show()
194
195+ def on_show_about_activated(self, widget):
196+ if self.about and len(self.about) != 0:
197+ self.about.present()
198+ else:
199+ self.about = []
200+ self.about = about_dialog()
201+ self.about.run()
202+ self.about.destroy()
203
204 if __name__ == '__main__':
205 # Initialise threading
206@@ -274,14 +324,12 @@
207
208 # Load the feeds
209 feeds = FeedContainer()
210- feeds.load_directory(SYS_FEEDS_DIR)
211 feeds.load_directory(USER_FEEDS_DIR)
212
213 #Initialise AWN and create the applet
214 awn.init(sys.argv[1:])
215 applet = ComicApplet(awn.uid, awn.panel_id, feeds)
216
217-
218 # Initialize user agent string
219 import urllib
220
221
222=== modified file 'applets/maintained/comics/comics_add.py'
223--- applets/maintained/comics/comics_add.py 2010-03-01 06:50:28 +0000
224+++ applets/maintained/comics/comics_add.py 2011-01-09 09:07:16 +0000
225@@ -17,6 +17,7 @@
226 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
227 # Boston, MA 02111-1307, USA.
228
229+from __future__ import with_statement
230
231 # Libraries used
232 import gobject
233@@ -30,10 +31,11 @@
234
235 # Local
236 from downloader import Downloader
237-from feed.basic import Feed, NAME, URL
238+from feed import FeedContainer
239+from feed.basic import Feed, NAME, URL, PLUGIN
240 from feed.settings import Settings
241 from feed.rss import IMG_INDEX
242-from shared import (UI_DIR, USER_FEEDS_DIR)
243+from shared import (UI_DIR, USER_FEEDS_DIR, SYS_FEEDS_DIR)
244
245 UI_FILE = os.path.join(UI_DIR, 'add.ui')
246
247@@ -67,13 +69,30 @@
248
249 return True
250
251+ def load_sys_list(self):
252+ if not self.sys:
253+ self.sys = FeedContainer()
254+ self.sys.load_directory(SYS_FEEDS_DIR)
255+ self.sys_model.clear()
256+ names = self.sys.feeds.keys()
257+ names.sort(key=str.lower)
258+ for feed in names:
259+ self.sys_model.append((feed, self.sys.feeds[feed].filename))
260+
261+ def on_screen(self):
262+ return len(self.assistant) != 0
263+
264+ def present(self):
265+ self.assistant.present()
266+
267 ########################################################################
268 # Standard python methods #
269 ########################################################################
270
271- def __init__(self, feeds):
272+ def __init__(self, parent):
273 """Create a new ComicsAdder instance."""
274- self.feeds = feeds
275+ self.__parent = parent
276+ self.feeds = parent.feeds
277 self.name = ''
278 self.url = ''
279 self.feed = None
280@@ -86,9 +105,24 @@
281 self.assistant = self.ui.get_object('add_assistant')
282 self.image_list = self.ui.get_object('image_list')
283
284+ self.sys = None
285+ self.sys_list = self.ui.get_object('pre_list')
286+ self.sys_model = gtk.ListStore(gobject.TYPE_STRING,
287+ gobject.TYPE_STRING)
288+ self.sys_col = self.ui.get_object('pre_col')
289+ self.load_sys_list()
290+ self.sys_list.set_model(self.sys_model)
291+
292+ self.from_list = True
293+ self.radio_button = self.ui.get_object('list_radio')
294+ self.radio_button.set_active(self.from_list)
295+
296 self.model = gtk.ListStore(gobject.TYPE_PYOBJECT, gtk.gdk.Pixbuf)
297 self.image_list.set_model(self.model)
298
299+ selection = self.sys_list.get_selection()
300+ selection.connect('changed', self.on_list_selection_changed)
301+ selection.set_mode(gtk.SELECTION_MULTIPLE)
302 # Show window
303 self.assistant.set_page_complete(self.ui.get_object('intro_page'),
304 True)
305@@ -115,39 +149,113 @@
306 os.mkdir(USER_FEEDS_DIR)
307 except Exception:
308 pass
309- f, filename = tempfile.mkstemp('.feed', '', USER_FEEDS_DIR, True)
310- os.close(f)
311- settings = Settings(filename)
312- settings.description = 'Automatically generated by comics'
313- settings[NAME] = self.name
314- settings[URL] = self.url
315- settings[IMG_INDEX] = self.image[0] + 1
316- settings.comments[IMG_INDEX] = \
317- 'The index of the image in the HTML-code'
318
319- settings.save()
320- self.feeds.add_feed(filename)
321+ if self.from_list:
322+ model, paths = self.sys_list.get_selection().get_selected_rows()
323+ for path in paths:
324+ self.name = model.get_value(model.get_iter(path), 0)
325+ src = model.get_value(model.get_iter(path), 1)
326+ filename = USER_FEEDS_DIR + src[len(SYS_FEEDS_DIR):]
327+ with open(src, 'r') as fp:
328+ src_content = fp.read()
329+ try:
330+ with open(filename, 'r') as fp:
331+ f = fp.read()
332+ except IOError:
333+ f = None
334+ if f:
335+ if cmp(src_content, f) == 0:
336+ continue
337+ msg = _("Overwrite comic \"%s\"?") % self.name
338+ sec = _(
339+ "This comic is already installed with different settings.")
340+ dialog = gtk.MessageDialog(parent=self.assistant,
341+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
342+ type=gtk.MESSAGE_WARNING,
343+ message_format=msg)
344+ dialog.format_secondary_markup(sec)
345+ if path != paths[-1]:
346+ dialog.add_buttons(
347+ gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
348+ dialog.add_buttons(gtk.STOCK_NO, gtk.RESPONSE_NO,
349+ gtk.STOCK_YES, gtk.RESPONSE_YES)
350+ response = dialog.run()
351+ dialog.destroy()
352+ if response == gtk.RESPONSE_NO:
353+ continue
354+ if response != gtk.RESPONSE_YES:
355+ return
356+ with open(filename, 'w') as fp:
357+ fp.write(src_content)
358+ self.feeds.add_feed(filename)
359+ self.feeds.update()
360+ self.__parent.toggle_feed(self.name, True)
361+ else:
362+ self.name = self.ui.get_object('name_entry').get_text()
363+ f, filename = tempfile.mkstemp('.feed', '', USER_FEEDS_DIR, True)
364+ os.close(f)
365+ settings = Settings(filename)
366+ settings.description = 'Automatically generated by comics'
367+ settings[NAME] = self.name
368+ settings[URL] = self.url
369+ settings[IMG_INDEX] = self.image[0] + 1
370+ settings.comments[IMG_INDEX] = \
371+ 'The index of the image in the HTML-code'
372+ if self.feed.__module__.startswith('feed.plugins.'):
373+ settings[PLUGIN] = self.feed.__module__[13:]
374+ settings.save()
375+ self.feeds.add_feed(filename)
376+ self.feeds.update()
377+ self.__parent.toggle_feed(self.name, True)
378
379 def on_add_assistant_prepare(self, widget, page):
380 if page is self.ui.get_object('url_page'):
381- self.ui.get_object('wait_page').show()
382+ if self.from_list:
383+ self.ui.get_object('list_box').show()
384+ self.ui.get_object('url_box').hide()
385+ else:
386+ self.ui.get_object('list_box').hide()
387+ self.ui.get_object('url_box').show()
388
389 elif page is self.ui.get_object('wait_page'):
390- self.assistant.set_page_complete(page, False)
391- self.url = self.ui.get_object('url_entry').get_text()
392-
393- self.ui.get_object('wait_label').set_markup(
394- _('Connecting to <i>%s</i>...') % self.url)
395-
396- # Download feed
397- self.feed = self.feeds.get_feed_for_url(self.url)
398- self.__update = self.feed.connect('updated', self.on_feed_updated)
399- self.feed.update()
400+ if self.from_list:
401+ self.ui.get_object('name_box').hide()
402+ last_label = self.ui.get_object('last_label')
403+ last_label.set_markup(_('''\
404+This guide has finished.\n\
405+Press "apply" to add the comic.'''))
406+ self.assistant.set_current_page(4)
407+ else:
408+ self.assistant.set_page_complete(page, False)
409+ self.url = self.ui.get_object('url_entry').get_text()
410+
411+ self.ui.get_object('wait_label').set_markup(
412+ _('Connecting to <i>%s</i>...') % self.url)
413+
414+ # Download feed
415+ self.feed = self.feeds.get_feed_for_url(self.url)
416+ self.__update = self.feed.connect('updated',
417+ self.on_feed_updated)
418+ self.feed.update()
419+
420+ def on_radio_button_toggled(self, widget):
421+ self.from_list = self.radio_button.get_active()
422
423 def on_url_entry_changed(self, widget):
424 text = widget.get_text()
425- self.assistant.set_page_complete(self.ui.get_object('url_page'),
426- not URL_RE.match(text) is None)
427+ if not self.from_list:
428+ self.assistant.set_page_complete(self.ui.get_object('url_page'),
429+ not URL_RE.match(text) is None)
430+
431+ def on_list_selection_changed(self, widget):
432+ if self.from_list:
433+ self.assistant.set_page_complete(self.ui.get_object('url_page'),
434+ self.sys_list.get_selection().count_selected_rows() > 0)
435+
436+ def on_name_entry_changed(self, widget):
437+ text = widget.get_text()
438+ self.assistant.set_page_complete(self.ui.get_object('last_page'),
439+ not text == '')
440
441 def on_image_list_unselect_all(self, widget):
442 self.assistant.set_page_complete(self.ui.get_object('image_page'),
443@@ -172,8 +280,10 @@
444
445 last_label = self.ui.get_object('last_label')
446 last_label.set_markup(_('''\
447-This guide has finished.\n\nPress "apply" to add <i>%s</i>.''') \
448- % self.name)
449+This guide has finished.\n\
450+You can change the name of this comic. Press "apply" to add it.'''))
451+ name_entry = self.ui.get_object('name_entry')
452+ name_entry.set_text(self.name)
453
454 # Can we skip the image page?
455 images = feed.get_unique_images()
456@@ -189,7 +299,11 @@
457 self.ui.get_object('image_page').show()
458 else:
459 self.ui.get_object('image_page').hide()
460- self.image = images[0]
461+ try:
462+ self.image = images[0]
463+ except IndexError:
464+ self.process_error(Feed.DOWNLOAD_NOT_FEED)
465+ return
466
467 # Complete page
468 self.assistant.set_page_complete(self.ui.get_object('wait_page'),
469@@ -204,7 +318,9 @@
470 if code != Downloader.OK:
471 self.model.remove(iterator)
472 else:
473- pixbuf = gtk.gdk.pixbuf_new_from_file(o.filename)
474+ try:
475+ pixbuf = gtk.gdk.pixbuf_new_from_file(o.filename)
476+ self.model.set_value(iterator, 1, pixbuf)
477+ except Exception:
478+ self.model.remove(iterator)
479 os.remove(o.filename)
480-
481- self.model.set_value(iterator, 1, pixbuf)
482
483=== modified file 'applets/maintained/comics/comics_manage.py'
484--- applets/maintained/comics/comics_manage.py 2010-03-01 06:50:28 +0000
485+++ applets/maintained/comics/comics_manage.py 2011-01-09 09:07:16 +0000
486@@ -24,6 +24,7 @@
487 import os
488
489 # Symbols used
490+from gettext import ngettext
491 from awn.extras import _
492
493 # Local
494@@ -47,86 +48,127 @@
495 def load_feeds(self):
496 """Load the descriptions of all installed feeds."""
497 self.model.clear()
498-
499- shared_iterator = self.model.append(None, (_('Shared comics'), ''))
500- user_iterator = self.model.append(None, (_('Your comics'), ''))
501- for feed_name, feed in self.feeds.feeds.items():
502- if os.access(os.path.dirname(feed.filename), os.W_OK):
503- self.model.append(user_iterator, (feed_name, feed.filename))
504- else:
505- self.model.append(shared_iterator, (feed_name, feed.filename))
506-
507- self.comics_list.expand_all()
508+ names = self.feeds.feeds.keys()
509+ names.sort(key=str.lower)
510+ for feed in names:
511+ self.model.append(
512+ (len([w for w in self.__parent.windows
513+ if w.feed_name == feed]) > 0,
514+ feed, self.feeds.feeds[feed].filename))
515
516 def show(self):
517 self.manage_window.show()
518
519+ def present(self):
520+ self.manage_window.present()
521+
522+ def on_screen(self):
523+ return len(self.manage_window) != 0
524+
525 ########################################################################
526 # Standard python methods #
527 ########################################################################
528
529- def __init__(self, feeds):
530+ def __init__(self, parent):
531 """Create a new ComicsManage instance."""
532 # Connect dialogue events
533 self.ui = gtk.Builder()
534 self.ui.add_from_file(UI_FILE)
535 self.ui.connect_signals(self)
536
537- self.feeds = feeds
538+ self.__parent = parent
539+ self.feeds = parent.feeds
540
541 self.manage_window = self.ui.get_object('manage_window')
542
543- self.model = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
544+ self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING,
545+ gobject.TYPE_STRING)
546
547 self.comics_list = self.ui.get_object('comics_list')
548 selection = self.comics_list.get_selection()
549 selection.connect('changed', self.on_comics_list_selection_changed)
550- cr = gtk.CellRendererText()
551- column = gtk.TreeViewColumn()
552- column.pack_start(cr)
553- column.set_attributes(cr, text=0)
554- self.comics_list.append_column(column)
555+ selection.set_mode(gtk.SELECTION_MULTIPLE)
556 self.comics_list.set_model(self.model)
557+ # Translators: checkbox to show comic
558+ self.ui.get_object('toggle_col').set_title(_('Show'))
559+ self.ui.get_object('name_col').set_title(_('Comic'))
560
561 self.load_feeds()
562+ x, y = self.comics_list.size_request()
563+ if x > 475:
564+ x = 475
565+ if y > 400:
566+ y = 400
567+ self.manage_window.set_default_size(x + 25, y + 100)
568
569 ########################################################################
570 # Event hooks #
571 ########################################################################
572
573 def on_comics_list_selection_changed(self, widget):
574- model, iterator = self.comics_list.get_selection().get_selected()
575+ rows = self.comics_list.get_selection().count_selected_rows()
576 button = self.ui.get_object('remove_button')
577- if iterator:
578- directory = os.path.dirname(self.model.get_value(iterator, 1))
579- button.set_sensitive(os.access(directory, os.W_OK))
580+ button.set_sensitive(rows > 0)
581+
582+ def on_feed_toggled(self, widget, path):
583+ self.model[path][0] = not self.model[path][0]
584+ self.__parent.toggle_feed(self.model[path][1], self.model[path][0])
585+
586+ def on_add_button_clicked(self, widget):
587+ if self.__parent.adder and self.__parent.adder.on_screen():
588+ self.__parent.adder.present()
589 else:
590- button.set_sensitive(False)
591-
592- def on_add_button_clicked(self, widget):
593- adder = ComicsAdder(self.feeds)
594- adder.assistant.set_transient_for(self.manage_window)
595- adder.assistant.connect('destroy', self.on_adder_destroy)
596+ self.__parent.adder = []
597+ self.__parent.adder = ComicsAdder(self.__parent)
598+ self.__parent.adder.assistant.set_transient_for(self.manage_window)
599+ self.__parent.adder.assistant.connect('destroy',
600+ self.on_adder_destroy)
601
602 def on_remove_button_clicked(self, widget):
603- model, iterator = self.comics_list.get_selection().get_selected()
604- feed_name = self.model.get_value(iterator, 0)
605- filename = self.model.get_value(iterator, 1)
606- try:
607- self.feeds.remove_feed(feed_name)
608- os.remove(filename)
609- except Exception:
610- msg = _('Failed to remove <i>%s</i>.') % filename
611- dialog = gtk.MessageDialog(parent=self.manage_window,
612- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
613- type=gtk.MESSAGE_INFO,
614- buttons=gtk.BUTTONS_CLOSE,
615- message_format=msg)
616- dialog.set_title(_('Error'))
617- dialog.run()
618- dialog.hide()
619- del dialog
620+ model, path = self.comics_list.get_selection().get_selected_rows()
621+ msg = ngettext(
622+ "Are you sure you want to remove the comic \"%(name)s\"?",
623+ "Are you sure you want to remove the %(number)d selected comics?",
624+ len(path)) % {'number': len(path),
625+ 'name': self.model.get_value(self.model.get_iter(path[0]), 1)}
626+ sec = ngettext(
627+ "This will remove the comic from your personal comics list.",
628+ "This will remove these comics from your personal comics list.",
629+ len(path))
630+
631+ dialog = gtk.MessageDialog(parent=self.manage_window,
632+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
633+ type=gtk.MESSAGE_WARNING,
634+ message_format=msg)
635+ dialog.format_secondary_markup(sec)
636+ dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
637+ gtk.STOCK_REMOVE, gtk.RESPONSE_OK)
638+ response = dialog.run()
639+ dialog.destroy()
640+
641+ if response != gtk.RESPONSE_OK:
642 return
643+
644+ def remove(model, path, iterator):
645+ feed_name = model.get_value(iterator, 1)
646+ filename = model.get_value(iterator, 2)
647+ self.__parent.toggle_feed(feed_name, False)
648+ try:
649+ self.feeds.remove_feed(feed_name)
650+ os.remove(filename)
651+ except Exception:
652+ msg = _("Failed to remove '%s'.") % filename
653+ dialog = gtk.MessageDialog(parent=self.manage_window,
654+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
655+ type=gtk.MESSAGE_INFO,
656+ buttons=gtk.BUTTONS_CLOSE,
657+ message_format=msg)
658+ dialog.set_title(_('Error'))
659+ dialog.run()
660+ dialog.destroy()
661+ return
662+
663+ self.comics_list.get_selection().selected_foreach(remove)
664 self.load_feeds()
665
666 def on_close_button_clicked(self, widget):
667
668=== modified file 'applets/maintained/comics/comics_view.py'
669--- applets/maintained/comics/comics_view.py 2010-03-01 06:50:28 +0000
670+++ applets/maintained/comics/comics_view.py 2011-01-09 09:07:16 +0000
671@@ -42,7 +42,6 @@
672
673 STRIPS_DIR = USER_DIR
674 CACHE_FILE = os.path.join(USER_DIR, '%s.cache')
675-UI_FILE = os.path.join(UI_DIR, 'view.ui')
676
677 BROWSER_COMMAND = 'xdg-open'
678
679@@ -123,11 +122,13 @@
680 screen = self.get_screen()
681 screen_width, screen_height = (screen.get_width(),
682 screen.get_height())
683+ w, h = self.get_size()
684+ x = self.__settings.get_int('x', (screen_width - w) / 2)
685+ y = self.__settings.get_int('y', (screen_height - h) / 2)
686
687 # Show the window first...
688 self.show()
689
690- x, y = self.get_position()
691 x %= screen_width
692 if x < 0:
693 x += screen_width
694@@ -135,32 +136,34 @@
695 if y < 0:
696 y += screen_height
697
698+ # this must be between self.show() and self.move()
699+ # it calls self.get_position(), without it the comic
700+ # will not be painted the very first time
701+ self.save_settings()
702+
703 # ...and then move it
704 self.move(x, y)
705
706- self.__settings['x'] = x
707- self.__settings['y'] = y
708-
709 if has_widget_layer():
710 compiz_widget_set(self, False)
711 else:
712+ if self.get_window():
713+ self.save_settings()
714 if has_widget_layer():
715 self.show()
716 compiz_widget_set(self, True)
717 else:
718 self.hide()
719
720- self.__settings.save()
721-
722 def close(self):
723- self.emit('removed')
724- self.__settings.delete()
725 self.destroy()
726
727 def get_menu_item_name(self, item):
728 """Return the menu item name of item."""
729 if item[DATE] > 0:
730 tt = time.localtime(item[DATE])
731+ # Translators: This is a date/time format string. You can check the
732+ # output in terminal with 'date +"%%A %d %B"'.
733 return time.strftime(_('%A %d %B'), tt)
734 else:
735 return item[TITLE]
736@@ -335,49 +338,64 @@
737
738 ctx.restore()
739
740- def make_file_type_chooser(self):
741- """Add the possible image types to the file chooser dialog."""
742- combo = self.__ui.get_object('file_format_combo')
743- model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
744- gobject.TYPE_STRING)
745- for format in gdk.pixbuf_get_formats():
746- if format['is_writable']:
747- text = '%s (*.%s)' % (format['description'],
748- format['extensions'][0])
749- model.append((format['description'], format['name'],
750- format['extensions'][0]))
751- combo.set_model(model)
752- combo.set_active(0)
753-
754 def make_menu(self):
755 """Create the context menu."""
756+ menu = gtk.Menu()
757+
758 # Generate history menu
759- history_menu = self.__ui.get_object('history_menu')
760- history_menu.foreach(lambda child: history_menu.remove(child))
761- items = self.feeds.feeds[self.feed_name].items.items()
762- items.sort(reverse=True)
763- for date, item in items:
764- label = gtk.Label()
765- text = self.get_menu_item_name(item)
766- if self.__current_timestamp == date:
767- label.set_markup('<b>' + text + '</b>')
768- else:
769- label.set_markup(text)
770- align = gtk.Alignment(xalign=0.0)
771- align.add(label)
772- menu_item = gtk.MenuItem()
773- menu_item.data = item
774- menu_item.connect('activate', self.on_history_activated)
775- menu_item.add(align)
776- history_menu.append(menu_item)
777- history_menu.show_all()
778- self.__ui.get_object('show_link_item').set_active(self.show_link)
779- self.__ui.get_object('history_container').set_sensitive(
780- len(self.feeds.feeds[self.feed_name].items) > 0)
781- self.__ui.get_object('save_as_item').set_sensitive(not self.__pixbuf \
782- is None)
783-
784- return self.__ui.get_object('menu')
785+ if len(self.feeds.feeds[self.feed_name].items) > 1:
786+ history_container = gtk.ImageMenuItem(gtk.STOCK_JUMP_TO)
787+ history_menu = gtk.Menu()
788+ history_menu.foreach(lambda child: history_menu.remove(child))
789+ items = self.feeds.feeds[self.feed_name].items.items()
790+ items.sort(reverse=True)
791+ for date, item in items:
792+ label = gtk.Label()
793+ text = self.get_menu_item_name(item)
794+ if self.__current_timestamp == date:
795+ label.set_markup('<b>' + text + '</b>')
796+ else:
797+ label.set_markup(text)
798+ align = gtk.Alignment(xalign=0.0)
799+ align.add(label)
800+ menu_item = gtk.MenuItem()
801+ menu_item.data = item
802+ menu_item.connect('activate', self.on_history_activated)
803+ menu_item.add(align)
804+ history_menu.append(menu_item)
805+ history_container.set_submenu(history_menu)
806+ menu.append(history_container)
807+
808+ size_container = gtk.MenuItem(_("Size"))
809+ size_menu = gtk.Menu()
810+ zoom_normal_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_100)
811+ zoom_normal_item.connect('activate', self.on_normal_activated)
812+ zoom_in_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN)
813+ zoom_in_item.connect('activate', self.on_larger_activated)
814+ zoom_out_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_OUT)
815+ zoom_out_item.connect('activate', self.on_smaller_activated)
816+ size_menu.append(zoom_normal_item)
817+ size_menu.append(zoom_in_item)
818+ size_menu.append(zoom_out_item)
819+ size_container.set_submenu(size_menu)
820+ menu.append(size_container)
821+
822+ show_link_item = gtk.CheckMenuItem(_("Show link"))
823+ show_link_item.set_active(self.show_link)
824+ show_link_item.connect('toggled', self.on_show_link_toggled)
825+ menu.append(show_link_item)
826+
827+ save_as_item = gtk.ImageMenuItem(stock_id='gtk-save-as')
828+ save_as_item.set_sensitive(not self.__pixbuf is None)
829+ save_as_item.connect('activate', self.on_save_as_activated)
830+ menu.append(save_as_item)
831+
832+ close_item = gtk.ImageMenuItem(stock_id='gtk-close')
833+ close_item.connect('activate', self.on_close_activated)
834+ menu.append(close_item)
835+
836+ menu.show_all()
837+ return menu
838
839 ########################################################################
840 # Standard python methods #
841@@ -399,9 +417,6 @@
842 except Exception:
843 self.__pixbuf = None
844 self.__is_error = False
845- self.__ui = gtk.Builder()
846- self.__ui.add_from_file(UI_FILE)
847- self.make_file_type_chooser()
848 self.__link = WWWLink('', '', LINK_FONTSIZE)
849 self.__link.connect('size-allocate', self.on_link_size_allocate)
850 self.__ticker = Ticker((20.0, 20.0))
851@@ -412,7 +427,6 @@
852 # Connect events
853 self.connect('destroy', self.on_destroy)
854 self.feeds.connect('feed-changed', self.on_feed_changed)
855- self.__ui.connect_signals(self)
856
857 # Build UI
858 self.__link.connect('button-press-event', self.on_link_clicked)
859@@ -422,9 +436,10 @@
860
861 self.set_skip_taskbar_hint(True)
862 self.set_skip_pager_hint(True)
863- self.set_visibility(visible)
864
865 self.load_settings()
866+ if visible:
867+ self.set_visibility(visible)
868
869 ########################################################################
870 # Property updating methods #
871@@ -432,14 +447,9 @@
872
873 def load_settings(self):
874 """Load the settings."""
875- screen = self.get_screen()
876- w, h = self.get_size()
877-
878 self.set_show_link(self.__settings.get_bool('show_link',
879 False))
880 self.set_feed_name(self.__settings.get_string('feed_name', ''))
881- self.move(self.__settings.get_int('x', (screen.get_width() - w) / 2),
882- self.__settings.get_int('y', (screen.get_height() - h) / 2))
883
884 def save_settings(self):
885 """Save the settings."""
886@@ -484,6 +494,8 @@
887 ########################################################################
888
889 def on_destroy(self, widget):
890+ self.emit('removed')
891+ self.__settings.delete()
892 if self.__update_id:
893 self.feeds.feeds[self.feed_name].disconnect(self.__update_id)
894 self.__update_id = None
895@@ -516,33 +528,55 @@
896 self.close()
897
898 def on_save_as_activated(self, widget):
899- dialog = self.__ui.get_object('save_as_dialog')
900- dialog.set_title(self.feed_name)
901- combo = self.__ui.get_object('file_format_combo')
902- model, iterator = combo.get_model(), combo.get_active_iter()
903- format = model.get_value(iterator, 1)
904- ext = model.get_value(iterator, 2)
905- dialog.set_current_name('%s.%s' % (self.__link.text, ext))
906- if dialog.run():
907- model, iterator = combo.get_model(), combo.get_active_iter()
908- format = model.get_value(iterator, 1)
909+ """Run FileChooserDialog and save file."""
910+ self.dialog = gtk.FileChooserDialog(_("Save comic as…"), \
911+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
912+ gtk.STOCK_SAVE, gtk.RESPONSE_OK), \
913+ action=gtk.FILE_CHOOSER_ACTION_SAVE)
914+ self.dialog.set_icon_from_file(os.path.join(UI_DIR, 'comics.svg'))
915+ self.dialog.set_do_overwrite_confirmation(True)
916+ self.dialog.set_current_name(self.__link.text + '.jpg')
917+
918+ # Set filters, default jpg, without ico
919+ for format in gdk.pixbuf_get_formats():
920+ if format['is_writable'] and format['name'] != 'ico':
921+ ff = gtk.FileFilter()
922+ ff.set_name(format['description'])
923+ for i in format['mime_types']:
924+ ff.add_mime_type(i)
925+ self.dialog.add_filter(ff)
926+ if format['name'] == 'jpeg':
927+ self.dialog.set_filter(ff)
928+ self.dialog.connect('notify::filter', self.on_filter_changed)
929+
930+ if self.dialog.run() == gtk.RESPONSE_OK:
931+ ff = gtk.FileFilter()
932+ ff = self.dialog.get_filter()
933+ name = ff.get_name()
934+ for format in gdk.pixbuf_get_formats():
935+ if format['description'] == name:
936+ name = format['name']
937+ break
938 try:
939- self.__pixbuf.save(dialog.get_filename(), format)
940+ self.__pixbuf.save(self.dialog.get_filename(), name)
941 except Exception:
942 self.applet.show_message(_('Failed to save <i>%s</i>.') %
943- dialog.get_filename(), gtk.STOCK_DIALOG_ERROR)
944-
945- dialog.hide()
946-
947- def on_file_format_combo_changed(self, widget):
948- dialog = self.__ui.get_object('save_as_dialog')
949- current_name = dialog.get_filename().rsplit('.', 1)
950+ self.dialog.get_filename(), gtk.STOCK_DIALOG_ERROR)
951+ self.dialog.destroy()
952+
953+ def on_filter_changed(self, pspec, data):
954+ """Change filename extension."""
955+ current_name = self.dialog.get_filename().rsplit('.', 1)
956 if len(current_name) == 2:
957- combo = widget
958- model, iterator = combo.get_model(), combo.get_active_iter()
959- ext = model.get_value(iterator, 2)
960- dialog.set_current_name('%s.%s' % (
961- os.path.basename(current_name[0]), ext))
962+ ff = gtk.FileFilter()
963+ ff = self.dialog.get_filter()
964+ for i in gdk.pixbuf_get_formats():
965+ if i['description'] == ff.get_name():
966+ for ext in i['extensions']:
967+ if current_name[1] == ext:
968+ return
969+ self.dialog.set_current_name('%s.%s' % (
970+ os.path.basename(current_name[0]), i['extensions'][0]))
971
972 def on_link_size_allocate(self, widget, e):
973 i_dim = self.get_image_dimensions()
974@@ -578,7 +612,8 @@
975 # Only emit the updated signal when there actually is an update
976 if self.__current_timestamp != 0.0:
977 self.emit('updated', feed.items[feed.newest][TITLE])
978- self.select_item(feed.items[feed.newest])
979+ if feed.newest in feed.items:
980+ self.select_item(feed.items[feed.newest])
981
982 def on_download_completed(self, o, code, item):
983 """A new image has been downloaded."""
984@@ -593,7 +628,11 @@
985 self.__download_id = None
986
987 if not self.__is_error:
988- del self.__pixbuf
989+ try:
990+ del self.__pixbuf
991+ except AttributeError:
992+ # Received destroy signal after download was initiated
993+ return
994 try:
995 self.__pixbuf = gdk.pixbuf_new_from_file(o.filename)
996 except gobject.GError:
997
998=== modified file 'applets/maintained/comics/feed/__init__.py'
999--- applets/maintained/comics/feed/__init__.py 2010-01-04 07:37:45 +0000
1000+++ applets/maintained/comics/feed/__init__.py 2011-01-09 09:07:16 +0000
1001@@ -40,14 +40,14 @@
1002 of factories. If filename does not contain a feed factory, it is not
1003 added."""
1004 try:
1005- module = __import__('plugins.%s' % name, fromlist=[name])
1006+ module = __import__('plugins.%s' % name, globals(), locals(), [name], -1)
1007 if hasattr(module, 'matches_url') and hasattr(module, 'get_class'):
1008- self.feed_factories.append(module)
1009+ self.feed_factories[name] = module
1010 return True
1011 else:
1012 del module
1013- except Exception:
1014- pass
1015+ except Exception, err:
1016+ print "Comics!: Error loading plugin: %s" % err
1017
1018 return False
1019
1020@@ -75,14 +75,15 @@
1021 if plugin in self.feed_factories:
1022 factory = self.feed_factories[plugin].get_class()
1023 else:
1024+ print "Comics!: Plugin '%s' not found" % plugin
1025 return False
1026 else:
1027 factory = RSSFeed
1028 feed = factory(settings)
1029 self.feeds[settings[NAME]] = feed
1030 self.emit('feed-changed', feed, FeedContainer.FEED_ADDED)
1031- except Exception:
1032- pass
1033+ except Exception, err:
1034+ print "Comics!: Error loading feed: %s" % err
1035
1036 return False
1037
1038@@ -90,8 +91,8 @@
1039 """Creates a feed suitable for a given URL. If no plugin matches the
1040 URL, an RSSFeed is returned."""
1041 for factory in self.feed_factories:
1042- if factory.matches_url(url):
1043- return factory.get_class()(url=url)
1044+ if self.feed_factories[factory].matches_url(url):
1045+ return self.feed_factories[factory].get_class()(url=url)
1046 return RSSFeed(url=url)
1047
1048 def remove_feed(self, feed_name):
1049
1050=== modified file 'applets/maintained/comics/feed/basic.py'
1051--- applets/maintained/comics/feed/basic.py 2010-01-04 07:36:10 +0000
1052+++ applets/maintained/comics/feed/basic.py 2011-01-09 09:07:16 +0000
1053@@ -23,15 +23,23 @@
1054 import urllib
1055 import urlparse
1056 import threading
1057+import htmlentitydefs
1058+import httplib
1059+import time
1060
1061 from settings import Settings
1062
1063 NAME = 'name'
1064 URL = 'url'
1065+PLUGIN = 'plugin'
1066 TITLE = 'title'
1067 LINK = 'link'
1068 DATE = 'date'
1069
1070+month = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04',
1071+ 'May': '05', 'Jun': '06', 'Jul': '07', 'Aug': '08',
1072+ 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}
1073+
1074
1075 class Feed(gobject.GObject):
1076 """A feed class."""
1077@@ -58,8 +66,83 @@
1078 elif parsed[0][2][0] == '/':
1079 return parsed[1][0] + '://' + parsed[1][1] + parsed[0][2]
1080 else:
1081+ # TODO this didn't work for some (or all?) urls,
1082+ # like http://www.gwscomic.com - test more thoroughly whether
1083+ # there should be an elif for that
1084+ #return parsed[1][0] + '://' + parsed[1][1] \
1085+ # + parsed[1][2].rsplit('/', 1)[0] + parsed[0][2]
1086 return parsed[1][0] + '://' + parsed[1][1] \
1087- + parsed[1][2].rsplit('/', 1)[0] + parsed[0][2]
1088+ + '/' + parsed[0][2]
1089+
1090+ def get_timestamp_for_url(self, url):
1091+ """Request the "Last-Modified" header from url without downloading
1092+ any data and return a timestamp or None"""
1093+ if url is None or len(url) == 0:
1094+ return None
1095+ p = urlparse.urlparse(url)
1096+ try:
1097+ if p.scheme == 'http':
1098+ conn = httplib.HTTPConnection(p.netloc)
1099+ elif p.scheme == 'https':
1100+ conn = httplib.HTTPSConnection(p.netloc)
1101+ else:
1102+ raise Exception
1103+ conn.request("HEAD", p.path)
1104+ res = conn.getresponse()
1105+ htime = res.getheader("Last-Modified")
1106+ except Exception:
1107+ return None
1108+
1109+ # Based on a posting by Philip Semanchuk, Nov 2009 on
1110+ # http://mail.python.org/mailman/listinfo/python-list
1111+
1112+ try:
1113+ if not htime.endswith("GMT"):
1114+ # ASCTIME format
1115+ # Work around locale problems: remove weedays,
1116+ # convert month names to decimals
1117+ htime = htime[4:]
1118+ htime = month[htime[0:3]] + htime[3:]
1119+ timestamp = time.strptime(htime, "%m %d %H:%M:%S %Y")
1120+ else:
1121+ # RFC 850 Format
1122+ if "-" in htime:
1123+ htime = htime.split(" ", 1)[1]
1124+ htime = htime[:3] + month[htime[3:6]] + htime[6:]
1125+ timestamp = time.strptime(htime, "%d-%m-%y %H:%M:%S GMT")
1126+ else:
1127+ # RFC 1123 Format
1128+ htime = htime[5:]
1129+ htime = htime[:3] + month[htime[3:6]] + htime[6:]
1130+ timestamp = time.strptime(htime, "%d %m %Y %H:%M:%S GMT")
1131+ timestamp = time.mktime(timestamp)
1132+ except Exception, err:
1133+ print "Comics!: %s" % err
1134+ return None
1135+ return timestamp
1136+
1137+ def unescape_html(self, text):
1138+ """Taken from Fredrik Lundh -
1139+ http://effbot.org/zone/re-sub.htm#unescape-html"""
1140+ def fixup(m):
1141+ text = m.group(0)
1142+ if text[:2] == "&#":
1143+ # character reference
1144+ try:
1145+ if text[:3] == "&#x":
1146+ return unichr(int(text[3:-1], 16))
1147+ else:
1148+ return unichr(int(text[2:-1]))
1149+ except ValueError:
1150+ pass
1151+ else:
1152+ # named entity
1153+ try:
1154+ text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
1155+ except KeyError:
1156+ pass
1157+ return text # leave as is
1158+ return re.sub("&#?\w+;", fixup, text)
1159
1160 def __init__(self, settings=None, url=None):
1161 """Initialize a feed."""
1162@@ -88,23 +171,21 @@
1163 """The thread body."""
1164 if not self.__lock.acquire(False):
1165 return
1166+ old_status = self.status
1167+ self.updated = False
1168 try:
1169- old_status = self.status
1170- try:
1171- self.updated = False
1172- filename, headers = urllib.urlretrieve(self.url)
1173- self.status = self.parse_file(filename)
1174- finally:
1175- pass
1176- #except Exception:
1177- # self.status = Feed.DOWNLOAD_FAILED
1178-
1179+ filename, headers = urllib.urlretrieve(self.url)
1180+ self.status = self.parse_file(filename)
1181 # If the status has changed, the feed is considered updated
1182 if self.updated or old_status != self.status:
1183 gobject.idle_add(gobject.GObject.emit, self, 'updated',
1184 self.status)
1185- finally:
1186- self.__lock.release()
1187+ except IOError: # Network is down
1188+ self.status = Feed.DOWNLOAD_FAILED
1189+ except Exception, err:
1190+ self.status = Feed.DOWNLOAD_FAILED
1191+ print "Comics!: Parsing error: %s" % err
1192+ self.__lock.release()
1193
1194 def update(self):
1195 """Reload the feed."""
1196
1197=== added file 'applets/maintained/comics/feed/plugins/__init__.py'
1198--- applets/maintained/comics/feed/plugins/__init__.py 1970-01-01 00:00:00 +0000
1199+++ applets/maintained/comics/feed/plugins/__init__.py 2011-01-09 09:07:16 +0000
1200@@ -0,0 +1,18 @@
1201+# -*- coding: utf-8 -*-
1202+
1203+# Copyright (c) 2010 Gabor Karsay
1204+#
1205+# This library is free software; you can redistribute it and/or
1206+# modify it under the terms of the GNU Lesser General Public
1207+# License as published by the Free Software Foundation; either
1208+# version 2 of the License, or (at your option) any later version.
1209+#
1210+# This library is distributed in the hope that it will be useful,
1211+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1212+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1213+# Lesser General Public License for more details.
1214+#
1215+# You should have received a copy of the GNU Lesser General Public
1216+# License along with this library; if not, write to the
1217+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1218+# Boston, MA 02111-1307, USA.
1219
1220=== added file 'applets/maintained/comics/feed/plugins/simple_screen_scraper.py'
1221--- applets/maintained/comics/feed/plugins/simple_screen_scraper.py 1970-01-01 00:00:00 +0000
1222+++ applets/maintained/comics/feed/plugins/simple_screen_scraper.py 2011-01-09 09:07:16 +0000
1223@@ -0,0 +1,112 @@
1224+# -*- coding: utf-8 -*-
1225+
1226+# Copyright (c) 2010 Gabor Karsay
1227+#
1228+# This library is free software; you can redistribute it and/or
1229+# modify it under the terms of the GNU Lesser General Public
1230+# License as published by the Free Software Foundation; either
1231+# version 2 of the License, or (at your option) any later version.
1232+#
1233+# This library is distributed in the hope that it will be useful,
1234+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1235+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1236+# Lesser General Public License for more details.
1237+#
1238+# You should have received a copy of the GNU Lesser General Public
1239+# License along with this library; if not, write to the
1240+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1241+# Boston, MA 02111-1307, USA.
1242+
1243+from __future__ import with_statement
1244+
1245+import feedparser
1246+import re
1247+
1248+from ..basic import URL, TITLE, LINK, DATE, Feed
1249+from ..rss import IMAGES
1250+
1251+
1252+def get_class():
1253+ '''Mandatory for plugins.'''
1254+ return SimpleScreenScraper
1255+
1256+
1257+def matches_url(url):
1258+ '''Mandatory for plugins.
1259+ Return True if we want to read a comic from this url, else return False.
1260+ SimpleScreenScraper accepts all urls that are not feeds.'''
1261+ try:
1262+ feed = feedparser.parse(url)
1263+ if feed.version == '':
1264+ return True
1265+ except Exception:
1266+ return True
1267+ return False
1268+
1269+
1270+class SimpleScreenScraper(Feed):
1271+ """A SimpleScreenScraper class."""
1272+
1273+ def __init__(self, settings=None, url=None):
1274+ super(SimpleScreenScraper, self).__init__(settings, url)
1275+ if settings:
1276+ self.img_index = settings.get_int('img_index', 1) - 1
1277+ else:
1278+ self.img_index = 0
1279+
1280+ def parse_file(self, filename):
1281+ '''Mandatory for plugins.
1282+ Parses given file (a downloaded feed) and puts each found item
1283+ into a dict with the keys URL (path to the image), LINK to the
1284+ page, TITLE for that link, DATE (a timestamp) and IMAGES (list of
1285+ images, only needed for new comics).
1286+ Each of this dicts has to be put into self.items with DATE as key.'''
1287+ try:
1288+ with open(filename, 'r') as f:
1289+ data = f.read()
1290+ except IOError:
1291+ return Feed.DOWNLOAD_FAILED
1292+
1293+ # Update properties
1294+ if self.name is None:
1295+ title_re = re.compile("<title>(.*?)<\/title>", re.DOTALL |
1296+ re.M |
1297+ re.IGNORECASE)
1298+ try:
1299+ self.name = self.unescape_html(title_re.findall(data)[0])
1300+ except IndexError:
1301+ self.name = "Comic"
1302+
1303+
1304+ images = []
1305+ images += [self.make_absolute_url(u, self.url)
1306+ for u in Feed.IMG_SRC_RE.findall(data)]
1307+
1308+ item = {}
1309+ try:
1310+ item[URL] = images[self.img_index]
1311+ except IndexError:
1312+ print "Comics!: img_index out of range in '%s'." % self.name
1313+ return Feed.DOWNLOAD_NOT_FEED
1314+ item[LINK] = self.url
1315+ item[TITLE] = self.name
1316+ item[DATE] = self.get_timestamp_for_url(item[URL])
1317+ if item[DATE] == None:
1318+ item[DATE] = 1.0
1319+ item[IMAGES] = images
1320+
1321+ self.items[item[DATE]] = item
1322+
1323+ if self.newest != item[DATE]:
1324+ self.newest = item[DATE]
1325+ self.updated = True
1326+ return Feed.DOWNLOAD_OK
1327+
1328+ def get_unique_images(self):
1329+ """Mandatory for plugins.
1330+ Returns a list of (index, url) tuples for the images."""
1331+ if len(self.items) == 0:
1332+ return None
1333+ items = self.items.itervalues()
1334+ item = items.next()
1335+ return list(enumerate(item[IMAGES]))
1336
1337=== modified file 'applets/maintained/comics/feed/rss.py'
1338--- applets/maintained/comics/feed/rss.py 2010-01-04 07:40:00 +0000
1339+++ applets/maintained/comics/feed/rss.py 2011-01-09 09:07:16 +0000
1340@@ -89,9 +89,9 @@
1341
1342 # Update properties
1343 if 'description' in feed:
1344- self.description = feed.description
1345+ self.description = self.unescape_html(feed.description)
1346 if 'title' in feed.feed:
1347- self.name = feed.feed.title
1348+ self.name = self.unescape_html(feed.feed.title)
1349
1350 # Create an item-thread tuple for every entry
1351 threads = []
1352
1353=== added file 'applets/maintained/comics/feeds/ben.feed'
1354--- applets/maintained/comics/feeds/ben.feed 1970-01-01 00:00:00 +0000
1355+++ applets/maintained/comics/feeds/ben.feed 2011-01-09 09:07:16 +0000
1356@@ -0,0 +1,7 @@
1357+# Automatically generated by comics
1358+
1359+url=http://comics.com/ben/
1360+plugin=simple_screen_scraper
1361+name=Ben
1362+# The index of the image in the HTML-code
1363+img_index=4
1364
1365=== modified file 'applets/maintained/comics/feeds/buttersafe.feed'
1366--- applets/maintained/comics/feeds/buttersafe.feed 2009-01-29 04:55:04 +0000
1367+++ applets/maintained/comics/feeds/buttersafe.feed 2011-01-09 09:07:16 +0000
1368@@ -1,6 +1,6 @@
1369 # Automatically generated by comics
1370
1371-url=http://feeds.feedburner.com/Buttersafe
1372-name=Buttersafe
1373+url=http://feeds.feedburner.com/buttersafe
1374+name=Buttersafe - Updated Tuesdays and Thursdays
1375 # The index of the image in the HTML-code
1376-img_index=4
1377+img_index=5
1378
1379=== added file 'applets/maintained/comics/feeds/calvinandhobbes.feed'
1380--- applets/maintained/comics/feeds/calvinandhobbes.feed 1970-01-01 00:00:00 +0000
1381+++ applets/maintained/comics/feeds/calvinandhobbes.feed 2011-01-09 09:07:16 +0000
1382@@ -0,0 +1,6 @@
1383+# Automatically generated by comics
1384+
1385+url=http://feeds.feedburner.com/uclick/calvinandhobbes
1386+name=Calvin and Hobbes
1387+# The index of the image in the HTML-code
1388+img_index=27
1389
1390=== added file 'applets/maintained/comics/feeds/ferdnand.feed'
1391--- applets/maintained/comics/feeds/ferdnand.feed 1970-01-01 00:00:00 +0000
1392+++ applets/maintained/comics/feeds/ferdnand.feed 2011-01-09 09:07:16 +0000
1393@@ -0,0 +1,7 @@
1394+# Automatically generated by comics
1395+
1396+url=http://comics.com/ferdnand/
1397+plugin=simple_screen_scraper
1398+name=Ferd'nand
1399+# The index of the image in the HTML-code
1400+img_index=4
1401
1402=== added file 'applets/maintained/comics/feeds/garfield.feed'
1403--- applets/maintained/comics/feeds/garfield.feed 1970-01-01 00:00:00 +0000
1404+++ applets/maintained/comics/feeds/garfield.feed 2011-01-09 09:07:16 +0000
1405@@ -0,0 +1,6 @@
1406+# Automatically generated by comics
1407+
1408+url=http://feeds.feedburner.com/uclick/garfield
1409+name=Garfield
1410+# The index of the image in the HTML-code
1411+img_index=27
1412
1413=== added file 'applets/maintained/comics/feeds/nancy.feed'
1414--- applets/maintained/comics/feeds/nancy.feed 1970-01-01 00:00:00 +0000
1415+++ applets/maintained/comics/feeds/nancy.feed 2011-01-09 09:07:16 +0000
1416@@ -0,0 +1,7 @@
1417+# Automatically generated by comics
1418+
1419+url=http://comics.com/nancy/
1420+plugin=simple_screen_scraper
1421+name=Nancy
1422+# The index of the image in the HTML-code
1423+img_index=4
1424
1425=== added file 'applets/maintained/comics/feeds/pcnp.feed'
1426--- applets/maintained/comics/feeds/pcnp.feed 1970-01-01 00:00:00 +0000
1427+++ applets/maintained/comics/feeds/pcnp.feed 2011-01-09 09:07:16 +0000
1428@@ -0,0 +1,7 @@
1429+# Automatically generated by comics
1430+
1431+url=http://comics.com/pc_and_pixel/
1432+plugin=simple_screen_scraper
1433+name=PC and Pixel
1434+# The index of the image in the HTML-code
1435+img_index=4
1436
1437=== added file 'applets/maintained/comics/feeds/peanuts.feed'
1438--- applets/maintained/comics/feeds/peanuts.feed 1970-01-01 00:00:00 +0000
1439+++ applets/maintained/comics/feeds/peanuts.feed 2011-01-09 09:07:16 +0000
1440@@ -0,0 +1,7 @@
1441+# Automatically generated by comics
1442+
1443+url=http://comics.com/peanuts
1444+plugin=simple_screen_scraper
1445+name=Peanuts
1446+# The index of the image in the HTML-code
1447+img_index=6
1448
1449=== removed file 'applets/maintained/comics/feeds/peanuts.feed'
1450--- applets/maintained/comics/feeds/peanuts.feed 2008-12-11 22:58:58 +0000
1451+++ applets/maintained/comics/feeds/peanuts.feed 1970-01-01 00:00:00 +0000
1452@@ -1,2 +0,0 @@
1453-name=Peanuts
1454-url=http://feeds.feedburner.com/tapestrypeanuts
1455
1456=== modified file 'applets/maintained/comics/feeds/pearls.feed'
1457--- applets/maintained/comics/feeds/pearls.feed 2008-02-23 15:38:06 +0000
1458+++ applets/maintained/comics/feeds/pearls.feed 2011-01-09 09:07:16 +0000
1459@@ -1,5 +1,7 @@
1460-# Feed description
1461-
1462-name=Pearls before Swine
1463-url=http://feeds.feedburner.com/tapestrypearls
1464-
1465+# Automatically generated by comics
1466+
1467+url=http://comics.com/pearls_before_swine/
1468+plugin=simple_screen_scraper
1469+name=Pearls Before Swine
1470+# The index of the image in the HTML-code
1471+img_index=4
1472
1473=== added file 'applets/maintained/comics/feeds/pickles.feed'
1474--- applets/maintained/comics/feeds/pickles.feed 1970-01-01 00:00:00 +0000
1475+++ applets/maintained/comics/feeds/pickles.feed 2011-01-09 09:07:16 +0000
1476@@ -0,0 +1,6 @@
1477+# Automatically generated by comics
1478+
1479+url=http://feeds.feedburner.com/uclick/pickles
1480+name=Pickles
1481+# The index of the image in the HTML-code
1482+img_index=26
1483
1484=== added file 'applets/maintained/comics/feeds/userfriendly.feed'
1485--- applets/maintained/comics/feeds/userfriendly.feed 1970-01-01 00:00:00 +0000
1486+++ applets/maintained/comics/feeds/userfriendly.feed 2011-01-09 09:07:16 +0000
1487@@ -0,0 +1,7 @@
1488+# Automatically generated by comics
1489+
1490+url=http://www.userfriendly.org/static/
1491+plugin=simple_screen_scraper
1492+name=UserFriendly.Org
1493+# The index of the image in the HTML-code
1494+img_index=4
1495
1496=== modified file 'applets/maintained/comics/feeds/wizardofid.feed'
1497--- applets/maintained/comics/feeds/wizardofid.feed 2009-01-19 18:50:48 +0000
1498+++ applets/maintained/comics/feeds/wizardofid.feed 2011-01-09 09:07:16 +0000
1499@@ -1,3 +1,6 @@
1500-name=Wizard of ID
1501-url=http://feeds.gocomics.com/uclick/wizardofid
1502-img_index=17
1503+# Automatically generated by comics
1504+
1505+url=http://feeds.feedburner.com/uclick/wizardofid
1506+name=Wizard of Id
1507+# The index of the image in the HTML-code
1508+img_index=26
1509
1510=== modified file 'applets/maintained/comics/ui/add.ui'
1511--- applets/maintained/comics/ui/add.ui 2010-01-26 03:46:15 +0000
1512+++ applets/maintained/comics/ui/add.ui 2011-01-09 09:07:16 +0000
1513@@ -1,77 +1,249 @@
1514 <?xml version="1.0"?>
1515-<!--Generated with glade3 3.4.0 on Thu Feb 21 11:37:45 2008 -->
1516 <interface>
1517+ <!-- interface-requires gtk+ 2.12 -->
1518+ <!-- interface-naming-policy toplevel-contextual -->
1519 <object class="GtkAssistant" id="add_assistant">
1520 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1521- <property name="border_width">4</property>
1522+ <property name="border_width">12</property>
1523 <property name="title" translatable="yes">Add Comic</property>
1524- <property name="window_position">GTK_WIN_POS_CENTER</property>
1525+ <property name="window_position">center</property>
1526 <property name="icon">comics.svg</property>
1527- <signal handler="on_add_assistant_close" name="close"/>
1528- <signal handler="on_add_assistant_cancel" name="cancel"/>
1529- <signal handler="on_add_assistant_apply" name="apply"/>
1530- <signal handler="on_add_assistant_prepare" name="prepare"/>
1531+ <signal name="apply" handler="on_add_assistant_apply"/>
1532+ <signal name="prepare" handler="on_add_assistant_prepare"/>
1533+ <signal name="cancel" handler="on_add_assistant_cancel"/>
1534+ <signal name="close" handler="on_add_assistant_close"/>
1535+ <child>
1536+ <placeholder/>
1537+ </child>
1538+ <child>
1539+ <placeholder/>
1540+ </child>
1541 <child>
1542 <object class="GtkVBox" id="intro_page">
1543 <property name="visible">True</property>
1544 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1545- <property name="spacing">10</property>
1546- <child>
1547- <object class="GtkLabel" id="intro_label">
1548+ <property name="border_width">12</property>
1549+ <property name="spacing">12</property>
1550+ <child>
1551+ <placeholder/>
1552+ </child>
1553+ <child>
1554+ <object class="GtkVBox" id="vbox2">
1555 <property name="visible">True</property>
1556- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1557- <property name="xalign">0</property>
1558- <property name="yalign">0</property>
1559- <property name="label" translatable="yes">This guide will help you to add a new comic.
1560-
1561-To find comics suitable for adding, you may search the Internet for "comics rss".
1562-
1563-Press "next" to proceed.</property>
1564- <property name="wrap">True</property>
1565+ <property name="spacing">12</property>
1566+ <child>
1567+ <object class="GtkLabel" id="intro_label">
1568+ <property name="visible">True</property>
1569+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1570+ <property name="xalign">0</property>
1571+ <property name="yalign">0</property>
1572+ <property name="label" translatable="yes">This guide will help you to add a new comic.</property>
1573+ <property name="use_markup">True</property>
1574+ <property name="wrap">True</property>
1575+ </object>
1576+ <packing>
1577+ <property name="position">0</property>
1578+ </packing>
1579+ </child>
1580+ <child>
1581+ <object class="GtkLabel" id="intro_label2">
1582+ <property name="visible">True</property>
1583+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1584+ <property name="xalign">0</property>
1585+ <property name="yalign">0</property>
1586+ <property name="label" translatable="yes">Please select how you want to add a comic:</property>
1587+ <property name="use_markup">True</property>
1588+ <property name="wrap">True</property>
1589+ </object>
1590+ <packing>
1591+ <property name="position">1</property>
1592+ </packing>
1593+ </child>
1594+ <child>
1595+ <placeholder/>
1596+ </child>
1597+ <child>
1598+ <placeholder/>
1599+ </child>
1600+ <child>
1601+ <object class="GtkAlignment" id="alignment1">
1602+ <property name="visible">True</property>
1603+ <property name="left_padding">12</property>
1604+ <child>
1605+ <object class="GtkVBox" id="vbox1">
1606+ <property name="visible">True</property>
1607+ <property name="spacing">6</property>
1608+ <child>
1609+ <object class="GtkRadioButton" id="list_radio">
1610+ <property name="label" translatable="yes">Select a comic from a list</property>
1611+ <property name="visible">True</property>
1612+ <property name="can_focus">True</property>
1613+ <property name="receives_default">False</property>
1614+ <property name="active">True</property>
1615+ <property name="draw_indicator">True</property>
1616+ <signal name="toggled" handler="on_radio_button_toggled"/>
1617+ </object>
1618+ <packing>
1619+ <property name="position">0</property>
1620+ </packing>
1621+ </child>
1622+ <child>
1623+ <object class="GtkRadioButton" id="url_radio">
1624+ <property name="label" translatable="yes">Add a comic by URL</property>
1625+ <property name="visible">True</property>
1626+ <property name="can_focus">True</property>
1627+ <property name="receives_default">False</property>
1628+ <property name="active">True</property>
1629+ <property name="draw_indicator">True</property>
1630+ <property name="group">list_radio</property>
1631+ </object>
1632+ <packing>
1633+ <property name="position">1</property>
1634+ </packing>
1635+ </child>
1636+ </object>
1637+ </child>
1638+ </object>
1639+ <packing>
1640+ <property name="position">4</property>
1641+ </packing>
1642+ </child>
1643 </object>
1644+ <packing>
1645+ <property name="expand">False</property>
1646+ <property name="fill">False</property>
1647+ <property name="position">1</property>
1648+ </packing>
1649 </child>
1650 </object>
1651 <packing>
1652- <property name="page_type">GTK_ASSISTANT_PAGE_INTRO</property>
1653+ <property name="page_type">intro</property>
1654 <property name="title" translatable="yes">Add Comic</property>
1655 <property name="sidebar_image">logo.svg</property>
1656 </packing>
1657 </child>
1658 <child>
1659+ <placeholder/>
1660+ </child>
1661+ <child>
1662 <object class="GtkVBox" id="url_page">
1663 <property name="visible">True</property>
1664 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1665- <property name="spacing">10</property>
1666- <child>
1667- <object class="GtkHBox" id="url_page_hbox">
1668- <property name="visible">True</property>
1669- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1670- <property name="spacing">10</property>
1671- <child>
1672- <object class="GtkLabel" id="url_page_label">
1673- <property name="visible">True</property>
1674- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1675- <property name="xalign">1</property>
1676- <property name="label" translatable="yes">Enter the URL of the RSS feed:</property>
1677- </object>
1678- <packing>
1679- <property name="expand">False</property>
1680- <property name="fill">False</property>
1681- </packing>
1682- </child>
1683- <child>
1684- <object class="GtkEntry" id="url_entry">
1685- <property name="visible">True</property>
1686- <property name="can_focus">True</property>
1687- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1688- <property name="text">http://</property>
1689- <signal handler="on_url_entry_changed" name="changed"/>
1690- </object>
1691- <packing>
1692- <property name="position">1</property>
1693- </packing>
1694- </child>
1695- </object>
1696+ <property name="border_width">12</property>
1697+ <property name="spacing">12</property>
1698+ <child>
1699+ <object class="GtkVBox" id="url_box">
1700+ <property name="visible">True</property>
1701+ <child>
1702+ <object class="GtkLabel" id="intro_label1">
1703+ <property name="visible">True</property>
1704+ <property name="can_focus">True</property>
1705+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1706+ <property name="xalign">0</property>
1707+ <property name="yalign">0</property>
1708+ <property name="label" translatable="yes">Comics! needs either an RSS feed or a web page with a comic.
1709+
1710+Comics from feeds contain several strips. You may find suitable feeds on dedicated comics websites like &lt;a href="http://www.gocomics.com/features/rsspage"&gt;gocomics.com&lt;/a&gt;.
1711+
1712+Using a web page only the current comic is shown. You'll find suitable web pages e.g. at &lt;a href="http://www.comics.com/"&gt;comics.com&lt;/a&gt; or searching the web for "comics" or "webcomics".</property>
1713+ <property name="use_markup">True</property>
1714+ <property name="wrap">True</property>
1715+ </object>
1716+ <packing>
1717+ <property name="expand">False</property>
1718+ <property name="fill">False</property>
1719+ <property name="position">0</property>
1720+ </packing>
1721+ </child>
1722+ <child>
1723+ <object class="GtkHBox" id="url_page_hbox">
1724+ <property name="visible">True</property>
1725+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1726+ <property name="spacing">10</property>
1727+ <child>
1728+ <object class="GtkLabel" id="url_page_label">
1729+ <property name="visible">True</property>
1730+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1731+ <property name="xalign">1</property>
1732+ <property name="label" translatable="yes">URL of the RSS feed or web page:</property>
1733+ </object>
1734+ <packing>
1735+ <property name="expand">False</property>
1736+ <property name="fill">False</property>
1737+ <property name="position">0</property>
1738+ </packing>
1739+ </child>
1740+ <child>
1741+ <object class="GtkEntry" id="url_entry">
1742+ <property name="visible">True</property>
1743+ <property name="can_focus">True</property>
1744+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1745+ <property name="invisible_char">&#x25CF;</property>
1746+ <property name="activates_default">True</property>
1747+ <property name="text">http://</property>
1748+ <signal name="changed" handler="on_url_entry_changed"/>
1749+ </object>
1750+ <packing>
1751+ <property name="position">1</property>
1752+ </packing>
1753+ </child>
1754+ </object>
1755+ <packing>
1756+ <property name="expand">False</property>
1757+ <property name="fill">False</property>
1758+ <property name="position">1</property>
1759+ </packing>
1760+ </child>
1761+ </object>
1762+ <packing>
1763+ <property name="expand">False</property>
1764+ <property name="fill">False</property>
1765+ <property name="position">0</property>
1766+ </packing>
1767+ </child>
1768+ <child>
1769+ <placeholder/>
1770+ </child>
1771+ <child>
1772+ <object class="GtkVBox" id="list_box">
1773+ <property name="visible">True</property>
1774+ <child>
1775+ <placeholder/>
1776+ </child>
1777+ <child>
1778+ <object class="GtkScrolledWindow" id="scrolledwindow1">
1779+ <property name="visible">True</property>
1780+ <property name="can_focus">True</property>
1781+ <property name="hscrollbar_policy">automatic</property>
1782+ <property name="vscrollbar_policy">automatic</property>
1783+ <child>
1784+ <object class="GtkTreeView" id="pre_list">
1785+ <property name="visible">True</property>
1786+ <property name="can_focus">True</property>
1787+ <property name="headers_visible">False</property>
1788+ <property name="rules_hint">True</property>
1789+ <child>
1790+ <object class="GtkTreeViewColumn" id="pre_col">
1791+ <property name="title">column</property>
1792+ <child>
1793+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
1794+ <attributes>
1795+ <attribute name="text">0</attribute>
1796+ </attributes>
1797+ </child>
1798+ </object>
1799+ </child>
1800+ </object>
1801+ </child>
1802+ </object>
1803+ <packing>
1804+ <property name="position">1</property>
1805+ </packing>
1806+ </child>
1807+ </object>
1808+ <packing>
1809+ <property name="position">2</property>
1810+ </packing>
1811 </child>
1812 </object>
1813 <packing>
1814@@ -79,9 +251,13 @@
1815 </packing>
1816 </child>
1817 <child>
1818+ <placeholder/>
1819+ </child>
1820+ <child>
1821 <object class="GtkVBox" id="wait_page">
1822 <property name="visible">True</property>
1823 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1824+ <property name="border_width">12</property>
1825 <property name="spacing">10</property>
1826 <child>
1827 <object class="GtkLabel" id="wait_label">
1828@@ -91,10 +267,13 @@
1829 <property name="yalign">0</property>
1830 <property name="wrap">True</property>
1831 </object>
1832+ <packing>
1833+ <property name="position">0</property>
1834+ </packing>
1835 </child>
1836 </object>
1837 <packing>
1838- <property name="page_type">GTK_ASSISTANT_PAGE_PROGRESS</property>
1839+ <property name="page_type">progress</property>
1840 <property name="title" translatable="yes">Downloading Comic</property>
1841 </packing>
1842 </child>
1843@@ -102,6 +281,7 @@
1844 <object class="GtkVBox" id="image_page">
1845 <property name="visible">True</property>
1846 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1847+ <property name="border_width">12</property>
1848 <property name="spacing">10</property>
1849 <child>
1850 <object class="GtkLabel" id="label_image_page">
1851@@ -115,6 +295,7 @@
1852 <packing>
1853 <property name="expand">False</property>
1854 <property name="fill">False</property>
1855+ <property name="position">0</property>
1856 </packing>
1857 </child>
1858 <child>
1859@@ -122,16 +303,21 @@
1860 <property name="visible">True</property>
1861 <property name="can_focus">True</property>
1862 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1863- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
1864- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
1865+ <property name="hscrollbar_policy">automatic</property>
1866+ <property name="vscrollbar_policy">automatic</property>
1867 <child>
1868 <object class="GtkIconView" id="image_list">
1869 <property name="visible">True</property>
1870 <property name="can_focus">True</property>
1871 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1872- <property name="pixbuf_column">1</property>
1873 <property name="item_width">100</property>
1874- <signal handler="on_image_list_selection_changed" name="selection_changed"/>
1875+ <signal name="selection_changed" handler="on_image_list_selection_changed"/>
1876+ <child>
1877+ <object class="GtkCellRendererPixbuf" id="cellrenderertext"/>
1878+ <attributes>
1879+ <attribute name="pixbuf">1</attribute>
1880+ </attributes>
1881+ </child>
1882 </object>
1883 </child>
1884 </object>
1885@@ -148,6 +334,7 @@
1886 <object class="GtkVBox" id="last_page">
1887 <property name="visible">True</property>
1888 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1889+ <property name="border_width">12</property>
1890 <property name="spacing">10</property>
1891 <child>
1892 <object class="GtkLabel" id="last_label">
1893@@ -159,12 +346,49 @@
1894 <property name="wrap">True</property>
1895 </object>
1896 <packing>
1897+ <property name="expand">False</property>
1898+ <property name="fill">False</property>
1899+ <property name="position">0</property>
1900+ </packing>
1901+ </child>
1902+ <child>
1903+ <object class="GtkHBox" id="name_box">
1904+ <property name="visible">True</property>
1905+ <property name="spacing">12</property>
1906+ <child>
1907+ <object class="GtkLabel" id="label1">
1908+ <property name="visible">True</property>
1909+ <property name="xalign">0</property>
1910+ <property name="label" translatable="yes">Name of the comic:</property>
1911+ </object>
1912+ <packing>
1913+ <property name="expand">False</property>
1914+ <property name="fill">False</property>
1915+ <property name="position">0</property>
1916+ </packing>
1917+ </child>
1918+ <child>
1919+ <object class="GtkEntry" id="name_entry">
1920+ <property name="visible">True</property>
1921+ <property name="can_focus">True</property>
1922+ <property name="invisible_char">&#x25CF;</property>
1923+ <property name="activates_default">True</property>
1924+ <signal name="changed" handler="on_name_entry_changed"/>
1925+ </object>
1926+ <packing>
1927+ <property name="position">1</property>
1928+ </packing>
1929+ </child>
1930+ </object>
1931+ <packing>
1932+ <property name="expand">False</property>
1933+ <property name="fill">False</property>
1934 <property name="position">1</property>
1935 </packing>
1936 </child>
1937 </object>
1938 <packing>
1939- <property name="page_type">GTK_ASSISTANT_PAGE_CONFIRM</property>
1940+ <property name="page_type">confirm</property>
1941 <property name="title" translatable="yes">Ready to add comic!</property>
1942 </packing>
1943 </child>
1944
1945=== modified file 'applets/maintained/comics/ui/manage.ui'
1946--- applets/maintained/comics/ui/manage.ui 2010-01-26 03:46:15 +0000
1947+++ applets/maintained/comics/ui/manage.ui 2011-01-09 09:07:16 +0000
1948@@ -1,45 +1,60 @@
1949 <?xml version="1.0"?>
1950-<!--Generated with glade3 3.4.0 on Thu Feb 21 11:35:04 2008 -->
1951 <interface>
1952+ <!-- interface-requires gtk+ 2.12 -->
1953+ <!-- interface-naming-policy toplevel-contextual -->
1954 <object class="GtkWindow" id="manage_window">
1955 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1956+ <property name="border_width">6</property>
1957 <property name="title" translatable="yes">Manage comics</property>
1958- <property name="window_position">GTK_WIN_POS_CENTER</property>
1959- <property name="default_width">300</property>
1960- <property name="default_height">400</property>
1961+ <property name="window_position">center</property>
1962 <property name="icon">manage.svg</property>
1963 <child>
1964 <object class="GtkVBox" id="manage_window_vbox">
1965 <property name="visible">True</property>
1966 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1967 <property name="border_width">2</property>
1968- <property name="spacing">5</property>
1969+ <property name="spacing">6</property>
1970 <child>
1971- <object class="GtkLabel" id="manage_window_label">
1972- <property name="visible">True</property>
1973- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1974- <property name="xalign">0</property>
1975- <property name="yalign">0</property>
1976- <property name="label" translatable="yes">The following comics are installed:</property>
1977- </object>
1978- <packing>
1979- <property name="expand">False</property>
1980- <property name="fill">False</property>
1981- </packing>
1982+ <placeholder/>
1983 </child>
1984 <child>
1985 <object class="GtkScrolledWindow" id="manage_window_scrolledwindow">
1986 <property name="visible">True</property>
1987 <property name="can_focus">True</property>
1988 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1989- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
1990- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
1991+ <property name="hscrollbar_policy">automatic</property>
1992+ <property name="vscrollbar_policy">automatic</property>
1993 <child>
1994 <object class="GtkTreeView" id="comics_list">
1995 <property name="visible">True</property>
1996 <property name="can_focus">True</property>
1997 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
1998- <property name="headers_visible">False</property>
1999+ <property name="headers_clickable">False</property>
2000+ <property name="rules_hint">True</property>
2001+ <child>
2002+ <object class="GtkTreeViewColumn" id="toggle_col">
2003+ <property name="title">column</property>
2004+ <child>
2005+ <object class="GtkCellRendererToggle" id="cellrenderertoggle1">
2006+ <signal name="toggled" handler="on_feed_toggled"/>
2007+ </object>
2008+ <attributes>
2009+ <attribute name="active">0</attribute>
2010+ </attributes>
2011+ </child>
2012+ </object>
2013+ </child>
2014+ <child>
2015+ <object class="GtkTreeViewColumn" id="name_col">
2016+ <property name="title">column</property>
2017+ <child>
2018+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
2019+ <attributes>
2020+ <attribute name="text">1</attribute>
2021+ </attributes>
2022+ </child>
2023+ </object>
2024+ </child>
2025 </object>
2026 </child>
2027 </object>
2028@@ -51,44 +66,55 @@
2029 <object class="GtkHButtonBox" id="manage_window_hbuttonbox">
2030 <property name="visible">True</property>
2031 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2032- <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
2033+ <property name="border_width">6</property>
2034+ <property name="spacing">6</property>
2035+ <property name="layout_style">spread</property>
2036 <child>
2037 <object class="GtkButton" id="add_button">
2038- <property name="visible">True</property>
2039- <property name="can_focus">True</property>
2040- <property name="receives_default">True</property>
2041- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2042 <property name="label">gtk-add</property>
2043+ <property name="visible">True</property>
2044+ <property name="can_focus">True</property>
2045+ <property name="receives_default">True</property>
2046+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2047 <property name="use_stock">True</property>
2048- <signal handler="on_add_button_clicked" name="clicked"/>
2049+ <signal name="clicked" handler="on_add_button_clicked"/>
2050 </object>
2051+ <packing>
2052+ <property name="expand">False</property>
2053+ <property name="fill">False</property>
2054+ <property name="position">0</property>
2055+ </packing>
2056 </child>
2057 <child>
2058 <object class="GtkButton" id="remove_button">
2059+ <property name="label">gtk-remove</property>
2060 <property name="visible">True</property>
2061 <property name="sensitive">False</property>
2062 <property name="can_focus">True</property>
2063 <property name="receives_default">True</property>
2064 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2065- <property name="label">gtk-remove</property>
2066 <property name="use_stock">True</property>
2067- <signal handler="on_remove_button_clicked" name="clicked"/>
2068+ <signal name="clicked" handler="on_remove_button_clicked"/>
2069 </object>
2070 <packing>
2071+ <property name="expand">False</property>
2072+ <property name="fill">False</property>
2073 <property name="position">1</property>
2074 </packing>
2075 </child>
2076 <child>
2077 <object class="GtkButton" id="close_button">
2078- <property name="visible">True</property>
2079- <property name="can_focus">True</property>
2080- <property name="receives_default">True</property>
2081- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2082 <property name="label">gtk-close</property>
2083+ <property name="visible">True</property>
2084+ <property name="can_focus">True</property>
2085+ <property name="receives_default">True</property>
2086+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2087 <property name="use_stock">True</property>
2088- <signal handler="on_close_button_clicked" name="clicked"/>
2089+ <signal name="clicked" handler="on_close_button_clicked"/>
2090 </object>
2091 <packing>
2092+ <property name="expand">False</property>
2093+ <property name="fill">False</property>
2094 <property name="position">2</property>
2095 </packing>
2096 </child>
2097
2098=== removed file 'applets/maintained/comics/ui/view.ui'
2099--- applets/maintained/comics/ui/view.ui 2010-03-25 12:38:35 +0000
2100+++ applets/maintained/comics/ui/view.ui 1970-01-01 00:00:00 +0000
2101@@ -1,154 +0,0 @@
2102-<?xml version="1.0"?>
2103-<interface>
2104- <!-- interface-requires gtk+ 2.12 -->
2105- <!-- interface-naming-policy toplevel-contextual -->
2106- <object class="GtkUIManager" id="uimanager1">
2107- <child>
2108- <object class="GtkActionGroup" id="actiongroup1">
2109- <child>
2110- <object class="GtkAction" id="history_container">
2111- <property name="stock_id">gtk-jump-to</property>
2112- <property name="name">history_container</property>
2113- </object>
2114- </child>
2115- <child>
2116- <object class="GtkAction" id="size_container">
2117- <property name="name">size_container</property>
2118- <property name="label" translatable="yes">Size</property>
2119- </object>
2120- </child>
2121- <child>
2122- <object class="GtkAction" id="zoom_normal_item">
2123- <property name="stock_id">gtk-zoom-100</property>
2124- <property name="name">zoom_normal_item</property>
2125- <signal handler="on_normal_activated" name="activate"/>
2126- </object>
2127- </child>
2128- <child>
2129- <object class="GtkAction" id="zoom_in_item">
2130- <property name="stock_id">gtk-zoom-in</property>
2131- <property name="name">zoom_in_item</property>
2132- <signal handler="on_larger_activated" name="activate"/>
2133- </object>
2134- </child>
2135- <child>
2136- <object class="GtkAction" id="zoom_out_item">
2137- <property name="stock_id">gtk-zoom-out</property>
2138- <property name="name">zoom_out_item</property>
2139- <signal handler="on_smaller_activated" name="activate"/>
2140- </object>
2141- </child>
2142- <child>
2143- <object class="GtkToggleAction" id="show_link_item">
2144- <property name="name">show_link_item</property>
2145- <property name="label" translatable="yes">Show link</property>
2146- <signal handler="on_show_link_toggled" name="toggled"/>
2147- </object>
2148- </child>
2149- <child>
2150- <object class="GtkAction" id="save_as_item">
2151- <property name="stock_id">gtk-save-as</property>
2152- <property name="name">save_as_item</property>
2153- <signal handler="on_save_as_activated" name="activate"/>
2154- </object>
2155- </child>
2156- <child>
2157- <object class="GtkAction" id="close_item">
2158- <property name="stock_id">gtk-close</property>
2159- <property name="name">close_item</property>
2160- <signal handler="on_close_activated" name="activate"/>
2161- </object>
2162- </child>
2163- </object>
2164- </child>
2165- <ui>
2166- <popup name="history_menu">
2167- <menu action="history_container"/>
2168- <menu action="size_container">
2169- <menuitem action="zoom_normal_item"/>
2170- <menuitem action="zoom_in_item"/>
2171- <menuitem action="zoom_out_item"/>
2172- </menu>
2173- <menuitem action="show_link_item"/>
2174- <menuitem action="save_as_item"/>
2175- <menuitem action="close_item"/>
2176- </popup>
2177- </ui>
2178- </object>
2179- <object class="GtkMenu" constructor="uimanager1" id="history_menu">
2180- <property name="visible">True</property>
2181- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2182- <signal handler="on_widget_show" name="show"/>
2183- </object>
2184- <object class="GtkFileChooserDialog" id="save_as_dialog">
2185- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2186- <property name="border_width">5</property>
2187- <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
2188- <property name="icon">comics.svg</property>
2189- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
2190- <property name="has_separator">False</property>
2191- <property name="use_preview_label">False</property>
2192- <property name="action">GTK_FILE_CHOOSER_ACTION_SAVE</property>
2193- <property name="do_overwrite_confirmation">True</property>
2194- <property name="preview_widget_active">False</property>
2195- <child internal-child="vbox">
2196- <object class="GtkVBox" id="save_as_dialog_vbox">
2197- <property name="visible">True</property>
2198- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2199- <property name="orientation">vertical</property>
2200- <property name="spacing">2</property>
2201- <child>
2202- <object class="GtkComboBox" id="file_format_combo">
2203- <property name="visible">True</property>
2204- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2205- <signal handler="on_file_format_combo_changed" name="changed"/>
2206- </object>
2207- <packing>
2208- <property name="expand">False</property>
2209- <property name="fill">False</property>
2210- <property name="position">2</property>
2211- </packing>
2212- </child>
2213- <child internal-child="action_area">
2214- <object class="GtkHButtonBox" id="action_area_hbuttonbox">
2215- <property name="visible">True</property>
2216- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2217- <property name="layout_style">end</property>
2218- <child>
2219- <object class="GtkButton" id="action_area_cancel">
2220- <property name="visible">True</property>
2221- <property name="can_focus">True</property>
2222- <property name="receives_default">True</property>
2223- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2224- <property name="label">gtk-cancel</property>
2225- <property name="use_stock">True</property>
2226- </object>
2227- </child>
2228- <child>
2229- <object class="GtkButton" id="action_area_save">
2230- <property name="visible">True</property>
2231- <property name="can_focus">True</property>
2232- <property name="receives_default">True</property>
2233- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
2234- <property name="label">gtk-save</property>
2235- <property name="use_stock">True</property>
2236- </object>
2237- <packing>
2238- <property name="position">1</property>
2239- </packing>
2240- </child>
2241- </object>
2242- <packing>
2243- <property name="expand">False</property>
2244- <property name="pack_type">end</property>
2245- <property name="position">0</property>
2246- </packing>
2247- </child>
2248- </object>
2249- </child>
2250- <action-widgets>
2251- <action-widget response="0">action_area_cancel</action-widget>
2252- <action-widget response="1">action_area_save</action-widget>
2253- </action-widgets>
2254- </object>
2255-</interface>
2256
2257=== removed file 'applets/unmaintained/comic/Makefile.am'
2258--- applets/unmaintained/comic/Makefile.am 2009-02-01 00:13:07 +0000
2259+++ applets/unmaintained/comic/Makefile.am 1970-01-01 00:00:00 +0000
2260@@ -1,24 +0,0 @@
2261-APPLET_NAME = comic
2262-APPLET_MAIN_FILE = comic.py
2263-include $(top_srcdir)/Makefile.python-applet
2264-
2265-dist_applet_DATA = \
2266- comicdialog.py \
2267- getben.py \
2268- getborn.py \
2269- getdilbert.py \
2270- getferdnand.py \
2271- getgarfield.py \
2272- getnancy.py \
2273- getpcnp.py \
2274- getpeanuts.py \
2275- getpickles.py \
2276- getuf.py \
2277- getxkcd.py \
2278- getwiz.py \
2279- $(NULL)
2280-
2281-comic_iconsdir = $(applet_datadir)/icons
2282-dist_comic_icons_DATA = \
2283- icons/comic-applet.png \
2284- $(NULL)
2285
2286=== removed file 'applets/unmaintained/comic/comic.desktop.in'
2287--- applets/unmaintained/comic/comic.desktop.in 2009-10-06 19:42:48 +0000
2288+++ applets/unmaintained/comic/comic.desktop.in 1970-01-01 00:00:00 +0000
2289@@ -1,11 +0,0 @@
2290-[Desktop Entry]
2291-Version=1.0
2292-_Name=Dilbert Applet
2293-Type=Application
2294-X-AWN-Type=Applet
2295-X-AWN-AppletType=Python
2296-_Comment=Read Dilbert and other comics
2297-Exec=awn-applet -p %k
2298-X-AWN-AppletExec=comic/comic.py
2299-Icon=comic/icons/comic-applet.png
2300-X-AWN-AppletCategory=Network,News,Amusement
2301
2302=== removed file 'applets/unmaintained/comic/comic.py'
2303--- applets/unmaintained/comic/comic.py 2009-08-14 13:00:22 +0000
2304+++ applets/unmaintained/comic/comic.py 1970-01-01 00:00:00 +0000
2305@@ -1,226 +0,0 @@
2306-#!/usr/bin/python
2307-# -*- coding: iso-8859-15 -*-
2308-#
2309-# This program is free software; you can redistribute it and/or modify
2310-# it under the terms of the GNU General Public License version 2 as
2311-# published by the Free Software Foundation
2312-#
2313-# This program is distributed in the hope that it will be useful,
2314-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2315-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2316-# GNU General Public License for more details.
2317-#
2318-# You should have received a copy of the GNU General Public License
2319-# along with this program; if not, write to the Free Software
2320-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2321-#
2322-# Name: comic.py
2323-# Version: .5.
2324-# Date: 10-15-07
2325-# Description: A python Applet for the avant-windows-navigator to display comic strips.
2326-#
2327-# Authors: cj13
2328-# pavpanchekha
2329-
2330-import sys, os
2331-import gobject
2332-import gtk
2333-import awn
2334-import comicdialog
2335-#default comic
2336-GETWHAT = 'getdilbert.py'
2337-showhover = False
2338-
2339-class App (awn.AppletSimple):
2340- titleText = "Daily Comic"
2341- visible = False
2342-
2343- def __init__ (self, uid, orient, height):
2344- awn.AppletSimple.__init__ (self, uid, orient, height)
2345- self.set_awn_icon('comic', 'comic-applet')
2346-
2347- self.title = awn.awn_title_get_default ()
2348- self.dialog = awn.AppletDialog (self)
2349- self.connect ("button-press-event", self.button_press)
2350- self.connect ("enter-notify-event", self.enter_notify)
2351- self.connect ("leave-notify-event", self.leave_notify)
2352- self.dialog.connect ("focus-out-event", self.dialog_focus_out)
2353-
2354- # Setup popup menu
2355- self.popup_menu = self.create_default_menu()
2356- dil_item = gtk.MenuItem("Dilbert")
2357- pnut_item = gtk.MenuItem("Peanuts")
2358- born_item = gtk.MenuItem("The Born Loser")
2359- ben_item = gtk.MenuItem("Ben")
2360- ferdnand_item = gtk.MenuItem("Ferdnand")
2361- nancy_item = gtk.MenuItem("Nancy")
2362- pickles_item = gtk.MenuItem("Pickles")
2363- garfield_item = gtk.MenuItem("Garfield")
2364- uf_item = gtk.MenuItem("User Friendly")
2365- wiz_item = gtk.MenuItem("Wizard of ID")
2366- xkcd_item = gtk.MenuItem("xkcd")
2367- showho_item = gtk.CheckMenuItem("Hide Strip on Hover")
2368- self.popup_menu.append(dil_item)
2369- self.popup_menu.append(pnut_item)
2370- self.popup_menu.append(born_item)
2371- self.popup_menu.append(ben_item)
2372- self.popup_menu.append(ferdnand_item)
2373- self.popup_menu.append(nancy_item)
2374- self.popup_menu.append(pickles_item)
2375- self.popup_menu.append(garfield_item)
2376- self.popup_menu.append(uf_item)
2377- self.popup_menu.append(wiz_item)
2378- self.popup_menu.append(xkcd_item)
2379- self.popup_menu.append(showho_item)
2380- dil_item.connect_object("activate",self.dil_callback,self)
2381- pnut_item.connect_object("activate",self.pnut_callback,self)
2382- born_item.connect_object("activate",self.born_callback,self)
2383- ben_item.connect_object("activate",self.ben_callback,self)
2384- ferdnand_item.connect_object("activate",self.ferdnand_callback,self)
2385- nancy_item.connect_object("activate",self.nancy_callback,self)
2386- pickles_item.connect_object("activate",self.pickles_callback,self)
2387- garfield_item.connect_object("activate",self.garfield_callback,self)
2388- uf_item.connect_object("activate",self.uf_callback,self)
2389- wiz_item.connect_object("activate",self.wiz_callback,self)
2390- xkcd_item.connect_object("activate",self.xkcd_callback,self)
2391- showho_item.connect_object("activate",self.showho_callback,self)
2392- dil_item.show()
2393- pnut_item.show()
2394- born_item.show()
2395- ben_item.show()
2396- ferdnand_item.show()
2397- nancy_item.show()
2398- pickles_item.show()
2399- garfield_item.show()
2400- uf_item.show()
2401- wiz_item.show()
2402- xkcd_item.show()
2403- showho_item.show()
2404-
2405- self.build_dialog()
2406-
2407-
2408- def build_dialog(self):
2409- #print "Getting Comic"
2410-
2411- getit = 'python ' + os.path.dirname (__file__) + '/' + GETWHAT
2412- os.system(getit)
2413-
2414- self.dialog = awn.AppletDialog (self)
2415- self.dialog.set_title("Comic")
2416-
2417- box = gtk.VBox()
2418- comic = comicdialog.ComicDialog()
2419- box.pack_start(comic,False,False,0)
2420- box.show_all()
2421- self.dialog.add(box)
2422-
2423- self.timer = gobject.timeout_add (3600000, self.build_dialog)
2424-
2425-
2426- def button_press (self, widget, event):
2427- if event.button == 3:
2428- # right click
2429- self.title.hide(self)
2430- self.visible = False
2431- self.dialog.hide()
2432- self.popup_menu.popup(None, None, None, event.button, event.time)
2433- elif event.button == 1:
2434- if self.visible:
2435- self.dialog.hide()
2436- self.title.hide(self)
2437- else:
2438- self.title.hide(self)
2439- self.dialog.show_all()
2440- self.visible = not self.visible
2441-
2442-
2443- def dil_callback(self, widget):
2444- global GETWHAT
2445- GETWHAT = 'getdilbert.py'
2446- self.build_dialog()
2447-
2448-
2449- def pnut_callback(self, widget):
2450- global GETWHAT
2451- GETWHAT = 'getpeanuts.py'
2452- self.build_dialog()
2453-
2454- def born_callback(self, widget):
2455- global GETWHAT
2456- GETWHAT = 'getborn.py'
2457- self.build_dialog()
2458-
2459- def ben_callback(self, widget):
2460- global GETWHAT
2461- GETWHAT = 'getben.py'
2462- self.build_dialog()
2463-
2464- def ferdnand_callback(self, widget):
2465- global GETWHAT
2466- GETWHAT = 'getferdnand.py'
2467- self.build_dialog()
2468-
2469- def nancy_callback(self, widget):
2470- global GETWHAT
2471- GETWHAT = 'getnancy.py'
2472- self.build_dialog()
2473-
2474- def pickles_callback(self, widget):
2475- global GETWHAT
2476- GETWHAT = 'getpickles.py'
2477- self.build_dialog()
2478-
2479- def garfield_callback(self, widget):
2480- global GETWHAT
2481- GETWHAT = 'getgarfield.py'
2482- self.build_dialog()
2483-
2484- def uf_callback(self, widget):
2485- global GETWHAT
2486- GETWHAT = 'getuf.py'
2487- self.build_dialog()
2488-
2489- def wiz_callback(self, widget):
2490- global GETWHAT
2491- GETWHAT = 'getwiz.py'
2492- self.build_dialog()
2493-
2494- def xkcd_callback(self, widget):
2495- global GETWHAT
2496- GETWHAT = 'getxkcd.py'
2497- self.build_dialog()
2498-
2499- def showho_callback(self, widget):
2500- global showhover
2501- showhover = not showhover
2502-
2503-
2504- def dialog_focus_out (self, widget, event):
2505- self.visible = False
2506- self.dialog.hide()
2507-
2508-
2509- def enter_notify (self, widget, event):
2510- global showhover
2511- self.title.show (self, self.titleText)
2512- if showhover:
2513- self.title.hide(self)
2514- self.dialog.show_all()
2515- self.visible = False
2516-
2517- def leave_notify (self, widget, event):
2518- global showhover
2519- self.title.hide(self)
2520- if showhover:
2521- self.dialog.hide()
2522- self.visible = False
2523-
2524-
2525-if __name__ == "__main__":
2526- awn.init (sys.argv[1:])
2527- #print "main %s %d %d" % (awn.uid, awn.orient, awn.height)
2528- applet = App(awn.uid, awn.orient, awn.height)
2529- awn.embed_applet(applet)
2530- applet.show_all()
2531- gtk.main()
2532
2533=== removed file 'applets/unmaintained/comic/comicdialog.py'
2534--- applets/unmaintained/comic/comicdialog.py 2008-08-23 00:52:27 +0000
2535+++ applets/unmaintained/comic/comicdialog.py 1970-01-01 00:00:00 +0000
2536@@ -1,46 +0,0 @@
2537-#!/usr/bin/python
2538-# -*- coding: iso-8859-15 -*-
2539-#
2540-# This program is free software; you can redistribute it and/or modify
2541-# it under the terms of the GNU General Public License version 2 as
2542-# published by the Free Software Foundation
2543-#
2544-# This program is distributed in the hope that it will be useful,
2545-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2546-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2547-# GNU General Public License for more details.
2548-#
2549-# You should have received a copy of the GNU General Public License
2550-# along with this program; if not, write to the Free Software
2551-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2552-#
2553-# Name: comic.py
2554-# Version: .5.
2555-# Date: 10-15-07
2556-# Description: A python Applet for the avant-windows-navigator to display comic strips.
2557-#
2558-# Authors: cj13
2559-#
2560-import gtk
2561-from gtk import gdk
2562-import cairo
2563-
2564-class ComicDialog(gtk.DrawingArea):
2565- def __init__(self):
2566- gtk.DrawingArea.__init__(self)
2567- self.connect("expose_event", self.expose)
2568-
2569- def expose(self,widget,event):
2570- icon_name = '/tmp/dilbert.gif'
2571- icon = gdk.pixbuf_new_from_file(icon_name)
2572- dim = [icon.get_width(),icon.get_height()]
2573- self.set_size_request(dim[0], dim[1])
2574-
2575- context = widget.window.cairo_create()
2576- context.set_source_rgb(0,0,0)
2577-
2578- context.set_source_pixbuf(icon,1,1)
2579- context.fill()
2580- context.paint()
2581- return False
2582-
2583
2584=== removed file 'applets/unmaintained/comic/getben.py'
2585--- applets/unmaintained/comic/getben.py 2008-11-21 20:19:36 +0000
2586+++ applets/unmaintained/comic/getben.py 1970-01-01 00:00:00 +0000
2587@@ -1,75 +0,0 @@
2588-#!/usr/bin/python
2589-
2590-# This program is free software; you can redistribute it and/or modify
2591-# it under the terms of the GNU General Public License version 2 as
2592-# published by the Free Software Foundation
2593-#
2594-# This program is distributed in the hope that it will be useful,
2595-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2596-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2597-# GNU General Public License for more details.
2598-#
2599-# You should have received a copy of the GNU General Public License
2600-# along with this program; if not, write to the Free Software
2601-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2602-
2603-################################################################
2604-# get_bornloser_strips.py -- fetch strips of last N days
2605-
2606-################################################################
2607-# BEGIN configuration
2608-
2609-number_of_days = 1
2610-
2611-path_prefix = '/tmp/' # where do you want to save the files?
2612-
2613-# --END configuration
2614-################################################################
2615-
2616-import sys
2617-import urllib
2618-import re
2619-
2620-from string import join
2621-from datetime import datetime, timedelta
2622-
2623-if len(sys.argv) > 1:
2624- number_of_days = int(sys.argv[1])
2625-
2626-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
2627-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
2628-temp1 = 'http://www.comics.com/ben/%s/'
2629-temp2 = 'http://assets.comics.com/dyn/%s'
2630-
2631-date = datetime.today()
2632-one_day = timedelta(1)
2633-
2634-filename = None
2635-
2636-for i in range(number_of_days):
2637- url = temp1 % (date.strftime('%Y-%m-%d'))
2638- #print '? %s' % (url)
2639- fil = urllib.urlopen(url)
2640- for line in fil:
2641- match = pattern.search(line)
2642- if match != None:
2643- filename = match.group()
2644- break
2645- else:
2646- match2 = pattern2.search(line)
2647- if match2 != None:
2648- filename = match2.group()
2649- break
2650- fil.close()
2651-
2652- if filename != None:
2653- url = temp2 % (filename)
2654- #print '+ %s' % (url)
2655- fil = urllib.urlopen(url)
2656- diskfile = file(path_prefix + 'dilbert.gif', 'w')
2657- diskfile.write(fil.read())
2658- fil.close()
2659- diskfile.close()
2660-
2661- date = date - one_day
2662- filename = None
2663
2664=== removed file 'applets/unmaintained/comic/getborn.py'
2665--- applets/unmaintained/comic/getborn.py 2008-11-21 20:19:36 +0000
2666+++ applets/unmaintained/comic/getborn.py 1970-01-01 00:00:00 +0000
2667@@ -1,75 +0,0 @@
2668-#!/usr/bin/python
2669-
2670-# This program is free software; you can redistribute it and/or modify
2671-# it under the terms of the GNU General Public License version 2 as
2672-# published by the Free Software Foundation
2673-#
2674-# This program is distributed in the hope that it will be useful,
2675-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2676-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2677-# GNU General Public License for more details.
2678-#
2679-# You should have received a copy of the GNU General Public License
2680-# along with this program; if not, write to the Free Software
2681-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2682-
2683-################################################################
2684-# get_bornloser_strips.py -- fetch strips of last N days
2685-
2686-################################################################
2687-# BEGIN configuration
2688-
2689-number_of_days = 1
2690-
2691-path_prefix = '/tmp/' # where do you want to save the files?
2692-
2693-# --END configuration
2694-################################################################
2695-
2696-import sys
2697-import urllib
2698-import re
2699-
2700-from string import join
2701-from datetime import datetime, timedelta
2702-
2703-if len(sys.argv) > 1:
2704- number_of_days = int(sys.argv[1])
2705-
2706-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
2707-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
2708-temp1 = 'http://comics.com/the_born_loser/%s/'
2709-temp2 = 'http://assets.comics.com/dyn/%s'
2710-
2711-date = datetime.today()
2712-one_day = timedelta(1)
2713-
2714-filename = None
2715-
2716-for i in range(number_of_days):
2717- url = temp1 % (date.strftime('%Y%m%d'))
2718- #print '? %s' % (url)
2719- fil = urllib.urlopen(url)
2720- for line in fil:
2721- match = pattern.search(line)
2722- if match != None:
2723- filename = match.group()
2724- break
2725- else:
2726- match2 = pattern2.search(line)
2727- if match2 != None:
2728- filename = match2.group()
2729- break
2730- fil.close()
2731-
2732- if filename != None:
2733- url = temp2 % (filename)
2734- #print '+ %s' % (url)
2735- fil = urllib.urlopen(url)
2736- diskfile = file(path_prefix + 'dilbert.gif', 'w')
2737- diskfile.write(fil.read())
2738- fil.close()
2739- diskfile.close()
2740-
2741- date = date - one_day
2742- filename = None
2743
2744=== removed file 'applets/unmaintained/comic/getdilbert.py'
2745--- applets/unmaintained/comic/getdilbert.py 2008-11-21 20:19:36 +0000
2746+++ applets/unmaintained/comic/getdilbert.py 1970-01-01 00:00:00 +0000
2747@@ -1,75 +0,0 @@
2748-#!/usr/bin/python
2749-
2750-# This program is free software; you can redistribute it and/or modify
2751-# it under the terms of the GNU General Public License version 2 as
2752-# published by the Free Software Foundation
2753-#
2754-# This program is distributed in the hope that it will be useful,
2755-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2756-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2757-# GNU General Public License for more details.
2758-#
2759-# You should have received a copy of the GNU General Public License
2760-# along with this program; if not, write to the Free Software
2761-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2762-
2763-################################################################
2764-# get_dilbert_strips.py -- fetch dilbert strips of last N days
2765-
2766-################################################################
2767-# BEGIN configuration
2768-
2769-number_of_days = 1
2770-
2771-path_prefix = '/tmp/' # where do you want to save the files?
2772-
2773-# --END configuration
2774-################################################################
2775-
2776-import sys
2777-import urllib
2778-import re
2779-
2780-from string import join
2781-from datetime import datetime, timedelta
2782-
2783-if len(sys.argv) > 1:
2784- number_of_days = int(sys.argv[1])
2785-
2786-pattern = re.compile('str_strip[0-9/]+\\.strip\\.gif')
2787-pattern2 = re.compile('str_strip[0-9/]+\\.strip\\.sunday\\.gif')
2788-temp1 = 'http://dilbert.com/%s/'
2789-temp2 = 'http://dilbert.com/dyn/%s'
2790-
2791-date = datetime.today()
2792-one_day = timedelta(1)
2793-
2794-filename = None
2795-
2796-for i in range(number_of_days):
2797- url = temp1 % (date.strftime('%Y-%m-%d'))
2798- #print '? %s' % (url)
2799- fil = urllib.urlopen(url)
2800- for line in fil:
2801- match = pattern.search(line)
2802- if match != None:
2803- filename = match.group()
2804- break
2805- else:
2806- match2 = pattern2.search(line)
2807- if match2 != None:
2808- filename = match2.group()
2809- break
2810- fil.close()
2811-
2812- if filename != None:
2813- url = temp2 % (filename)
2814- #print '+ %s' % (url)
2815- fil = urllib.urlopen(url)
2816- diskfile = file(path_prefix + 'dilbert.gif', 'w')
2817- diskfile.write(fil.read())
2818- fil.close()
2819- diskfile.close()
2820-
2821- date = date - one_day
2822- filename = None
2823
2824=== removed file 'applets/unmaintained/comic/getferdnand.py'
2825--- applets/unmaintained/comic/getferdnand.py 2008-11-21 20:19:36 +0000
2826+++ applets/unmaintained/comic/getferdnand.py 1970-01-01 00:00:00 +0000
2827@@ -1,75 +0,0 @@
2828-#!/usr/bin/python
2829-
2830-# This program is free software; you can redistribute it and/or modify
2831-# it under the terms of the GNU General Public License version 2 as
2832-# published by the Free Software Foundation
2833-#
2834-# This program is distributed in the hope that it will be useful,
2835-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2836-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2837-# GNU General Public License for more details.
2838-#
2839-# You should have received a copy of the GNU General Public License
2840-# along with this program; if not, write to the Free Software
2841-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2842-
2843-################################################################
2844-# get_bornloser_strips.py -- fetch strips of last N days
2845-
2846-################################################################
2847-# BEGIN configuration
2848-
2849-number_of_days = 1
2850-
2851-path_prefix = '/tmp/' # where do you want to save the files?
2852-
2853-# --END configuration
2854-################################################################
2855-
2856-import sys
2857-import urllib
2858-import re
2859-
2860-from string import join
2861-from datetime import datetime, timedelta
2862-
2863-if len(sys.argv) > 1:
2864- number_of_days = int(sys.argv[1])
2865-
2866-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
2867-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
2868-temp1 = 'http://comics.com/ferdnand/%s/'
2869-temp2 = 'http://assets.comics.com/dyn/%s'
2870-
2871-date = datetime.today()
2872-one_day = timedelta(1)
2873-
2874-filename = None
2875-
2876-for i in range(number_of_days):
2877- url = temp1 % (date.strftime('%Y%m%d'))
2878- #print '? %s' % (url)
2879- fil = urllib.urlopen(url)
2880- for line in fil:
2881- match = pattern.search(line)
2882- if match != None:
2883- filename = match.group()
2884- break
2885- else:
2886- match2 = pattern2.search(line)
2887- if match2 != None:
2888- filename = match2.group()
2889- break
2890- fil.close()
2891-
2892- if filename != None:
2893- url = temp2 % (filename)
2894- #print '+ %s' % (url)
2895- fil = urllib.urlopen(url)
2896- diskfile = file(path_prefix + 'dilbert.gif', 'w')
2897- diskfile.write(fil.read())
2898- fil.close()
2899- diskfile.close()
2900-
2901- date = date - one_day
2902- filename = None
2903
2904=== removed file 'applets/unmaintained/comic/getgarfield.py'
2905--- applets/unmaintained/comic/getgarfield.py 2009-01-16 17:07:28 +0000
2906+++ applets/unmaintained/comic/getgarfield.py 1970-01-01 00:00:00 +0000
2907@@ -1,56 +0,0 @@
2908-#!/usr/bin/python
2909-
2910-# This program is free software; you can redistribute it and/or modify
2911-# it under the terms of the GNU General Public License version 2 as
2912-# published by the Free Software Foundation
2913-#
2914-# This program is distributed in the hope that it will be useful,
2915-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2916-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2917-# GNU General Public License for more details.
2918-#
2919-# You should have received a copy of the GNU General Public License
2920-# along with this program; if not, write to the Free Software
2921-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2922-
2923-################################################################
2924-# getgarfield.py -- fetch strips of last N days
2925-
2926-################################################################
2927-# BEGIN configuration
2928-
2929-number_of_days = 1
2930-
2931-path_prefix = '/tmp/' # where do you want to save the files?
2932-
2933-# --END configuration
2934-################################################################
2935-
2936-import sys
2937-import urllib
2938-import re
2939-
2940-from string import join
2941-from datetime import datetime, timedelta
2942-
2943-if len(sys.argv) > 1:
2944- number_of_days = int(sys.argv[1])
2945-
2946-temp = 'http://picayune.uclick.com/comics/ga/%s/ga%s.%s'
2947-
2948-date = datetime.today()
2949-one_day = timedelta(1)
2950-
2951-for i in range(number_of_days):
2952-
2953- giforjpg = 'gif'
2954-
2955- url = temp % (date.strftime('%Y'),date.strftime('%y%m%d'),giforjpg)
2956- print '+ %s' % (url)
2957- fil = urllib.urlopen(url)
2958- diskfile = file(path_prefix + 'dilbert.gif', 'w')
2959- diskfile.write(fil.read())
2960- fil.close()
2961- diskfile.close()
2962-
2963- date = date - one_day
2964
2965=== removed file 'applets/unmaintained/comic/getnancy.py'
2966--- applets/unmaintained/comic/getnancy.py 2008-11-21 20:19:36 +0000
2967+++ applets/unmaintained/comic/getnancy.py 1970-01-01 00:00:00 +0000
2968@@ -1,75 +0,0 @@
2969-#!/usr/bin/python
2970-
2971-# This program is free software; you can redistribute it and/or modify
2972-# it under the terms of the GNU General Public License version 2 as
2973-# published by the Free Software Foundation
2974-#
2975-# This program is distributed in the hope that it will be useful,
2976-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2977-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2978-# GNU General Public License for more details.
2979-#
2980-# You should have received a copy of the GNU General Public License
2981-# along with this program; if not, write to the Free Software
2982-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2983-
2984-################################################################
2985-# get_bornloser_strips.py -- fetch strips of last N days
2986-
2987-################################################################
2988-# BEGIN configuration
2989-
2990-number_of_days = 1
2991-
2992-path_prefix = '/tmp/' # where do you want to save the files?
2993-
2994-# --END configuration
2995-################################################################
2996-
2997-import sys
2998-import urllib
2999-import re
3000-
3001-from string import join
3002-from datetime import datetime, timedelta
3003-
3004-if len(sys.argv) > 1:
3005- number_of_days = int(sys.argv[1])
3006-
3007-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
3008-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
3009-temp1 = 'http://www.comics.com/nancy/%s/'
3010-temp2 = 'http://assets.comics.com/dyn/%s'
3011-
3012-date = datetime.today()
3013-one_day = timedelta(1)
3014-
3015-filename = None
3016-
3017-for i in range(number_of_days):
3018- url = temp1 % (date.strftime('%Y%m%d'))
3019- #print '? %s' % (url)
3020- fil = urllib.urlopen(url)
3021- for line in fil:
3022- match = pattern.search(line)
3023- if match != None:
3024- filename = match.group()
3025- break
3026- else:
3027- match2 = pattern2.search(line)
3028- if match2 != None:
3029- filename = match2.group()
3030- break
3031- fil.close()
3032-
3033- if filename != None:
3034- url = temp2 % (filename)
3035- #print '+ %s' % (url)
3036- fil = urllib.urlopen(url)
3037- diskfile = file(path_prefix + 'dilbert.gif', 'w')
3038- diskfile.write(fil.read())
3039- fil.close()
3040- diskfile.close()
3041-
3042- date = date - one_day
3043- filename = None
3044
3045=== removed file 'applets/unmaintained/comic/getpcnp.py'
3046--- applets/unmaintained/comic/getpcnp.py 2008-08-23 00:52:27 +0000
3047+++ applets/unmaintained/comic/getpcnp.py 1970-01-01 00:00:00 +0000
3048@@ -1,75 +0,0 @@
3049-#!/usr/bin/python
3050-
3051-# This program is free software; you can redistribute it and/or modify
3052-# it under the terms of the GNU General Public License version 2 as
3053-# published by the Free Software Foundation
3054-#
3055-# This program is distributed in the hope that it will be useful,
3056-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3057-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3058-# GNU General Public License for more details.
3059-#
3060-# You should have received a copy of the GNU General Public License
3061-# along with this program; if not, write to the Free Software
3062-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3063-
3064-################################################################
3065-# get_pcnpixel_strips.py -- fetch strips of last N days
3066-
3067-################################################################
3068-# BEGIN configuration
3069-
3070-number_of_days = 1
3071-
3072-path_prefix = '/tmp/' # where do you want to save the files?
3073-
3074-# --END configuration
3075-################################################################
3076-
3077-import sys
3078-import urllib
3079-import re
3080-
3081-from string import join
3082-from datetime import datetime, timedelta
3083-
3084-if len(sys.argv) > 1:
3085- number_of_days = int(sys.argv[1])
3086-
3087-pattern = re.compile('pcnpixel\\d+\\.gif')
3088-pattern2 = re.compile('pcnpixel\\d+\\.jpg')
3089-temp1 = 'http://www.snoopy.com/wash/pcnpixel%s.html'
3090-temp2 = 'http://www.snoopy.com/wash/pcnpixel/archive/images/%s'
3091-
3092-date = datetime.today()
3093-one_day = timedelta(1)
3094-
3095-filename = None
3096-
3097-for i in range(number_of_days):
3098- url = temp1 % (date.strftime('%Y%m%d'))
3099- #print '? %s' % (url)
3100- fil = urllib.urlopen(url)
3101- for line in fil:
3102- match = pattern.search(line)
3103- if match != None:
3104- filename = match.group()
3105- break
3106- else:
3107- match2 = pattern2.search(line)
3108- if match2 != None:
3109- filename = match2.group()
3110- break
3111- fil.close()
3112-
3113- if filename != None:
3114- url = temp2 % (filename)
3115- #print '+ %s' % (url)
3116- fil = urllib.urlopen(url)
3117- diskfile = file(path_prefix + 'dilbert.gif', 'w')
3118- diskfile.write(fil.read())
3119- fil.close()
3120- diskfile.close()
3121-
3122- date = date - one_day
3123- filename = None
3124
3125=== removed file 'applets/unmaintained/comic/getpeanuts.py'
3126--- applets/unmaintained/comic/getpeanuts.py 2008-11-21 20:19:36 +0000
3127+++ applets/unmaintained/comic/getpeanuts.py 1970-01-01 00:00:00 +0000
3128@@ -1,75 +0,0 @@
3129-#!/usr/bin/python
3130-
3131-# This program is free software; you can redistribute it and/or modify
3132-# it under the terms of the GNU General Public License version 2 as
3133-# published by the Free Software Foundation
3134-#
3135-# This program is distributed in the hope that it will be useful,
3136-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3137-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3138-# GNU General Public License for more details.
3139-#
3140-# You should have received a copy of the GNU General Public License
3141-# along with this program; if not, write to the Free Software
3142-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3143-
3144-################################################################
3145-# get_peanuts_strips.py -- fetch peanuts strips of last N days
3146-
3147-################################################################
3148-# BEGIN configuration
3149-
3150-number_of_days = 1
3151-
3152-path_prefix = '/tmp/' # where do you want to save the files?
3153-
3154-# --END configuration
3155-################################################################
3156-
3157-import sys
3158-import urllib
3159-import re
3160-
3161-from string import join
3162-from datetime import datetime, timedelta
3163-
3164-if len(sys.argv) > 1:
3165- number_of_days = int(sys.argv[1])
3166-
3167-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
3168-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
3169-temp1 = 'http://comics.com/peanuts/%s/'
3170-temp2 = 'http://assets.comics.com/dyn/%s'
3171-
3172-date = datetime.today()
3173-one_day = timedelta(1)
3174-
3175-filename = None
3176-
3177-for i in range(number_of_days):
3178- url = temp1 % (date.strftime('%Y%m%d'))
3179- #print '? %s' % (url)
3180- fil = urllib.urlopen(url)
3181- for line in fil:
3182- match = pattern.search(line)
3183- if match != None:
3184- filename = match.group()
3185- break
3186- else:
3187- match2 = pattern2.search(line)
3188- if match2 != None:
3189- filename = match2.group()
3190- break
3191- fil.close()
3192-
3193- if filename != None:
3194- url = temp2 % (filename)
3195- #print '+ %s' % (url)
3196- fil = urllib.urlopen(url)
3197- diskfile = file(path_prefix + 'dilbert.gif', 'w')
3198- diskfile.write(fil.read())
3199- fil.close()
3200- diskfile.close()
3201-
3202- date = date - one_day
3203- filename = None
3204
3205=== removed file 'applets/unmaintained/comic/getpickles.py'
3206--- applets/unmaintained/comic/getpickles.py 2008-11-21 20:19:36 +0000
3207+++ applets/unmaintained/comic/getpickles.py 1970-01-01 00:00:00 +0000
3208@@ -1,75 +0,0 @@
3209-#!/usr/bin/python
3210-
3211-# This program is free software; you can redistribute it and/or modify
3212-# it under the terms of the GNU General Public License version 2 as
3213-# published by the Free Software Foundation
3214-#
3215-# This program is distributed in the hope that it will be useful,
3216-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3217-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3218-# GNU General Public License for more details.
3219-#
3220-# You should have received a copy of the GNU General Public License
3221-# along with this program; if not, write to the Free Software
3222-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3223-
3224-################################################################
3225-# get_bornloser_strips.py -- fetch strips of last N days
3226-
3227-################################################################
3228-# BEGIN configuration
3229-
3230-number_of_days = 1
3231-
3232-path_prefix = '/tmp/' # where do you want to save the files?
3233-
3234-# --END configuration
3235-################################################################
3236-
3237-import sys
3238-import urllib
3239-import re
3240-
3241-from string import join
3242-from datetime import datetime, timedelta
3243-
3244-if len(sys.argv) > 1:
3245- number_of_days = int(sys.argv[1])
3246-
3247-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
3248-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
3249-temp1 = 'http://www.comics.com/pickles/%s/'
3250-temp2 = 'http://assets.comics.com/dyn/%s'
3251-
3252-date = datetime.today()
3253-one_day = timedelta(1)
3254-
3255-filename = None
3256-
3257-for i in range(number_of_days):
3258- url = temp1 % (date.strftime('%Y-%m-%d'))
3259- #print '? %s' % (url)
3260- fil = urllib.urlopen(url)
3261- for line in fil:
3262- match = pattern.search(line)
3263- if match != None:
3264- filename = match.group()
3265- break
3266- else:
3267- match2 = pattern2.search(line)
3268- if match2 != None:
3269- filename = match2.group()
3270- break
3271- fil.close()
3272-
3273- if filename != None:
3274- url = temp2 % (filename)
3275- #print '+ %s' % (url)
3276- fil = urllib.urlopen(url)
3277- diskfile = file(path_prefix + 'dilbert.gif', 'w')
3278- diskfile.write(fil.read())
3279- fil.close()
3280- diskfile.close()
3281-
3282- date = date - one_day
3283- filename = None
3284
3285=== renamed file 'applets/unmaintained/comic/getuf.py' => 'applets/unmaintained/comic/getuf.py.THIS'
3286=== removed file 'applets/unmaintained/comic/getwiz.py'
3287--- applets/unmaintained/comic/getwiz.py 2008-11-21 20:19:36 +0000
3288+++ applets/unmaintained/comic/getwiz.py 1970-01-01 00:00:00 +0000
3289@@ -1,75 +0,0 @@
3290-#!/usr/bin/python
3291-
3292-# This program is free software; you can redistribute it and/or modify
3293-# it under the terms of the GNU General Public License version 2 as
3294-# published by the Free Software Foundation
3295-#
3296-# This program is distributed in the hope that it will be useful,
3297-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3298-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3299-# GNU General Public License for more details.
3300-#
3301-# You should have received a copy of the GNU General Public License
3302-# along with this program; if not, write to the Free Software
3303-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3304-
3305-################################################################
3306-# get_wizofid_strips.py -- fetch wizofids strips of last N days
3307-
3308-################################################################
3309-# BEGIN configuration
3310-
3311-number_of_days = 1
3312-
3313-path_prefix = '/tmp/' # where do you want to save the files?
3314-
3315-# --END configuration
3316-################################################################
3317-
3318-import sys
3319-import urllib
3320-import re
3321-
3322-from string import join
3323-from datetime import datetime, timedelta
3324-
3325-if len(sys.argv) > 1:
3326- number_of_days = int(sys.argv[1])
3327-
3328-pattern = re.compile('str_strip[0-9/]+\\.full\\.gif')
3329-pattern2 = re.compile('str_strip[0-9/]+\\.full\\.jpg')
3330-temp1 = 'http://comics.com/wizard_of_id/%s/'
3331-temp2 = 'http://assets.comics.com/dyn/%s'
3332-
3333-date = datetime.today()
3334-one_day = timedelta(1)
3335-
3336-filename = None
3337-
3338-for i in range(number_of_days):
3339- url = temp1 % (date.strftime('%Y%m%d'))
3340- #print '? %s' % (url)
3341- fil = urllib.urlopen(url)
3342- for line in fil:
3343- match = pattern.search(line)
3344- if match != None:
3345- filename = match.group()
3346- break
3347- else:
3348- match2 = pattern2.search(line)
3349- if match2 != None:
3350- filename = match2.group()
3351- break
3352- fil.close()
3353-
3354- if filename != None:
3355- url = temp2 % (filename)
3356- #print '+ %s' % (url)
3357- fil = urllib.urlopen(url)
3358- diskfile = file(path_prefix + 'dilbert.gif', 'w')
3359- diskfile.write(fil.read())
3360- fil.close()
3361- diskfile.close()
3362-
3363- date = date - one_day
3364- filename = None
3365
3366=== removed file 'applets/unmaintained/comic/getxkcd.py'
3367--- applets/unmaintained/comic/getxkcd.py 2008-08-23 00:52:27 +0000
3368+++ applets/unmaintained/comic/getxkcd.py 1970-01-01 00:00:00 +0000
3369@@ -1,40 +0,0 @@
3370-#!/usr/bin/python
3371-
3372-# This program is free software; you can redistribute it and/or modify
3373-# it under the terms of the GNU General Public License version 2 as
3374-# published by the Free Software Foundation
3375-#
3376-# This program is distributed in the hope that it will be useful,
3377-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3378-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3379-# GNU General Public License for more details.
3380-#
3381-# You should have received a copy of the GNU General Public License
3382-# along with this program; if not, write to the Free Software
3383-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3384-
3385-################################################################
3386-# getxkcd.py -- fetch last (current) xkcd strip
3387-
3388-################################################################
3389-# BEGIN configuration
3390-
3391-
3392-path_prefix = '/tmp/' # where do you want to save the files?
3393-
3394-# --END configuration
3395-################################################################
3396-
3397-import urllib
3398-import re
3399-
3400-
3401-comic = urllib.urlopen("http://www.xkcd.com/")
3402-link = re.compile("http://imgs.xkcd.com/comics/.*png").search(comic.read(),1)
3403-fil = urllib.urlopen(link.group())
3404-
3405-diskfile = file(path_prefix + 'dilbert.gif', 'w')
3406-diskfile.write(fil.read())
3407-fil.close()
3408-diskfile.close()
3409-
3410
3411=== removed directory 'applets/unmaintained/comic/icons'
3412=== removed file 'applets/unmaintained/comic/icons/comic-applet.png'
3413Binary files applets/unmaintained/comic/icons/comic-applet.png 2008-07-18 02:16:24 +0000 and applets/unmaintained/comic/icons/comic-applet.png 1970-01-01 00:00:00 +0000 differ
3414=== modified file 'debian/awn-applets-python-extras-trunk.install'
3415--- debian/awn-applets-python-extras-trunk.install 2010-09-30 16:12:44 +0000
3416+++ debian/awn-applets-python-extras-trunk.install 2011-01-09 09:07:16 +0000
3417@@ -49,9 +49,6 @@
3418 # Disabled applets #
3419 ####################
3420 #
3421-#usr/share/avant-window-navigator/applets/comic/
3422-#usr/share/avant-window-navigator/applets/comic.desktop
3423-#
3424 # Rtm
3425 #
3426 #usr/share/avant-window-navigator/applets/rtm/
3427
3428=== modified file 'po/POTFILES.in'
3429--- po/POTFILES.in 2010-10-22 17:00:33 +0000
3430+++ po/POTFILES.in 2011-01-09 09:07:16 +0000
3431@@ -43,7 +43,6 @@
3432 applets/maintained/comics/feed/__init__.py
3433 [type: gettext/glade]applets/maintained/comics/ui/add.ui
3434 [type: gettext/glade]applets/maintained/comics/ui/manage.ui
3435-[type: gettext/glade]applets/maintained/comics/ui/view.ui
3436 applets/maintained/comics/main.py
3437 applets/maintained/common-folder/common-folder.desktop.in
3438 applets/maintained/common-folder/common-folder.py
3439
3440=== modified file 'po/POTFILES.skip'
3441--- po/POTFILES.skip 2010-10-15 18:18:48 +0000
3442+++ po/POTFILES.skip 2011-01-09 09:07:16 +0000
3443@@ -26,7 +26,6 @@
3444 # Disabled applets
3445 #
3446 applets/maintained/rtm/rtm.desktop.in
3447-applets/unmaintained/comic/comic.desktop.in
3448 applets/unmaintained/dropper/awn-applet-dropper.schema-ini.in
3449 applets/unmaintained/dropper/dropper.desktop.in
3450 applets/unmaintained/dropper/dropper-prefs.ui

Subscribers

People subscribed via source and target branches