commit/readFeeds: norrumar: Initial dialog for managge feeds with guiHelper

  • From: commits-noreply@xxxxxxxxxxxxx
  • To: nvda-addons-commits@xxxxxxxxxxxxx
  • Date: Sun, 04 Dec 2016 11:47:12 -0000

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.

Other related posts:

  • » commit/readFeeds: norrumar: Initial dialog for managge feeds with guiHelper - commits-noreply