Last active
August 5, 2022 05:24
-
-
Save Hayao0819/ed70edac37ccff58c4a3bd8221deb6a0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
# Version 2, December 2004 | |
# | |
#:: License | |
# | |
# Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> | |
# | |
# Everyone is permitted to copy and distribute verbatim or modified | |
# copies of this license document, and changing it is allowed as long | |
# as the name is changed. | |
# | |
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE | |
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
# | |
# 0. You just DO WHAT THE FUCK YOU WANT TO. | |
# | |
#:: Dependencies | |
# - python3 | |
# - python-feedparser | |
# - python-wxpython | |
# | |
#:: Usage | |
# Run: python3 archnews.py | |
import wx; | |
import feedparser; | |
import sys; | |
import wx.html as html; | |
import os; | |
import urllib.request | |
Japanese=True; | |
Version = 0.1 | |
class RSSParseError(Exception): | |
pass | |
class ArchNews(): | |
RSSEnglish = "http://www.archlinux.org/feeds/news/"; | |
RSSJapaese = "https://www.archlinux.jp/feeds/news.xml"; | |
CurrentFeedURL=None | |
def __init__(self): | |
FeedURL="" | |
if Japanese: | |
FeedURL=self.RSSJapaese | |
else: | |
FeedURL=self.RSSEnglish | |
self.UpdateFeed(FeedURL) | |
def GetTitleList(self): | |
TitleList = []; | |
for entry in self.NewsList: | |
TitleList.append(entry.title); | |
return TitleList; | |
def GetDetailFromTitle(self,Title): | |
for entry in self.NewsList: | |
if entry.title == Title: | |
return entry.summary; | |
return "" | |
def UpdateFeed(self,url): | |
self.CurrentFeedURL=url | |
self.Feed = feedparser.parse(url) | |
self.NewsList=self.Feed.entries; | |
try: | |
self.Feed.status | |
except (NameError, AttributeError): | |
raise RSSParseError | |
class MainPanel(wx.Panel): | |
News=None # ArchNewsオブジェクト | |
CurrentHTML="" # ArchNewsから取得した現在のHTML | |
NewsListSizer=None # 左のニュース一覧 | |
NewsListBox=None # 左のニュース一覧のListBox | |
NewsDetailSizer=None # 右の詳細 | |
HTMLWindow=None # 右の詳細の中のHTMLビューアー | |
WrapSizer=None # 全体 | |
def __init__(self, parent): | |
try: | |
self.News = ArchNews(); | |
except RSSParseError: | |
self.CreateErrorWindow(); | |
sys.exit(1) | |
# パネル初期化 | |
wx.Panel.__init__(self, parent) | |
self.CreateWrapSizer() | |
self.CreateLeftNewsListSizer() | |
self.CreateRightNewsDetailSizer() | |
self.SetSizer(self.WrapSizer) | |
def CreateErrorWindow(self): | |
ErrorMsgBox = wx.MessageDialog(None, 'RSSの取得に失敗しました', 'RSSエラー') | |
ErrorMsgBox.ShowModal() | |
ErrorMsgBox.Destroy() | |
def CreateWrapSizer(self): | |
self.WrapSizer= wx.FlexGridSizer(rows=1, cols=2, gap=(10, 10)) | |
self.WrapSizer.AddGrowableCol(1) # News Detail を拡張可能にする | |
self.WrapSizer.AddGrowableRow(0) | |
return | |
def CreateLeftNewsListSizer(self): | |
self.NewsListSizer = wx.StaticBoxSizer(orient=wx.VERTICAL, parent=self, label="News List") | |
self.NewsListBox = wx.ListBox(self, -1, choices=self.News.GetTitleList()) | |
self.NewsListSizer.Add(self.NewsListBox, 1, wx.EXPAND) | |
self.Bind(wx.EVT_LISTBOX, self.NewsSelected, self.NewsListBox) | |
self.WrapSizer.Add(self.NewsListSizer, 1, wx.EXPAND) | |
return | |
# News Detail | |
def CreateRightNewsDetailSizer(self,html_text=""): | |
Sizer = wx.StaticBoxSizer(orient=wx.VERTICAL, parent=self, label="News Detail") | |
self.HTMLWindow = html.HtmlWindow(self,id=1); # HTMLWindowをNewsSelectedからアクセスできるようにclass全体の変数にした | |
Sizer.Add(self.HTMLWindow, 1, wx.EXPAND) | |
self.WrapSizer.Add(Sizer, 1, wx.EXPAND) | |
return | |
# ニュースが選択されたときに実行される関数 | |
def NewsSelected(self, event): | |
self.UpdateNewsDetail(event.GetString()) | |
#def SaveMenuHTML(self): | |
# print(self.CurrentHTML) | |
def UpdateNewsDetail(self,title): | |
self.CurrentHTML= self.News.GetDetailFromTitle(title); | |
if self.CurrentHTML == "": | |
self.CurrentHTML = "<h1>No News Selected</h1>"; | |
if self.HTMLWindow == None: #self.HTMLWindowがCreateRightNewsDetailSizerによって定義される前にこの関数が実行されると「None」が代入されているので関数を終了する | |
return | |
self.HTMLWindow.SetPage(self.CurrentHTML); | |
def UpdateNewsListBox(self, url="",file=None): | |
if file != None: | |
self.News.UpdateFeed(f"file://{file}") # ArchNewsオブジェクトの情報をファイルから更新する | |
else: | |
self.News.UpdateFeed(url) # ArchNewsオブジェクトの情報を更新する | |
self.NewsListBox.SetItems(self.News.GetTitleList()) # ニュースリストを更新する | |
self.NewsListBox.SetSelection(0) # 先頭を選択状態にする | |
self.UpdateNewsDetail(self.NewsListBox.GetString(0)) # 先頭のニュースのタイトルを取得して右のHTMLを更新する | |
def SwitchLanguage(self): | |
global Japanese | |
if Japanese: | |
self.UpdateNewsListBox(self.News.RSSEnglish) | |
Japanese = False | |
else: | |
self.UpdateNewsListBox(self.News.RSSJapaese) | |
Japanese=True; | |
def GetCurrentFeedURL(self): | |
return self.News.CurrentFeedURL | |
class OpenDialog(wx.Dialog): | |
Path=None | |
BrowseSizer=None | |
ButtonSizer=None | |
WrapSizer=None | |
InputBox=None | |
BrowseButton=None | |
OKButton=None | |
CancelButton=None | |
def __init__(self): | |
wx.Dialog.__init__(self, None, -1, 'Title', size=(500,120)) | |
# Sizerを作成 | |
self.WrapSizer = wx.BoxSizer(wx.VERTICAL) | |
self.BrowseSizer = wx.BoxSizer(wx.HORIZONTAL) | |
self.ButtonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
# InputBoxを作成 | |
self.BrowseSizer.Add(wx.StaticText(self, -1, 'File Name:'), 0, wx.ALIGN_CENTER_VERTICAL) #ラベル | |
self.InputBox = wx.TextCtrl(self, -1, '') | |
self.BrowseSizer.Add(self.InputBox, 1, wx.ALIGN_CENTER_VERTICAL) | |
# 参照ボタンを作成 | |
self.BrowseButton = wx.Button(self, -1, '参照') | |
self.Bind(wx.EVT_BUTTON, self.OnBrowse, self.BrowseButton) | |
self.BrowseSizer.Add(self.BrowseButton, 0, wx.ALIGN_CENTER_VERTICAL) | |
# OKボタンを作成 | |
self.OKButton = wx.Button(self, wx.ID_OK, 'OK') | |
self.ButtonSizer.Add(self.OKButton, 0, wx.CENTER) | |
self.Bind(wx.EVT_BUTTON, self.OnOK, self.OKButton) | |
# Cancelボタンを作成 | |
self.CancelButton = wx.Button(self, wx.ID_CANCEL, 'Cancel') | |
self.ButtonSizer.Add(self.CancelButton, 0, wx.CENTER ) | |
self.Bind(wx.EVT_BUTTON, self.OnCancel, self.CancelButton) | |
# Sizerを設定 | |
self.WrapSizer.Add(self.BrowseSizer, 1, wx.EXPAND) | |
self.WrapSizer.Add(self.ButtonSizer, 0, wx.EXPAND) | |
self.SetSizer(self.WrapSizer) | |
def OnBrowse(self, event): | |
BrowseDialog = wx.FileDialog(self, 'RSSファイルを指定してください',wildcard='RSS files (*.xml)|*.xml|All files(*)|*',style=wx.FD_OPEN) | |
if BrowseDialog.ShowModal() == wx.ID_OK: | |
self.Path = BrowseDialog.GetPath() | |
self.InputBox.SetValue(self.Path) | |
BrowseDialog.Destroy() | |
def OnOK(self, event): | |
self.EndModal(wx.ID_OK) | |
return | |
def OnCancel(self, event): | |
self.EndModal(wx.ID_CANCEL) | |
return | |
class MainWindowFrame(wx.Frame): | |
def __init__(self): | |
super().__init__(None, id=-1, title='wxPython') | |
self.SetSize(900, 500) | |
self.StatusBar = self.CreateStatusBar() | |
self.SetMenuBar(self.CreateMenuBar()) | |
self.SetStatusText("ようこそ") | |
self.Panel = MainPanel(self) | |
self.Show() | |
def Menu_File_SaveHTML(self,event): | |
PathSelectDialog = wx.FileDialog(self, '保存先を選択してください', defaultDir=os.environ["HOME"], defaultFile="", wildcard="HTMLファイル(*.html)|*.html", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) | |
if PathSelectDialog.ShowModal() == wx.ID_OK: | |
Path = PathSelectDialog.GetPath() | |
# 拡張子を追加 | |
if not Path.endswith(".html"): | |
Path += ".html" | |
File = open(Path, "w") | |
File.write(self.Panel.CurrentHTML) | |
File.close() | |
return | |
def Menu_File_SaveRSS(self, event): | |
PathSelectDialog = wx.FileDialog(self, '保存先を選択してください', defaultDir=os.environ["HOME"], defaultFile="", wildcard="XMLファイル(*.xml)|*.xml", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) | |
if PathSelectDialog.ShowModal() == wx.ID_OK: | |
Path = PathSelectDialog.GetPath() | |
# 拡張子を追加 | |
if not Path.endswith(".xml"): | |
Path += ".xml" | |
urllib.request.urlretrieve(self.Panel.GetCurrentFeedURL(), Path) | |
return | |
# Todo: ファイルパスを入力できるようなテキストボックスも一緒に表示する | |
def Menu_File_Open(self,event): | |
#def BrowseRSSFile(self): | |
# with wx.FileDialog(self, 'RSSファイルを指定してください',wildcard='RSS files (*.xml)|*.xml|All files(*)|*',style=wx.FD_OPEN) as dialog: | |
# # Todo: 例外処理をちゃんと書く | |
# if dialog.ShowModal() == wx.ID_OK: | |
# return dialog.GetPaths()[0] | |
#self.Panel.UpdateNewsListBox(file=BrowseRSSFile(self)) | |
Dialog = OpenDialog() | |
if Dialog.ShowModal() == wx.ID_OK: | |
self.Panel.UpdateNewsListBox(file=Dialog.Path) | |
return | |
# Todo: 例外処理をちゃんと書く | |
# Todo: Menu_File_Openと一緒にする | |
def Menu_File_URL(self,event): | |
URLDialog=wx.TextEntryDialog(None,"Copy and Paste below","heading","This is my text") | |
if URLDialog.ShowModal() == wx.ID_OK: | |
self.Panel.UpdateNewsListBox(URLDialog.GetValue()) | |
return | |
def Menu_File_Switch(self,event): | |
self.SetStatusText("言語を切り替えています...") | |
self.Panel.SwitchLanguage() | |
self.SetStatusText("完了") | |
return | |
def Menu_File_Exit(self,event): | |
sys.exit(0) | |
def Menu_Help_Version(self,event): | |
# あとでウィジェットを配置したちゃんとしたダイアログで書き直す | |
VersionDialogBox = wx.MessageDialog(None, f'Version: {Version}\nCreated by Hayao Yamada', 'バージョン情報') | |
VersionDialogBox.ShowModal() | |
VersionDialogBox.Destroy() | |
def CreateMenuBar(self): | |
MenuBar = wx.MenuBar() | |
#-- ファイル --# | |
# メニュー作成 | |
FileMenu = wx.Menu() | |
# 項目作成 | |
FileMenuSaveHTML = FileMenu.Append(-1, "HTMLを保存", "ニュースをテキストファイルに保存します\tCtrl+S") | |
self.Bind(wx.EVT_MENU, self.Menu_File_SaveHTML, FileMenuSaveHTML) | |
FileMenuSaveRSS = FileMenu.Append(-1, "RSSを保存", "現在のRSSを保存します\tCtrl+X") | |
self.Bind(wx.EVT_MENU, self.Menu_File_SaveRSS, FileMenuSaveRSS) | |
FileMenuOpen = FileMenu.Append(-1, "開く", "RSSファイルを開きます\tCtrl+O") | |
self.Bind(wx.EVT_MENU, self.Menu_File_Open, FileMenuOpen) | |
FileMenuSwitch = FileMenu.Append(-1, "言語切り替え", "日本語と英語でニュースの言語を切り替えます") | |
self.Bind(wx.EVT_MENU, self.Menu_File_Switch, FileMenuSwitch) | |
FileMenuExit = FileMenu.Append(-1, "終了", "アプリケーションを終了します\tCtrl+Q") | |
self.Bind(wx.EVT_MENU, self.Menu_File_Exit, FileMenuExit) | |
# メニューバーに「ファイル」を追加 | |
MenuBar.Append(FileMenu, "ファイル") | |
# ヘルプ | |
HelpMenu = wx.Menu() | |
#HelpMenu.Append(-1, "使い方", "オンラインで使い方を表示します\tCtrl+U") | |
#HelpMenu.Append(-1, "公式サイト", "Fascode Networkの公式サイトを開きます") | |
HelpMenuVersion = HelpMenu.Append(-1, "バージョン", 'バージョン情報を表示します\tCtrl+V') | |
self.Bind(wx.EVT_MENU, self.Menu_Help_Version, HelpMenuVersion) | |
MenuBar.Append(HelpMenu, "ヘルプ") | |
return MenuBar | |
if __name__ == '__main__': | |
App = wx.App() | |
Frame=MainWindowFrame() | |
App.SetTopWindow(Frame) | |
App.MainLoop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment