1 new commit in readFeeds:
https://bitbucket.org/nvdaaddonteam/readfeeds/commits/1b3a29ea0f7c/
Changeset: 1b3a29ea0f7c
Branch: enhancedgui
User: norrumar
Date: 2016-12-04 11:44:47+00:00
Summary: Initial dialog for managge feeds with guiHelper
Affected #: 2 files
diff --git a/addon/globalPlugins/readFeeds.py b/addon/globalPlugins/readFeeds.py
index e3a0542..9950b84 100644
--- a/addon/globalPlugins/readFeeds.py
+++ b/addon/globalPlugins/readFeeds.py
@@ -22,6 +22,7 @@ import urllib
import scriptHandler
import api
import gui
+from gui import guiHelper
import wx
import ui
from logHandler import log
@@ -32,27 +33,170 @@ del sys.path[-1]
addonHandler.initTranslation()
-# Default address, used when addressFile cannot be read
-address = 'http://rss.slashdot.org/Slashdot/slashdot'
-
-# The root of the addon folder
-_addonDir = os.path.join(os.path.dirname(__file__), "..").decode("mbcs")
-_curAddon = addonHandler.Addon(_addonDir)
-_addonSummary = _curAddon.manifest['summary']
-_savePath = os.path.join(_addonDir, "globalPlugins", "personalFeeds")
-# File containing the default feed address when the add-on starts
-addressFile = os.path.join(_savePath, "addressFile.txt")
-configPath = globalVars.appArgs.configPath
-
-try:
- f = open(addressFile, "r")
- address = f.read()
- f.close()
-except IOError:
- pass
+### 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.
-cannotReport = _("Unable to refresh feed. Check your Internet conectivity or
that the specified feed address is correct.")
+CAN_NOT_REPORT = _("Unable to refresh feed. Check your Internet conectivity or
that the specified feed address is correct.")
+
+### 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)
+ names = [os.path.splitext(filename)[0] for filename in
os.listdir(FEEDS_PATH)]
+ self.feedsList = wx.ListBox(self,
+ choices=names)
+ 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.feedsList.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 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
+
+ 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: Caption of a dialog.
+ _("Open an article"),
+ # Translators: Title of a dialog.
+ _("List of feeds (%d)" % 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 adress 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):
+ pass
+
+ 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):
@@ -130,54 +274,23 @@ class Feed(object):
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
- scriptCategory = unicode(_addonSummary)
+ scriptCategory = unicode(ADDON_SUMMARY)
def __init__(self):
super(globalPluginHandler.GlobalPlugin, self).__init__()
- self.menu = gui.mainFrame.sysTrayIcon.menu
+ 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.newsListItem = self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("Article &list..."),
- # Translators: the tooltip for a menu item.
- _("View article list"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onList,
self.newsListItem)
- self.setAddressItem = self.readFeedsMenu.Append(wx.ID_ANY,
+ self.feedsListItem = self.readFeedsMenu.Append(wx.ID_ANY,
# Translators: the name of a menu item.
- _("&Temporary feed address..."),
+ _("&Feeds..."),
# Translators: the tooltip for a menu item.
- _("View or choose current feed address"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onSetAddress,
self.setAddressItem)
- self.setAddressFileItem = self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("L&oad feed address from file..."),
- # Translators: the tooltip for a menu item.
- _("Select file which contains feed address."))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU,
self.onSetAddressFile, self.setAddressFileItem)
- self.saveAddressItem = self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("Save current feed address to file..."),
- # Translators: the tooltip for a menu item.
- _("Save current feed address to file"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onSaveAddress,
self.saveAddressItem)
- self.readFirstItem = self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("R&efresh current feed"),
- # Translators: the tooltip for a menu item.
- _("Checks for new articles for the current feed"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU,
self.onReadFirstFeed, self.readFirstItem)
- self.ReadFeedsFileManagerItem =
self.readFeedsMenu.Append(wx.ID_ANY,
- # Translators: the name of a menu item.
- _("&ReadFeeds file manager..."),
- # Translators: the tooltip for a menu item.
- _("Opens the ReadFeedsFileManager dialog"))
- gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU,
self.onReadFeedsFileManager, self.ReadFeedsFileManagerItem)
- self._feed = None
+ _("View and manage feeds"))
+ gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onList,
self.feedsListItem)
def terminate(self):
try:
@@ -186,38 +299,10 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
pass
def onList(self, evt):
- try:
- self._feed = Feed(address)
- except:
- wx.CallAfter(gui.messageBox,
- cannotReport,
- # Translators: the title of an error dialog.
- _("Refresh Error"),
- wx.OK|wx.ICON_ERROR)
- return
- articleTitles = [self._feed.getArticleTitle(index) for index in
range(0, self._feed.getNumberOfArticles())]
- dlg = wx.SingleChoiceDialog(gui.mainFrame,
- # Translators: the label of a single choice dialog.
- _("Open web page of selected article."),
- u"{title}
({itemNumber})".format(title=self._feed.getFeedName(),
itemNumber=self._feed.getNumberOfArticles()), choices=articleTitles)
- dlg.SetSelection(0)
gui.mainFrame.prePopup()
- try:
- result = dlg.ShowModal()
- except AttributeError:
- pass
+ d = FeedsDialog(gui.mainFrame)
+ d.Show()
gui.mainFrame.postPopup()
- if result == wx.ID_OK:
-
os.startfile(self._feed.getArticleLink(dlg.GetSelection()))
-
- def onSetAddress(self, evt):
- self.setAddressDialog()
-
- def onSetAddressFile(self, evt):
- self.setAddressFileDialog()
-
- def onSaveAddress(self, evt):
- self.saveAddressDialog()
def onReadFirstFeed(self, evt):
try:
@@ -305,17 +390,6 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
# Translators: message presented in input mode.
script_setAddress.__doc__ = _("Opens a dialog for entering a feed
address.")
- def setAddressFileDialog(self):
- d =wx.FileDialog(gui.mainFrame,
- # Translators: the label of a file dialog.
- _("Select feed address from file"),
- _savePath, "addressFile.txt", _("Text files (*.txt) |*.txt"),
wx.FD_OPEN)
- def callback(result):
- if result == wx.ID_OK:
- # Make sure this happens after focus returns to
the document.
- wx.CallLater(100, self.doSetAddressFile,
d.GetPath())
- gui.runScriptModalDialog(d, callback)
-
def doSetAddressFile(self, file):
if not file:
return
@@ -337,30 +411,6 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
# Translators: message presented in input mode.
script_setAddressFile.__doc__ = _("Opens a dialog for selecting a file
containing a feed address.")
- def saveAddressDialog(self):
- d =wx.FileDialog(gui.mainFrame,
- # Translators: the label of a file dialog.
- _("Save current feed address to file"),
- _savePath, "addressFile.txt", _("Text files (*.txt) | *.txt"),
wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
- def callback(result):
- if result == wx.ID_OK:
- # Make sure this happens after focus returns to
the document.
- wx.CallLater(200, self.doSaveAddress,
d.GetPath())
- gui.runScriptModalDialog(d, callback)
-
- def doSaveAddress(self, file):
- if not file:
- return
- try:
- f = open (file, "w")
- f.write(address)
- f.close()
- # Translators: message presented when the address of a
feed has been saved.
- ui.message(_("Saved %s") % address)
- except IOError:
- # Translators: Message presented when the feed address
cannot be saved.
- ui.message(_("Feed address can not be saved"))
-
def script_saveAddress(self, gesture):
self.onSaveAddress(None)
# Translators: message presented in input mode.
diff --git a/addon/installTasks.py b/addon/installTasks.py
deleted file mode 100644
index a7ca4f2..0000000
--- a/addon/installTasks.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- coding: UTF-8 -*-
-#Copyright (C) 2013-2016 Noelia Ruiz Martínez, other contributors
-# Released under GPL2import addonHandler
-
-import globalVars
-import os
-import shutil
-import glob
-import gui
-import wx
-
-basePath = os.path.dirname(__file__).decode("mbcs")
-savePath = os.path.join(basePath, "globalPlugins", "personalFeeds")
-
-addonHandler.initTranslation()
-
-def onInstall():
- for addon in addonHandler.getAvailableAddons():
- if addon.manifest['name'] == "ReadFeeds":
- if gui.messageBox(
- # Translators: the label of a message box
dialog.
- _("You have installed the ReadFeeds add-on,
probably an old and incompatible version with this one. Do you want to
uninstall the old version?"),
- # Translators: the title of a message box
dialog.
- _("Uninstall incompatible add-on"),
- wx.YES|wx.NO|wx.ICON_WARNING)==wx.YES:
- addon.requestRemove()
- break
- configPath = globalVars.appArgs.configPath
- addonPath = [os.path.join(configPath, "RSS"), os.path.join(configPath,
"personalFeeds")]
- for path in addonPath:
- if not os.path.isdir(path):
- continue
- pathFiles = os.listdir(path)
- validFiles = glob.glob(path+"\\*.txt")
- if len(pathFiles) != len(validFiles):
- return
- if gui.messageBox(
- # Translators: the label of a message box dialog.
- _("Your configuration folder for NVDA contains files that seem
to be derived from a previous version of this add-on. Do you want to update
it?"),
- # Translators: the title of a message box dialog.
- _("Install or update add-on"),
- wx.YES|wx.NO|wx.ICON_WARNING)==wx.YES:
- for file in validFiles:
- try:
- shutil.copy(file, savePath)
- except IOError:
- pass
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.