1 new commit in readFeeds:
https://bitbucket.org/nvdaaddonteam/readfeeds/commits/7fd97679f551/
Changeset: 7fd97679f551
Branch: enhancedgui
User: norrumar
Date: 2016-12-05 11:28:07+00:00
Summary: Added dialogs to copy and restore feeds based on the portable
creater dialog of NVDA, and reviewed placeMarkers add-on. Used skipTranslation
to get translated messages of NVDA core, and restructured folders to avoid
issues with modules external to the plugin.
Affected #: 69 files
diff --git a/addon/globalPlugins/personalFeeds/Blog SpazioAusili.txt
b/addon/globalPlugins/personalFeeds/Blog SpazioAusili.txt
deleted file mode 100644
index 4e93538..0000000
--- a/addon/globalPlugins/personalFeeds/Blog SpazioAusili.txt
+++ /dev/null
@@ -1 +0,0 @@
-http://www.spazioausili.net/rss/blog
\ No newline at end of file
diff --git a/addon/globalPlugins/personalFeeds/Forum SpazioAusili.txt
b/addon/globalPlugins/personalFeeds/Forum SpazioAusili.txt
deleted file mode 100644
index 467e223..0000000
--- a/addon/globalPlugins/personalFeeds/Forum SpazioAusili.txt
+++ /dev/null
@@ -1 +0,0 @@
-http://www.spazioausili.net/rss/forum
\ No newline at end of file
diff --git a/addon/globalPlugins/personalFeeds/W3C-news.txt
b/addon/globalPlugins/personalFeeds/W3C-news.txt
deleted file mode 100644
index d6d78cd..0000000
--- a/addon/globalPlugins/personalFeeds/W3C-news.txt
+++ /dev/null
@@ -1 +0,0 @@
-http://www.w3.org/News/atom.xml
\ No newline at end of file
diff --git a/addon/globalPlugins/personalFeeds/addons NVDA-project IT RSS.txt
b/addon/globalPlugins/personalFeeds/addons NVDA-project IT RSS.txt
deleted file mode 100644
index ce662ed..0000000
--- a/addon/globalPlugins/personalFeeds/addons NVDA-project IT RSS.txt
+++ /dev/null
@@ -1 +0,0 @@
-http://addons.nvda-project.org/index.it.rss
\ No newline at end of file
diff --git a/addon/globalPlugins/personalFeeds/addressFile.txt
b/addon/globalPlugins/personalFeeds/addressFile.txt
deleted file mode 100644
index 467e223..0000000
--- a/addon/globalPlugins/personalFeeds/addressFile.txt
+++ /dev/null
@@ -1 +0,0 @@
-http://www.spazioausili.net/rss/forum
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds.py b/addon/globalPlugins/readFeeds.py
deleted file mode 100644
index 7746d5c..0000000
--- a/addon/globalPlugins/readFeeds.py
+++ /dev/null
@@ -1,413 +0,0 @@
-# -*- coding: UTF-8 -*-
-
-# Read feeds: A simple plugin for reading feeds with NVDA
-#Copyright (C) 2012-2016 Noelia Ruiz Martínez, Mesar Hameed
-# Released under GPL 2
-
-# Version: 6.0
-# Used globalVars to get config path, for better results with temporary
copies, as instantTranslate or SaveLog add-ons
-# Version: 5.0
-# Control instead of alt in gesture. Added installTask to update the add-on
-# Version: 4.2
-# Channel title and number of articles in News list dialog
-# Date: 23/06/2012
-
-import addonHandler
-import globalPluginHandler
-import os
-import sys
-import shutil
-import globalVars
-import config
-import urllib
-import scriptHandler
-import api
-import gui
-from gui import guiHelper
-import wx
-import ui
-from logHandler import log
-import re
-
-sys.path.append(os.path.dirname(__file__))
-from xml2.dom import minidom
-del sys.path[-1]
-
-addonHandler.initTranslation()
-
-### Constants
-
-ADDON_DIR = os.path.join(os.path.dirname(__file__), "..") # The root of the
addon folder
-ADDON_INSTANCE = addonHandler.Addon(ADDON_DIR)
-ADDON_SUMMARY = ADDON_INSTANCE.manifest['summary']
-FEEDS_PATH = os.path.join(ADDON_DIR, "globalPlugins", "personalFeeds")
-CONFIG_PATH = globalVars.appArgs.configPath
-# Translators: message presented when feeds cannot be reported.
-CAN_NOT_REPORT = _("Unable to refresh feed. Check your Internet conectivity or
that the specified feed address is correct.")
-
-### Configuration
-
-confspec = {
- "addressFile": "string(default="")",
-}
-config.conf.spec["readFeeds"] = confspec
-
-### Dialogs
-
-class FeedsDialog(wx.Dialog):
-
- _instance = None
- def __new__(cls, *args, **kwargs):
- # Make this a singleton.
- if FeedsDialog._instance is None:
- return super(FeedsDialog, cls).__new__(cls, *args,
**kwargs)
- return FeedsDialog._instance
-
- def __init__(self, parent):
- if FeedsDialog._instance is not None:
- return
- FeedsDialog._instance = self
- # Translators: The title of a dialog.
- super(FeedsDialog, self).__init__(parent, title=_("Feeds"))
-
- mainSizer = wx.BoxSizer(wx.VERTICAL)
- sHelper = guiHelper.BoxSizerHelper(self,orientation=wx.VERTICAL)
- feedsListGroupSizer = wx.StaticBoxSizer(wx.StaticBox(self),
wx.HORIZONTAL)
- feedsListGroupContents = wx.BoxSizer(wx.HORIZONTAL)
- changeFeedsSizer = wx.BoxSizer(wx.VERTICAL)
-
- # Translators: The label of an edit box to search feeds.
- searchTextLabel = _("&Text to search:")
- searchLabeledCtrl = gui.guiHelper.LabeledControlHelper(self,
searchTextLabel, wx.TextCtrl)
- self.searchTextEdit = searchLabeledCtrl.control
- self.searchTextEdit.Bind(wx.EVT_TEXT,
self.onSearchEditTextChange)
-
- self.choices = [os.path.splitext(filename)[0] for filename in
os.listdir(FEEDS_PATH)]
- self.feedsList = wx.ListBox(self,
- choices=self.choices)
- self.feedsList.Selection = 0
- self.feedsList.Bind(wx.EVT_LISTBOX, self.onFeedsListChoice)
- changeFeedsSizer.Add(self.feedsList, proportion=1.0)
-
changeFeedsSizer.AddSpacer(guiHelper.SPACE_BETWEEN_BUTTONS_VERTICAL)
-
- # Translators: The label of a button to open the list of
articles of a feed.
- self.articlesButton = wx.Button(self, label=_("List of
&articles..."))
- self.articlesButton.Bind(wx.EVT_BUTTON, self.onArticles)
- self.AffirmativeId = self.articlesButton.Id
- self.articlesButton.SetDefault()
- changeFeedsSizer.Add(self.articlesButton)
-
- feedsListGroupContents.Add(changeFeedsSizer, flag = wx.EXPAND)
-
feedsListGroupContents.AddSpacer(guiHelper.SPACE_BETWEEN_ASSOCIATED_CONTROL_HORIZONTAL)
-
- buttonHelper = guiHelper.ButtonHelper(wx.VERTICAL)
- # Translators: The label of a button to add a new feed.
- newButton = buttonHelper.addButton(self, label=_("&New..."))
- newButton.Bind(wx.EVT_BUTTON, self.onNew)
-
- # Translators: The label of a button to rename a feed.
- self.renameButton = buttonHelper.addButton(self,
label=_("&Rename..."))
- self.renameButton.Bind(wx.EVT_BUTTON, self.onRename)
-
- # Translators: The label of a button to delete a feed.
- self.deleteButton = buttonHelper.addButton(self,
label=_("&Delete..."))
- self.deleteButton.Bind(wx.EVT_BUTTON, self.onDelete)
-
-# Translators: The label of a button to set a feed as default.
- self.defaultButton = buttonHelper.addButton(self, label=_("S&et
default"))
- self.defaultButton.Bind(wx.EVT_BUTTON, self.onDefault)
-
- feedsListGroupContents.Add(buttonHelper.sizer)
- feedsListGroupSizer.Add(feedsListGroupContents,
border=guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
- sHelper.addItem(feedsListGroupSizer)
-
- # Translators: The label of a button to close a dialog.
- closeButton = wx.Button(self, wx.ID_CLOSE, label=_("&Close"))
- closeButton.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
- sHelper.addDialogDismissButtons(closeButton)
- self.Bind(wx.EVT_CLOSE, self.onClose)
- self.EscapeId = wx.ID_CLOSE
-
- self.onFeedsListChoice(None)
- mainSizer.Add(sHelper.sizer, flag=wx.ALL,
border=guiHelper.BORDER_FOR_DIALOGS)
- mainSizer.Fit(self)
- self.Sizer = mainSizer
- self.searchTextEdit.SetFocus()
- self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
-
- def __del__(self):
- FeedsDialog._instance = None
-
- def createFeed(self, address):
- feed = Feed(address)
- feedName = api.filterFileName(feed.getFeedName())
- if os.path.isfile(os.path.join(FEEDS_PATH, "%s.txt" %
feedName)):
- feedName = "tempFeed"
- with open(os.path.join(FEEDS_PATH, "%s.txt" % feedName), "w")
as f:
- f.write(address)
- f.close()
- return feedName
-
- def onSearchEditTextChange(self, evt):
- self.feedsList.Clear()
- # Based on the filter of the Input gestures dialog of NVDA's
core.
- filter = self.searchTextEdit.Value
- filter = re.escape(filter)
- filterReg = re.compile(r'(?=.*?' +
r')(?=.*?'.join(filter.split('\ ')) + r')', re.U|re.IGNORECASE)
- for choice in self.choices:
- if filter and not filterReg.match(choice):
- continue
- self.feedsList.Append(choice)
- self.feedsList.Selection = 0
- self.onFeedsListChoice(None)
-
- def onFeedsListChoice(self, evt):
- self.sel = self.feedsList.Selection
- self.stringSel = self.feedsList.StringSelection
- self.articlesButton.Enabled = self.sel>= 0
- self.deleteButton.Enabled = self.sel >= 0
- self.renameButton.Enabled = self.sel >= 0
- self.defaultButton.Enabled = (self.sel >= 0 and
- self.stringSel !=
config.conf["readFeeds"]["addressFile"])
-
- def onArticles(self, evt):
- with open(os.path.join(FEEDS_PATH, "%s.txt" % self.stringSel),
"r") as f:
- address = f.read()
- f.close()
- feed = Feed(address)
- with wx.SingleChoiceDialog(self,
- # Translators: the label of a single choice dialog.
- _("Open web page of selected article."),
- # Translators: Title of a dialog.
- u"{feedTitle}
({feedNumber})".format(feedTitle=self.stringSel,
feedNumber=feed.getNumberOfArticles()),
- [feed.getArticleTitle(index) for index in
xrange(feed.getNumberOfArticles())]) as d:
- if d.ShowModal() == wx.ID_CANCEL:
- return
- os.startfile(feed.getArticleLink(d.Selection))
-
- def onNew(self, evt):
- # Translators: The label of a field to enter an address for a
new feed.
- with wx.TextEntryDialog(self, _("Address of a new feed:"),
- # Translators: The title of a dialog to create a new
feed.
- _("New feed")) as d:
- if d.ShowModal() == wx.ID_CANCEL:
- return
- name = self.createFeed(d.Value)
- self.feedsList.Append(name)
-
- def onDelete(self, evt):
- if gui.messageBox(
- # Translators: The confirmation prompt displayed when
the user requests to delete a feed.
- _("Are you sure you want to delete this feed? This
cannot be undone."),
- # Translators: The title of the confirmation dialog for
deletion of a feed.
- _("Confirm Deletion"),
- wx.YES | wx.NO | wx.ICON_QUESTION, self
- ) == wx.NO:
- return
- os.remove(os.path.join(FEEDS_PATH, "%s.txt" % self.stringSel))
- self.feedsList.Delete(self.sel)
- self.feedsList.Selection = 0
- self.onFeedsListChoice(None)
-
- def onDefault(self, evt):
- config.conf["readFeeds"]["addressFile"] = self.stringSel
- self.onFeedsListChoice(None)
- self.searchTextEdit.SetFocus()
-
- def onRename(self, evt):
- # Translators: The label of a field to enter a new name for a
feed.
- with wx.TextEntryDialog(self, _("New name:"),
- # Translators: The title of a dialog to rename
a feed.
- _("Rename feed"), defaultValue=self.stringSel)
as d:
- if d.ShowModal() == wx.ID_CANCEL or not d.Value:
- return
- curName = "%s.txt" % self.stringSel
- newName = "%s.txt" % api.filterFileName(d.Value)
- os.rename(os.path.join(FEEDS_PATH, curName),
- os.path.join(FEEDS_PATH, newName))
- self.feedsList.SetString(self.sel, os.path.splitext(newName)[0])
-
- def onClose(self, evt):
- self.Destroy()
-
-class Feed(object):
-
- def __init__(self, url):
- super(Feed, self).__init__()
- self._url = url
- self._document = None
- self._articles = []
- self.refresh()
-
- def refresh(self):
- try:
- self._document =
minidom.parse(urllib.urlopen(self._url))
- except Exception as e:
- raise e
- # Check if we are dealing with an rss or atom feed.
- rssFeed = self._document.getElementsByTagName('channel')
- if len(rssFeed):
- self._feedType = 'rss'
- self._articles =
self._document.getElementsByTagName('item')
- else:
- atomFeed = self._document.getElementsByTagName('feed')
- if len(atomFeed):
- self._feedType = 'atom'
- self._articles =
self._document.getElementsByTagName('entry')
- else:
- log.debugWarning("Unknown type of current
feed", exc_info=True)
- raise
- self._index = 0
-
- def getFeedUrl(self):
- return self._url
-
- def getFeedType(self):
- return self._feedType
-
- def getFeedName(self):
- try:
- return
self._document.getElementsByTagName('title')[0].firstChild.data
- except:
- return ""
-
- def getArticleTitle(self, index=None):
- if index is None: index = self._index
- try:
- return
self._articles[index].getElementsByTagName('title')[0].firstChild.data
- except:
- # Translators: Presented when the current article does
not have an associated title.
- return _("Unable to locate article title.")
-
- def getArticleLink(self, index=None):
- if index is None: index = self._index
- try:
- if self.getFeedType() == u'rss':
- return
self._articles[index].getElementsByTagName('link')[0].firstChild.data
- elif self.getFeedType() == u'atom':
- return
self._articles[index].getElementsByTagName('link')[0].getAttribute('href')
- except:
- # Translators: Presented when the current article does
not have an associated link.
- return _("Unable to locate article link.")
-
- def next(self):
- self._index += 1
- if self._index == self.getNumberOfArticles():
- self._index = 0
-
- def previous(self):
- self._index -= 1
- if self._index == -1:
- self._index = self.getNumberOfArticles() - 1
-
- def getNumberOfArticles(self):
- return len(self._articles)
-
-
-class GlobalPlugin(globalPluginHandler.GlobalPlugin):
-
- scriptCategory = unicode(ADDON_SUMMARY)
-
- def __init__(self):
- super(globalPluginHandler.GlobalPlugin, self).__init__()
- self.menu = gui.mainFrame.sysTrayIcon.toolsMenu
- self.readFeedsMenu = wx.Menu()
- self.mainItem = self.menu.AppendSubMenu(self.readFeedsMenu,
- # Translators: the name of a submenu.
- _("&Read Feeds"),
- # Translators: the tooltip for a submenu.
- _("Manage feeds."))
- self.feedsListItem = self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("&Feeds..."),
- # Translators: the tooltip for a menu item.
- _("View and manage feeds"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onFeeds,
self.feedsListItem)
- self.feed = None
-
- def terminate(self):
- try:
- self.menu.RemoveItem(self.mainItem)
- except wx.PyDeadObjectError:
- pass
-
- def onFeeds(self, evt):
- gui.mainFrame.prePopup()
- d = FeedsDialog(gui.mainFrame)
- d.Show()
- gui.mainFrame.postPopup()
-
- def script_feedsDialog(self, gesture):
- wx.CallAfter(self.onFeeds, None)
- # Translators: message presented in input mode.
- script_feedsDialog.__doc__ = _("Shows the Feeds dialog.")
-
- def getFirstFeed(self):
- if not self.feed:
- try:
- addressFile = "%s.txt" %
config.conf["readFeeds"]["addressFile"]
- with open(os.path.join(FEEDS_PATH,
addressFile), "r") as f:
- address = f.read()
- f.close()
- self.feed = Feed(address)
- except Exception as e:
- ui.message(CAN_NOT_REPORT)
-
- def script_readFirstFeed(self, gesture):
- self.getFirstFeed()
- if self.feed:
- ui.message(self.feed.getArticleTitle())
- # Translators: message presented in input mode.
- script_readFirstFeed.__doc__ = _("Refreshes the current feed and
announces the most recent article title.")
-
- def script_readCurrentFeed(self, gesture):
- self.getFirstFeed()
- feedInfo =
u"{title}\r\n\r\n{address}".format(title=self.feed.getArticleTitle(),
address=self.feed.getArticleLink())
- if scriptHandler.getLastScriptRepeatCount()==1 and
api.copyToClip(feedInfo):
- # Translators: message presented when the information
about an article of a feed is copied to the clipboard.
- ui.message(_("Copied to clipboard %s") % feedInfo)
- else:
- ui.message(feedInfo)
- # Translators: message presented in input mode.
- script_readCurrentFeed.__doc__ = _("Announces the title of the current
article. Pressed two times, copies title and related link to the clipboard.")
-
- def script_readNextFeed(self, gesture):
- self.getFirstFeed()
- self.feed.next()
- ui.message(self.feed.getArticleTitle())
- # Translators: message presented in input mode.
- script_readNextFeed.__doc__ = _("Announces the title of the next
article.")
-
- def script_readPriorFeed(self, gesture):
- self.getFirstFeed()
- self.feed.previous()
- ui.message(self.feed.getArticleTitle())
- # Translators: message presented in input mode.
- script_readPriorFeed.__doc__ = _("Announces the title of the previous
article.")
-
- def script_reportLink(self, gesture):
- self.getFirstFeed()
- feedLink = self.feed.getArticleLink()
- if scriptHandler.getLastScriptRepeatCount()==1:
- os.startfile(feedLink)
- else:
- ui.message(feedLink)
- # Translators: message presented in input mode.
- script_reportLink.__doc__ = _("Announces article link, when pressed two
times, opens related web page.")
-
- def script_copyFeedInfo(self, gesture):
- self.getFirstFeed()
- feedInfo =
u"{title}\r\n\r\n{address}".format(title=self.feed.getArticleTitle(),
address=self.feed.getArticleLink())
- if api.copyToClip(feedInfo):
- # Translators: message presented when the information
about an article of a feed is copied to the clipboard.
- ui.message(_("Copied to clipboard %s") % feedInfo)
-
- __gestures = {
- "kb:control+shift+NVDA+8": "readFirstFeed",
- "kb:control+shift+NVDA+i": "readCurrentFeed",
- "kb:control+shift+NVDA+o": "readNextFeed",
- "kb:control+shift+NVDA+u": "readPriorFeed",
- "kb:control+shift+NVDA+space": "reportLink",
- "kb:shift+NVDA+enter": "copyFeedInfo",
- }
-
diff --git a/addon/globalPlugins/readFeeds/__init__.py
b/addon/globalPlugins/readFeeds/__init__.py
new file mode 100644
index 0000000..9bfba46
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/__init__.py
@@ -0,0 +1,611 @@
+# -*- coding: UTF-8 -*-
+
+# Read feeds: A simple plugin for reading feeds with NVDA
+#Copyright (C) 2012-2016 Noelia Ruiz Martínez, Mesar Hameed
+# Released under GPL 2
+
+# Version: 6.0
+# Used globalVars to get config path, for better results with temporary
copies, as instantTranslate or SaveLog add-ons
+# Version: 5.0
+# Control instead of alt in gesture. Added installTask to update the add-on
+# Version: 4.2
+# Channel title and number of articles in News list dialog
+# Date: 23/06/2012
+
+import addonHandler
+import globalPluginHandler
+import os
+import sys
+import shutil
+import globalVars
+import config
+import urllib
+import scriptHandler
+import api
+import gui
+from gui import guiHelper
+import wx
+import ui
+from logHandler import log
+import re
+from skipTranslation import translate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
+from xml2.dom import minidom
+del sys.path[-1]
+
+addonHandler.initTranslation()
+
+### Constants
+
+ADDON_DIR = os.path.join(os.path.dirname(__file__), "..", "..") # The root of
the addon folder
+ADDON_INSTANCE = addonHandler.Addon(ADDON_DIR)
+ADDON_SUMMARY = ADDON_INSTANCE.manifest['summary']
+FEEDS_PATH = os.path.join(os.path.dirname(__file__),
"personalFeeds").decode("mbcs")
+CONFIG_PATH = globalVars.appArgs.configPath
+# Translators: message presented when feeds cannot be reported.
+CAN_NOT_REPORT = _("Unable to refresh feed. Check your Internet conectivity or
that the specified feed address is correct.")
+
+### Configuration
+
+confspec = {
+ "addressFile": "string(default="")",
+}
+config.conf.spec["readFeeds"] = confspec
+
+### Dialogs
+
+def doCopy(copyDirectory):
+ try:
+ shutil.rmtree(copyDirectory, ignore_errors=True)
+ shutil.copytree(FEEDS_PATH, copyDirectory)
+ wx.CallLater(100, ui.message,
+ # Translators: Message presented when feeds have been
copied.
+ _("Feeds copied"))
+ except Exception as e:
+ wx.CallAfter(gui.messageBox,
+ # Translators: label of error dialog shown when cannot
copy feeds folder.
+ _("Folder not copied"),
+ # Translators: title of error dialog shown when cannot
copy feeds folder.
+ _("Copy Error"),
+ wx.OK|wx.ICON_ERROR)
+ raise e
+
+def doRestore(restoreDirectory):
+ try:
+ shutil.rmtree(FEEDS_PATH, ignore_errors=True)
+ shutil.copytree(restoreDirectory, FEEDS_PATH)
+ wx.CallLater(100, ui.message,
+ # Translators: Message presented when feeds have been
restored.
+ _("Feeds restored"))
+ except Exception as e:
+ wx.CallAfter(gui.messageBox,
+ # Translators: label of error dialog shown when cannot
copy feeds folder.
+ _("Folder not copied"),
+ # Translators: title of error dialog shown when cannot
copy feeds folder.
+ _("Copy Error"),
+ wx.OK|wx.ICON_ERROR)
+ raise e
+
+class FeedsDialog(wx.Dialog):
+
+ _instance = None
+ def __new__(cls, *args, **kwargs):
+ # Make this a singleton.
+ if FeedsDialog._instance is None:
+ return super(FeedsDialog, cls).__new__(cls, *args,
**kwargs)
+ return FeedsDialog._instance
+
+ def __init__(self, parent):
+ if FeedsDialog._instance is not None:
+ return
+ FeedsDialog._instance = self
+ # Translators: The title of a dialog.
+ super(FeedsDialog, self).__init__(parent, title=_("Feeds"))
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ sHelper = guiHelper.BoxSizerHelper(self,orientation=wx.VERTICAL)
+ feedsListGroupSizer = wx.StaticBoxSizer(wx.StaticBox(self),
wx.HORIZONTAL)
+ feedsListGroupContents = wx.BoxSizer(wx.HORIZONTAL)
+ changeFeedsSizer = wx.BoxSizer(wx.VERTICAL)
+
+ # Translators: The label of an edit box to search feeds.
+ searchTextLabel = _("&Text to search:")
+ searchLabeledCtrl = gui.guiHelper.LabeledControlHelper(self,
searchTextLabel, wx.TextCtrl)
+ self.searchTextEdit = searchLabeledCtrl.control
+ self.searchTextEdit.Bind(wx.EVT_TEXT,
self.onSearchEditTextChange)
+
+ self.choices = [os.path.splitext(filename)[0] for filename in
os.listdir(FEEDS_PATH)]
+ self.feedsList = wx.ListBox(self,
+ choices=self.choices)
+ self.feedsList.Selection = 0
+ self.feedsList.Bind(wx.EVT_LISTBOX, self.onFeedsListChoice)
+ changeFeedsSizer.Add(self.feedsList, proportion=1.0)
+
changeFeedsSizer.AddSpacer(guiHelper.SPACE_BETWEEN_BUTTONS_VERTICAL)
+
+ # Translators: The label of a button to open the list of
articles of a feed.
+ self.articlesButton = wx.Button(self, label=_("List of
&articles..."))
+ self.articlesButton.Bind(wx.EVT_BUTTON, self.onArticles)
+ self.AffirmativeId = self.articlesButton.Id
+ self.articlesButton.SetDefault()
+ changeFeedsSizer.Add(self.articlesButton)
+
+ feedsListGroupContents.Add(changeFeedsSizer, flag = wx.EXPAND)
+
feedsListGroupContents.AddSpacer(guiHelper.SPACE_BETWEEN_ASSOCIATED_CONTROL_HORIZONTAL)
+
+ buttonHelper = guiHelper.ButtonHelper(wx.VERTICAL)
+ # Translators: The label of a button to add a new feed.
+ newButton = buttonHelper.addButton(self, label=_("&New..."))
+ newButton.Bind(wx.EVT_BUTTON, self.onNew)
+
+ # Translators: The label of a button to rename a feed.
+ self.renameButton = buttonHelper.addButton(self,
label=_("&Rename..."))
+ self.renameButton.Bind(wx.EVT_BUTTON, self.onRename)
+
+ # Translators: The label of a button to delete a feed.
+ self.deleteButton = buttonHelper.addButton(self,
label=_("&Delete..."))
+ self.deleteButton.Bind(wx.EVT_BUTTON, self.onDelete)
+
+# Translators: The label of a button to set a feed as default.
+ self.defaultButton = buttonHelper.addButton(self, label=_("S&et
default"))
+ self.defaultButton.Bind(wx.EVT_BUTTON, self.onDefault)
+
+ feedsListGroupContents.Add(buttonHelper.sizer)
+ feedsListGroupSizer.Add(feedsListGroupContents,
border=guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
+ sHelper.addItem(feedsListGroupSizer)
+
+ # Translators: The label of a button to close a dialog.
+ closeButton = wx.Button(self, wx.ID_CLOSE, label=_("&Close"))
+ closeButton.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
+ sHelper.addDialogDismissButtons(closeButton)
+ self.Bind(wx.EVT_CLOSE, self.onClose)
+ self.EscapeId = wx.ID_CLOSE
+
+ self.onFeedsListChoice(None)
+ mainSizer.Add(sHelper.sizer, flag=wx.ALL,
border=guiHelper.BORDER_FOR_DIALOGS)
+ mainSizer.Fit(self)
+ self.Sizer = mainSizer
+ self.searchTextEdit.SetFocus()
+ self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
+
+ def __del__(self):
+ FeedsDialog._instance = None
+
+ def createFeed(self, address):
+ feed = Feed(address)
+ feedName = api.filterFileName(feed.getFeedName())
+ if os.path.isfile(os.path.join(FEEDS_PATH, "%s.txt" %
feedName)):
+ feedName = "tempFeed"
+ with open(os.path.join(FEEDS_PATH, "%s.txt" % feedName), "w")
as f:
+ f.write(address)
+ f.close()
+ return feedName
+
+ def onSearchEditTextChange(self, evt):
+ self.feedsList.Clear()
+ # Based on the filter of the Input gestures dialog of NVDA's
core.
+ filter = self.searchTextEdit.Value
+ filter = re.escape(filter)
+ filterReg = re.compile(r'(?=.*?' +
r')(?=.*?'.join(filter.split('\ ')) + r')', re.U|re.IGNORECASE)
+ for choice in self.choices:
+ if filter and not filterReg.match(choice):
+ continue
+ self.feedsList.Append(choice)
+ self.feedsList.Selection = 0
+ self.onFeedsListChoice(None)
+
+ def onFeedsListChoice(self, evt):
+ self.sel = self.feedsList.Selection
+ self.stringSel = self.feedsList.StringSelection
+ self.articlesButton.Enabled = self.sel>= 0
+ self.deleteButton.Enabled = self.sel >= 0
+ self.renameButton.Enabled = self.sel >= 0
+ self.defaultButton.Enabled = (self.sel >= 0 and
+ self.stringSel !=
config.conf["readFeeds"]["addressFile"])
+
+ def onArticles(self, evt):
+ with open(os.path.join(FEEDS_PATH, "%s.txt" % self.stringSel),
"r") as f:
+ address = f.read()
+ f.close()
+ feed = Feed(address)
+ with wx.SingleChoiceDialog(self,
+ # Translators: the label of a single choice dialog.
+ _("Open web page of selected article."),
+ # Translators: Title of a dialog.
+ u"{feedTitle}
({feedNumber})".format(feedTitle=self.stringSel,
feedNumber=feed.getNumberOfArticles()),
+ [feed.getArticleTitle(index) for index in
xrange(feed.getNumberOfArticles())]) as d:
+ if d.ShowModal() == wx.ID_CANCEL:
+ return
+ os.startfile(feed.getArticleLink(d.Selection))
+
+ def onNew(self, evt):
+ # Translators: The label of a field to enter an address for a
new feed.
+ with wx.TextEntryDialog(self, _("Address of a new feed:"),
+ # Translators: The title of a dialog to create a new
feed.
+ _("New feed")) as d:
+ if d.ShowModal() == wx.ID_CANCEL:
+ return
+ name = self.createFeed(d.Value)
+ self.feedsList.Append(name)
+
+ def onDelete(self, evt):
+ if gui.messageBox(
+ # Translators: The confirmation prompt displayed when
the user requests to delete a feed.
+ _("Are you sure you want to delete this feed? This
cannot be undone."),
+ # Translators: The title of the confirmation dialog for
deletion of a feed.
+ _("Confirm Deletion"),
+ wx.YES | wx.NO | wx.ICON_QUESTION, self
+ ) == wx.NO:
+ return
+ os.remove(os.path.join(FEEDS_PATH, "%s.txt" % self.stringSel))
+ self.feedsList.Delete(self.sel)
+ self.feedsList.Selection = 0
+ self.onFeedsListChoice(None)
+
+ def onDefault(self, evt):
+ config.conf["readFeeds"]["addressFile"] = self.stringSel
+ self.onFeedsListChoice(None)
+ self.searchTextEdit.SetFocus()
+
+ def onRename(self, evt):
+ # Translators: The label of a field to enter a new name for a
feed.
+ with wx.TextEntryDialog(self, _("New name:"),
+ # Translators: The title of a dialog to rename
a feed.
+ _("Rename feed"), defaultValue=self.stringSel)
as d:
+ if d.ShowModal() == wx.ID_CANCEL or not d.Value:
+ return
+ curName = "%s.txt" % self.stringSel
+ newName = "%s.txt" % api.filterFileName(d.Value)
+ os.rename(os.path.join(FEEDS_PATH, curName),
+ os.path.join(FEEDS_PATH, newName))
+ self.feedsList.SetString(self.sel, os.path.splitext(newName)[0])
+
+ def onClose(self, evt):
+ self.Destroy()
+
+class CopyDialog(wx.Dialog):
+
+ def __init__(self, parent):
+ # Translators: The title of the Copy dialog.
+ super(CopyDialog, self).__init__(parent, title=_("Copy feeds"))
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ sHelper = gui.guiHelper.BoxSizerHelper(self,
orientation=wx.VERTICAL)
+
+ # Translators: An informational message displayed in the Copy
dialog.
+ dialogCaption=_("""Select a folder to save a backup of your
current feeds.\n
+ They will be copied from %s.""" % FEEDS_PATH)
+ sHelper.addItem(wx.StaticText(self, label=dialogCaption))
+
+ # Translators: The label of a grouping containing controls to
select the destination directory in the Copy dialog.
+ directoryGroupText = _("directory for backup:")
+ groupHelper =
sHelper.addItem(gui.guiHelper.BoxSizerHelper(self,
sizer=wx.StaticBoxSizer(wx.StaticBox(self, label=directoryGroupText),
wx.VERTICAL)))
+ # Message translated in NVDA core.
+ browseText = translate("Browse...")
+ # Translators: The title of the dialog presented when browsing
for the destination directory when copying feeds.
+ dirDialogTitle = _("Select directory to copy")
+ directoryEntryControl =
groupHelper.addItem(gui.guiHelper.PathSelectionHelper(self, browseText,
dirDialogTitle))
+ self.copyDirectoryEdit = directoryEntryControl.pathControl
+ self.copyDirectoryEdit.Value = os.path.join(CONFIG_PATH,
"personalFeeds")
+ bHelper =
sHelper.addDialogDismissButtons(gui.guiHelper.ButtonHelper(wx.HORIZONTAL))
+ # Message translated in NVDA core.
+ continueButton = bHelper.addButton(self,
label=translate("&Continue"), id=wx.ID_OK)
+ continueButton.SetDefault()
+ continueButton.Bind(wx.EVT_BUTTON, self.onCopy)
+ bHelper.addButton(self, id=wx.ID_CANCEL)
+ mainSizer.Add(sHelper.sizer,
border=gui.guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
+ self.Sizer = mainSizer
+ mainSizer.Fit(self)
+ self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
+
+ def onCopy(self, evt):
+ if not self.copyDirectoryEdit.Value:
+ # Message translated in NVDA core.
+ gui.messageBox(translate("Please specify a directory."),
+ # Message translated in NVDA core.
+ translate("Error"),
+ wx.OK | wx.ICON_ERROR)
+ return
+ drv=os.path.splitdrive(self.copyDirectoryEdit.Value)[0]
+ if drv and not os.path.isdir(drv):
+ # Message translated in NVDA core.
+ gui.messageBox(translate("Invalid drive %s")%drv,
+ # Message translated in NVDA core.
+ translate("Error"),
+ wx.OK | wx.ICON_ERROR)
+ return
+ self.Hide()
+ doCopy(self.copyDirectoryEdit.Value)
+ self.Destroy()
+
+ def onCancel(self, evt):
+ self.Destroy()
+
+class PathSelectionWithoutNewDir(gui.guiHelper.PathSelectionHelper):
+
+ def __init__(self, parent, buttonText, browseForDirectoryTitle):
+ super(PathSelectionWithoutNewDir, self).__init__(parent,
buttonText, browseForDirectoryTitle)
+
+ def onBrowseForDirectory(self, evt):
+ startPath = self.getDefaultBrowseForDirectoryPath()
+ with wx.DirDialog(self._parent, self._browseForDirectoryTitle,
defaultPath=startPath, style=wx.DD_DIR_MUST_EXIST | wx.DD_DEFAULT_STYLE) as d:
+ if d.ShowModal() == wx.ID_OK:
+ self._textCtrl.Value = d.Path
+
+class RestoreDialog(wx.Dialog):
+
+ def __init__(self, parent):
+ # Translators: The title of the Restore dialog.
+ super(RestoreDialog, self).__init__(parent, title=_("Restore
feeds"))
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ sHelper = gui.guiHelper.BoxSizerHelper(self,
orientation=wx.VERTICAL)
+
+ # Translators: An informational message displayed in the
Restore dialog.
+ dialogCaption=_("""Select a folder to restore a backup of your
previous copied feeds.\n
+ They will be copied to %s.""" % FEEDS_PATH)
+ sHelper.addItem(wx.StaticText(self, label=dialogCaption))
+
+ # Translators: The label of a grouping containing controls to
select the destination directory in the Restore dialog.
+ directoryGroupText = _("directory containing backup:")
+ groupHelper =
sHelper.addItem(gui.guiHelper.BoxSizerHelper(self,
sizer=wx.StaticBoxSizer(wx.StaticBox(self, label=directoryGroupText),
wx.VERTICAL)))
+ # Message translated in NVDA core.
+ browseText = translate("Browse...")
+ # Translators: The title of the dialog presented when browsing
for the destination directory when restoring feeds.
+ dirDialogTitle = _("Select directory to restore")
+ directoryEntryControl =
groupHelper.addItem(PathSelectionWithoutNewDir(self, browseText,
dirDialogTitle))
+ self.restoreDirectoryEdit = directoryEntryControl.pathControl
+ backupDirectory = os.path.join(CONFIG_PATH, "personalFeeds")
+ if os.path.isdir(backupDirectory):
+ self.restoreDirectoryEdit.Value = backupDirectory
+ bHelper =
sHelper.addDialogDismissButtons(gui.guiHelper.ButtonHelper(wx.HORIZONTAL))
+ # Message translated in NVDA core.
+ continueButton = bHelper.addButton(self,
label=translate("&Continue"), id=wx.ID_OK)
+ continueButton.SetDefault()
+ continueButton.Bind(wx.EVT_BUTTON, self.onRestore)
+ bHelper.addButton(self, id=wx.ID_CANCEL)
+ mainSizer.Add(sHelper.sizer,
border=gui.guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
+ self.Sizer = mainSizer
+ mainSizer.Fit(self)
+ self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
+
+ def onRestore(self, evt):
+ if not self.restoreDirectoryEdit.Value:
+ # Message translated in NVDA core.
+ gui.messageBox(translate("Please specify a directory."),
+ # Message translated in NVDA core.
+ translate("Error"),
+ wx.OK | wx.ICON_ERROR)
+ return
+ drv=os.path.splitdrive(self.restoreDirectoryEdit.Value)[0]
+ if drv and not os.path.isdir(drv):
+ # Message translated in NVDA core.
+ gui.messageBox(translate("Invalid drive %s")%drv,
+ # Message translated in NVDA core.
+ translate("Error"),
+ wx.OK | wx.ICON_ERROR)
+ return
+ self.Hide()
+ doRestore(self.restoreDirectoryEdit.Value)
+ self.Destroy()
+
+ def onCancel(self, evt):
+ self.Destroy()
+
+### Feed object
+
+class Feed(object):
+
+ def __init__(self, url):
+ super(Feed, self).__init__()
+ self._url = url
+ self._document = None
+ self._articles = []
+ self.refresh()
+
+ def refresh(self):
+ try:
+ self._document =
minidom.parse(urllib.urlopen(self._url))
+ except Exception as e:
+ raise e
+ # Check if we are dealing with an rss or atom feed.
+ rssFeed = self._document.getElementsByTagName('channel')
+ if len(rssFeed):
+ self._feedType = 'rss'
+ self._articles =
self._document.getElementsByTagName('item')
+ else:
+ atomFeed = self._document.getElementsByTagName('feed')
+ if len(atomFeed):
+ self._feedType = 'atom'
+ self._articles =
self._document.getElementsByTagName('entry')
+ else:
+ log.debugWarning("Unknown type of current
feed", exc_info=True)
+ raise
+ self._index = 0
+
+ def getFeedUrl(self):
+ return self._url
+
+ def getFeedType(self):
+ return self._feedType
+
+ def getFeedName(self):
+ try:
+ return
self._document.getElementsByTagName('title')[0].firstChild.data
+ except:
+ return ""
+
+ def getArticleTitle(self, index=None):
+ if index is None: index = self._index
+ try:
+ return
self._articles[index].getElementsByTagName('title')[0].firstChild.data
+ except:
+ # Translators: Presented when the current article does
not have an associated title.
+ return _("Unable to locate article title.")
+
+ def getArticleLink(self, index=None):
+ if index is None: index = self._index
+ try:
+ if self.getFeedType() == u'rss':
+ return
self._articles[index].getElementsByTagName('link')[0].firstChild.data
+ elif self.getFeedType() == u'atom':
+ return
self._articles[index].getElementsByTagName('link')[0].getAttribute('href')
+ except:
+ # Translators: Presented when the current article does
not have an associated link.
+ return _("Unable to locate article link.")
+
+ def next(self):
+ self._index += 1
+ if self._index == self.getNumberOfArticles():
+ self._index = 0
+
+ def previous(self):
+ self._index -= 1
+ if self._index == -1:
+ self._index = self.getNumberOfArticles() - 1
+
+ def getNumberOfArticles(self):
+ return len(self._articles)
+
+class GlobalPlugin(globalPluginHandler.GlobalPlugin):
+
+ scriptCategory = unicode(ADDON_SUMMARY)
+
+ def __init__(self):
+ super(globalPluginHandler.GlobalPlugin, self).__init__()
+ self.menu = gui.mainFrame.sysTrayIcon.toolsMenu
+ self.readFeedsMenu = wx.Menu()
+ self.mainItem = self.menu.AppendSubMenu(self.readFeedsMenu,
+ # Translators: the name of a submenu.
+ _("&Read Feeds"),
+ # Translators: the tooltip for a submenu.
+ _("Manage feeds."))
+ self.feedsListItem = self.readFeedsMenu.Append(wx.ID_ANY,
+ # Translators: the name of a menu item.
+ _("&Feeds..."),
+ # Translators: the tooltip for a menu item.
+ _("View and manage feeds"))
+ gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onFeeds,
self.feedsListItem)
+ self.copyItem = self.readFeedsMenu.Append(wx.ID_ANY,
+ # Translators: the name for an item of addon submenu.
+ _("&Copy feeds folder..."),
+ # Translators: the tooltip text for an item of addon
submenu.
+ _("Backup of feeds"))
+ gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onCopy,
self.copyItem)
+ self.restoreItem = self.readFeedsMenu.Append(wx.ID_ANY,
+ # Translators: the name for an item of addon submenu.
+ _("R&estore feeds..."),
+ # Translators: the tooltip text for an item of addon
submenu.
+ _("Restore previously saved feeds"))
+ gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onRestore,
self.restoreItem)
+
+ self.feed = None
+
+ def terminate(self):
+ try:
+ self.menu.RemoveItem(self.mainItem)
+ except wx.PyDeadObjectError:
+ pass
+
+ def onFeeds(self, evt):
+ gui.mainFrame.prePopup()
+ d = FeedsDialog(gui.mainFrame)
+ d.Show()
+ gui.mainFrame.postPopup()
+
+ def script_activateFeedsDialog(self, gesture):
+ wx.CallAfter(self.onFeeds, None)
+ # Translators: message presented in input mode.
+ script_activateFeedsDialog.__doc__ = _("Shows the Feeds dialog of %s."
% ADDON_SUMMARY)
+
+ def onCopy(self, evt):
+ gui.mainFrame.prePopup()
+ d = CopyDialog(gui.mainFrame)
+ d.Show()
+ gui.mainFrame.postPopup()
+
+ def script_activateCopyDialog(self, gesture):
+ wx.CallAfter(self.onCopy, None)
+ # Translators: message presented in input mode.
+ script_activateCopyDialog.__doc__ = _("Activates the Copy dialog of
%s." % ADDON_SUMMARY)
+
+ def onRestore(self, evt):
+ gui.mainFrame.prePopup()
+ d = RestoreDialog(gui.mainFrame)
+ d.Show()
+ gui.mainFrame.postPopup()
+
+ def script_activateRestoreDialog(self, gesture):
+ wx.CallAfter(self.onRestore, None)
+ # Translators: message presented in input mode.
+ script_activateRestoreDialog.__doc__ = _("Activates the Restore dialog
of %s." % ADDON_SUMMARY)
+
+ def getFirstFeed(self):
+ if not self.feed:
+ try:
+ addressFile = "%s.txt" %
config.conf["readFeeds"]["addressFile"]
+ with open(os.path.join(FEEDS_PATH,
addressFile), "r") as f:
+ address = f.read()
+ f.close()
+ self.feed = Feed(address)
+ except Exception as e:
+ ui.message(CAN_NOT_REPORT)
+
+ def script_readFirstFeed(self, gesture):
+ self.getFirstFeed()
+ if self.feed:
+ ui.message(self.feed.getArticleTitle())
+ # Translators: message presented in input mode.
+ script_readFirstFeed.__doc__ = _("Refreshes the current feed and
announces the most recent article title.")
+
+ def script_readCurrentFeed(self, gesture):
+ self.getFirstFeed()
+ feedInfo =
u"{title}\r\n\r\n{address}".format(title=self.feed.getArticleTitle(),
address=self.feed.getArticleLink())
+ if scriptHandler.getLastScriptRepeatCount()==1 and
api.copyToClip(feedInfo):
+ # Translators: message presented when the information
about an article of a feed is copied to the clipboard.
+ ui.message(_("Copied to clipboard %s") % feedInfo)
+ else:
+ ui.message(feedInfo)
+ # Translators: message presented in input mode.
+ script_readCurrentFeed.__doc__ = _("Announces the title of the current
article. Pressed two times, copies title and related link to the clipboard.")
+
+ def script_readNextFeed(self, gesture):
+ self.getFirstFeed()
+ self.feed.next()
+ ui.message(self.feed.getArticleTitle())
+ # Translators: message presented in input mode.
+ script_readNextFeed.__doc__ = _("Announces the title of the next
article.")
+
+ def script_readPriorFeed(self, gesture):
+ self.getFirstFeed()
+ self.feed.previous()
+ ui.message(self.feed.getArticleTitle())
+ # Translators: message presented in input mode.
+ script_readPriorFeed.__doc__ = _("Announces the title of the previous
article.")
+
+ def script_reportLink(self, gesture):
+ self.getFirstFeed()
+ feedLink = self.feed.getArticleLink()
+ if scriptHandler.getLastScriptRepeatCount()==1:
+ os.startfile(feedLink)
+ else:
+ ui.message(feedLink)
+ # Translators: message presented in input mode.
+ script_reportLink.__doc__ = _("Announces article link, when pressed two
times, opens related web page.")
+
+ def script_copyFeedInfo(self, gesture):
+ self.getFirstFeed()
+ feedInfo =
u"{title}\r\n\r\n{address}".format(title=self.feed.getArticleTitle(),
address=self.feed.getArticleLink())
+ if api.copyToClip(feedInfo):
+ # Translators: message presented when the information
about an article of a feed is copied to the clipboard.
+ ui.message(_("Copied to clipboard %s") % feedInfo)
+
+ __gestures = {
+ "kb:control+shift+NVDA+8": "readFirstFeed",
+ "kb:control+shift+NVDA+i": "readCurrentFeed",
+ "kb:control+shift+NVDA+o": "readNextFeed",
+ "kb:control+shift+NVDA+u": "readPriorFeed",
+ "kb:control+shift+NVDA+space": "reportLink",
+ "kb:shift+NVDA+enter": "copyFeedInfo",
+ }
+
diff --git a/addon/globalPlugins/readFeeds/__init__.pyo
b/addon/globalPlugins/readFeeds/__init__.pyo
new file mode 100644
index 0000000..5ee0829
Binary files /dev/null and b/addon/globalPlugins/readFeeds/__init__.pyo differ
diff --git a/addon/globalPlugins/readFeeds/personalFeeds/Blog SpazioAusili.txt
b/addon/globalPlugins/readFeeds/personalFeeds/Blog SpazioAusili.txt
new file mode 100644
index 0000000..4e93538
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/personalFeeds/Blog SpazioAusili.txt
@@ -0,0 +1 @@
+http://www.spazioausili.net/rss/blog
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds/personalFeeds/Forum SpazioAusili.txt
b/addon/globalPlugins/readFeeds/personalFeeds/Forum SpazioAusili.txt
new file mode 100644
index 0000000..467e223
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/personalFeeds/Forum SpazioAusili.txt
@@ -0,0 +1 @@
+http://www.spazioausili.net/rss/forum
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds/personalFeeds/W3C-news.txt
b/addon/globalPlugins/readFeeds/personalFeeds/W3C-news.txt
new file mode 100644
index 0000000..d6d78cd
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/personalFeeds/W3C-news.txt
@@ -0,0 +1 @@
+http://www.w3.org/News/atom.xml
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds/personalFeeds/addons NVDA-project IT
RSS.txt b/addon/globalPlugins/readFeeds/personalFeeds/addons NVDA-project IT
RSS.txt
new file mode 100644
index 0000000..ce662ed
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/personalFeeds/addons NVDA-project IT
RSS.txt
@@ -0,0 +1 @@
+http://addons.nvda-project.org/index.it.rss
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds/personalFeeds/addressFile.txt
b/addon/globalPlugins/readFeeds/personalFeeds/addressFile.txt
new file mode 100644
index 0000000..467e223
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/personalFeeds/addressFile.txt
@@ -0,0 +1 @@
+http://www.spazioausili.net/rss/forum
\ No newline at end of file
diff --git a/addon/globalPlugins/readFeeds/skipTranslation.py
b/addon/globalPlugins/readFeeds/skipTranslation.py
new file mode 100644
index 0000000..ea074a6
--- /dev/null
+++ b/addon/globalPlugins/readFeeds/skipTranslation.py
@@ -0,0 +1,9 @@
+# -*- coding: UTF-8 -*-
+# skipTranslation: Module to get translated texts from NVDA
+# Based on implementation made by Alberto Buffolino
+# https://github.com/nvaccess/nvda/issues/4652
+#Copyright (C) 2016 Noelia Ruiz Martínez
+# Released under GPL 2
+
+def translate(text):
+ return _(text)
diff --git a/addon/globalPlugins/readFeeds/skipTranslation.pyo
b/addon/globalPlugins/readFeeds/skipTranslation.pyo
new file mode 100644
index 0000000..6bbe7c0
Binary files /dev/null and b/addon/globalPlugins/readFeeds/skipTranslation.pyo
differ
diff --git a/addon/globalPlugins/xml2/__init__.py
b/addon/globalPlugins/xml2/__init__.py
deleted file mode 100644
index f7dcb04..0000000
--- a/addon/globalPlugins/xml2/__init__.py
+++ /dev/null
@@ -1,48 +0,0 @@
-"""Core XML support for Python.
-
-This package contains four sub-packages:
-
-dom -- The W3C Document Object Model. This supports DOM Level 1 +
- Namespaces.
-
-parsers -- Python wrappers for XML parsers (currently only supports Expat).
-
-sax -- The Simple API for XML, developed by XML-Dev, led by David
- Megginson and ported to Python by Lars Marius Garshol. This
- supports the SAX 2 API.
-
-etree -- The ElementTree XML library. This is a subset of the full
- ElementTree XML release.
-
-"""
-
-
-__all__ = ["dom", "parsers", "sax", "etree"]
-
-_MINIMUM_XMLPLUS_VERSION = (0, 8, 4)
-
-
-try:
- import _xmlplus
-except ImportError:
- pass
-else:
- try:
- v = _xmlplus.version_info
- except AttributeError:
- # _xmlplus is too old; ignore it
- pass
- else:
- if v >= _MINIMUM_XMLPLUS_VERSION:
- import sys
- _xmlplus.__path__.extend(__path__)
- sys.modules[__name__] = _xmlplus
- else:
- del v
-
-import globalPluginHandler
-
-class GlobalPlugin(globalPluginHandler.GlobalPlugin):
-
- """Plugin class"""
-
diff --git a/addon/globalPlugins/xml2/dom/NodeFilter.py
b/addon/globalPlugins/xml2/dom/NodeFilter.py
deleted file mode 100644
index fc05245..0000000
--- a/addon/globalPlugins/xml2/dom/NodeFilter.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This is the Python mapping for interface NodeFilter from
-# DOM2-Traversal-Range. It contains only constants.
-
-class NodeFilter:
- """
- This is the DOM2 NodeFilter interface. It contains only constants.
- """
- FILTER_ACCEPT = 1
- FILTER_REJECT = 2
- FILTER_SKIP = 3
-
- SHOW_ALL = 0xFFFFFFFFL
- SHOW_ELEMENT = 0x00000001
- SHOW_ATTRIBUTE = 0x00000002
- SHOW_TEXT = 0x00000004
- SHOW_CDATA_SECTION = 0x00000008
- SHOW_ENTITY_REFERENCE = 0x00000010
- SHOW_ENTITY = 0x00000020
- SHOW_PROCESSING_INSTRUCTION = 0x00000040
- SHOW_COMMENT = 0x00000080
- SHOW_DOCUMENT = 0x00000100
- SHOW_DOCUMENT_TYPE = 0x00000200
- SHOW_DOCUMENT_FRAGMENT = 0x00000400
- SHOW_NOTATION = 0x00000800
-
- def acceptNode(self, node):
- raise NotImplementedError
diff --git a/addon/globalPlugins/xml2/dom/__init__.py
b/addon/globalPlugins/xml2/dom/__init__.py
deleted file mode 100644
index 6363d00..0000000
--- a/addon/globalPlugins/xml2/dom/__init__.py
+++ /dev/null
@@ -1,139 +0,0 @@
-"""W3C Document Object Model implementation for Python.
-
-The Python mapping of the Document Object Model is documented in the
-Python Library Reference in the section on the xml.dom package.
-
-This package contains the following modules:
-
-minidom -- A simple implementation of the Level 1 DOM with namespace
- support added (based on the Level 2 specification) and other
- minor Level 2 functionality.
-
-pulldom -- DOM builder supporting on-demand tree-building for selected
- subtrees of the document.
-
-"""
-
-
-class Node:
- """Class giving the NodeType constants."""
-
- # DOM implementations may use this as a base class for their own
- # Node implementations. If they don't, the constants defined here
- # should still be used as the canonical definitions as they match
- # the values given in the W3C recommendation. Client code can
- # safely refer to these values in all tests of Node.nodeType
- # values.
-
- ELEMENT_NODE = 1
- ATTRIBUTE_NODE = 2
- TEXT_NODE = 3
- CDATA_SECTION_NODE = 4
- ENTITY_REFERENCE_NODE = 5
- ENTITY_NODE = 6
- PROCESSING_INSTRUCTION_NODE = 7
- COMMENT_NODE = 8
- DOCUMENT_NODE = 9
- DOCUMENT_TYPE_NODE = 10
- DOCUMENT_FRAGMENT_NODE = 11
- NOTATION_NODE = 12
-
-
-#ExceptionCode
-INDEX_SIZE_ERR = 1
-DOMSTRING_SIZE_ERR = 2
-HIERARCHY_REQUEST_ERR = 3
-WRONG_DOCUMENT_ERR = 4
-INVALID_CHARACTER_ERR = 5
-NO_DATA_ALLOWED_ERR = 6
-NO_MODIFICATION_ALLOWED_ERR = 7
-NOT_FOUND_ERR = 8
-NOT_SUPPORTED_ERR = 9
-INUSE_ATTRIBUTE_ERR = 10
-INVALID_STATE_ERR = 11
-SYNTAX_ERR = 12
-INVALID_MODIFICATION_ERR = 13
-NAMESPACE_ERR = 14
-INVALID_ACCESS_ERR = 15
-VALIDATION_ERR = 16
-
-
-class DOMException(Exception):
- """Abstract base class for DOM exceptions.
- Exceptions with specific codes are specializations of this class."""
-
- def __init__(self, *args, **kw):
- if self.__class__ is DOMException:
- raise RuntimeError(
- "DOMException should not be instantiated directly")
- Exception.__init__(self, *args, **kw)
-
- def _get_code(self):
- return self.code
-
-
-class IndexSizeErr(DOMException):
- code = INDEX_SIZE_ERR
-
-class DomstringSizeErr(DOMException):
- code = DOMSTRING_SIZE_ERR
-
-class HierarchyRequestErr(DOMException):
- code = HIERARCHY_REQUEST_ERR
-
-class WrongDocumentErr(DOMException):
- code = WRONG_DOCUMENT_ERR
-
-class InvalidCharacterErr(DOMException):
- code = INVALID_CHARACTER_ERR
-
-class NoDataAllowedErr(DOMException):
- code = NO_DATA_ALLOWED_ERR
-
-class NoModificationAllowedErr(DOMException):
- code = NO_MODIFICATION_ALLOWED_ERR
-
-class NotFoundErr(DOMException):
- code = NOT_FOUND_ERR
-
-class NotSupportedErr(DOMException):
- code = NOT_SUPPORTED_ERR
-
-class InuseAttributeErr(DOMException):
- code = INUSE_ATTRIBUTE_ERR
-
-class InvalidStateErr(DOMException):
- code = INVALID_STATE_ERR
-
-class SyntaxErr(DOMException):
- code = SYNTAX_ERR
-
-class InvalidModificationErr(DOMException):
- code = INVALID_MODIFICATION_ERR
-
-class NamespaceErr(DOMException):
- code = NAMESPACE_ERR
-
-class InvalidAccessErr(DOMException):
- code = INVALID_ACCESS_ERR
-
-class ValidationErr(DOMException):
- code = VALIDATION_ERR
-
-class UserDataHandler:
- """Class giving the operation constants for UserDataHandler.handle()."""
-
- # Based on DOM Level 3 (WD 9 April 2002)
-
- NODE_CLONED = 1
- NODE_IMPORTED = 2
- NODE_DELETED = 3
- NODE_RENAMED = 4
-
-XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace";
-XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/";
-XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
-EMPTY_NAMESPACE = None
-EMPTY_PREFIX = None
-
-from domreg import getDOMImplementation,registerDOMImplementation
diff --git a/addon/globalPlugins/xml2/dom/domreg.py
b/addon/globalPlugins/xml2/dom/domreg.py
deleted file mode 100644
index ea8b7c9..0000000
--- a/addon/globalPlugins/xml2/dom/domreg.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""Registration facilities for DOM. This module should not be used
-directly. Instead, the functions getDOMImplementation and
-registerDOMImplementation should be imported from xml.dom."""
-
-from xml2.dom.minicompat import * # isinstance, StringTypes
-
-# This is a list of well-known implementations. Well-known names
-# should be published by posting to xml-sig@xxxxxxxxxx, and are
-# subsequently recorded in this file.
-
-well_known_implementations = {
- 'minidom':'xml.dom.minidom',
- '4DOM': 'xml.dom.DOMImplementation',
- }
-
-# DOM implementations not officially registered should register
-# themselves with their
-
-registered = {}
-
-def registerDOMImplementation(name, factory):
- """registerDOMImplementation(name, factory)
-
- Register the factory function with the name. The factory function
- should return an object which implements the DOMImplementation
- interface. The factory function can either return the same object,
- or a new one (e.g. if that implementation supports some
- customization)."""
-
- registered[name] = factory
-
-def _good_enough(dom, features):
- "_good_enough(dom, features) -> Return 1 if the dom offers the features"
- for f,v in features:
- if not dom.hasFeature(f,v):
- return 0
- return 1
-
-def getDOMImplementation(name = None, features = ()):
- """getDOMImplementation(name = None, features = ()) -> DOM implementation.
-
- Return a suitable DOM implementation. The name is either
- well-known, the module name of a DOM implementation, or None. If
- it is not None, imports the corresponding module and returns
- DOMImplementation object if the import succeeds.
-
- If name is not given, consider the available implementations to
- find one with the required feature set. If no implementation can
- be found, raise an ImportError. The features list must be a sequence
- of (feature, version) pairs which are passed to hasFeature."""
-
- import os
- creator = None
- mod = well_known_implementations.get(name)
- if mod:
- mod = __import__(mod, {}, {}, ['getDOMImplementation'])
- return mod.getDOMImplementation()
- elif name:
- return registered[name]()
- elif "PYTHON_DOM" in os.environ:
- return getDOMImplementation(name = os.environ["PYTHON_DOM"])
-
- # User did not specify a name, try implementations in arbitrary
- # order, returning the one that has the required features
- if isinstance(features, StringTypes):
- features = _parse_feature_string(features)
- for creator in registered.values():
- dom = creator()
- if _good_enough(dom, features):
- return dom
-
- for creator in well_known_implementations.keys():
- try:
- dom = getDOMImplementation(name = creator)
- except StandardError: # typically ImportError, or AttributeError
- continue
- if _good_enough(dom, features):
- return dom
-
- raise ImportError,"no suitable DOM implementation found"
-
-def _parse_feature_string(s):
- features = []
- parts = s.split()
- i = 0
- length = len(parts)
- while i < length:
- feature = parts[i]
- if feature[0] in "0123456789":
- raise ValueError, "bad feature name: %r" % (feature,)
- i = i + 1
- version = None
- if i < length:
- v = parts[i]
- if v[0] in "0123456789":
- i = i + 1
- version = v
- features.append((feature, version))
- return tuple(features)
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/nvdaaddonteam/readfeeds/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.