1 Star 0 Fork 5

cuglujun/debreateforuos

forked from 鱆鱼尾/debreateforuos 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
main.py 19.60 KB
一键复制 编辑 原始数据 按行查看 历史
鱆鱼尾 提交于 2021-11-28 09:54 . 基本完成目标
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
# -*- coding: utf-8 -*-
## \page main.py Main Window Interface
#
# Defines interface of the main window.
# MIT licensing
# See: docs/LICENSE.txt
import os, shutil, subprocess, urllib, webbrowser, wx, wx.html
from urllib2 import HTTPError
from urllib2 import URLError
from dbr.config import GetDefaultConfigValue
from dbr.config import WriteConfig
from dbr.event import EVT_CHANGE_PAGE
from dbr.event import EVT_TIMER_STOP
from dbr.functions import GetCurrentVersion
from dbr.functions import UsingDevelopmentVersion
from dbr.help import HelpDialog
from dbr.icon import Icon
from dbr.language import GT
from dbr.log import DebugEnabled
from dbr.log import Logger
from dbr.timer import DebreateTimer
from fileio.fileio import ReadFile
from fileio.fileio import WriteFile
from globals.application import APP_homepage
from globals.application import APP_project_gh
from globals.application import APP_project_sf
from globals.application import AUTHOR_email
from globals.application import AUTHOR_name
from globals.application import VERSION_string
from globals.application import VERSION_tuple
from globals.bitmaps import LOGO
from globals.execute import GetExecutable
from globals.ident import menuid
from globals.ident import pgid
from globals.moduleaccess import ModuleAccessCtrl
from globals.paths import ConcatPaths
from globals.paths import PATH_app
from globals.paths import PATH_cache
from globals.paths import PATH_local
from globals.project import PROJECT_ext
from globals.project import PROJECT_txt
from globals.strings import GS
from globals.threads import Thread
from startup.tests import GetTestList
from ui.about import AboutDialog
from ui.dialog import ConfirmationDialog
from ui.dialog import DetailedMessageDialog
from ui.dialog import ShowErrorDialog
from ui.distcache import DistNamesCacheDialog
from ui.layout import BoxSizer
from ui.menu import createMenuBar
from ui.progress import ProgressDialog
from ui.quickbuild import QuickBuild
from ui.statusbar import StatusBar #状态栏
from wiz.helper import GetPage
from wiz.pginit import Page as PageInit
from wiz.wizard import Wizard
default_title = GT(u'DebreateForUos-UOS软件打包工具')
## The main window interface
class MainWindow(wx.Frame, ModuleAccessCtrl):
## Constructor
#
# \param pos
# <b><i>Integer tuple</i></b> or <b><i>wx.Point</i></b> instance indicating the screen position of the window
# \param size
# <b><i>Integer tuple</i></b> or <b><i>wx.Size</i></b> instance indicating the dimensions of the window
def __init__(self, pos, size):
wx.Frame.__init__(self, None, wx.ID_ANY, default_title, pos, size)
ModuleAccessCtrl.__init__(self, __name__)
self.timer = DebreateTimer(self)
# placeholder for progress dialog
self.progress = None
self.Bind(wx.EVT_TIMER, self.__onTimerEvent)
self.Bind(EVT_TIMER_STOP, self.__onTimerStop)
# Make sure that this frame is set as the top window
if not wx.GetApp().GetTopWindow() == self:
Logger.Debug(__name__, GT(u'Setting MainWindow instance as top window'))
wx.GetApp().SetTopWindow(self)
if DebugEnabled():
self.SetTitle(u'{} ({})'.format(default_title, GT(u'debugging')))
self.SetMinSize(wx.Size(640, 400))
# ----- Set Titlebar Icon
self.SetIcon(Icon(LOGO))
# *** Status Bar *** #
StatusBar(self)
# *** Menus *** #
createMenuBar(self)
self.Wizard = Wizard(self)
# *** Current Project Status *** #
self.LoadedProject = None
self.ProjectDirty = False
# *** Event Handling *** #
wx.EVT_MENU(self, menuid.NEW, self.OnProjectNew)
wx.EVT_MENU(self, menuid.OPEN, self.OnProjectOpen)
wx.EVT_MENU(self, menuid.SAVE, self.OnProjectSave)
wx.EVT_MENU(self, menuid.SAVEAS, self.OnProjectSave)
wx.EVT_MENU(self, menuid.QBUILD, self.OnQuickBuild)
wx.EVT_MENU(self, menuid.EXIT, self.OnQuit)
wx.EVT_MENU(self, menuid.TOOLTIPS, self.OnToggleToolTips)
wx.EVT_MENU(self, menuid.DIST, self.OnUpdateDistNamesCache)
wx.EVT_MENU(self, menuid.UPDATE, self.OnCheckUpdate)
wx.EVT_MENU(self, menuid.HELP, self.OnHelp)
wx.EVT_MENU(self, menuid.ABOUT, self.OnAbout)
self.Bind(EVT_CHANGE_PAGE, self.OnWizardBtnPage)
# Custom close event shows a dialog box to confirm quit
wx.EVT_CLOSE(self, self.OnQuit)
# *** Layout *** #
lyt_main = BoxSizer(wx.VERTICAL)
lyt_main.Add(self.Wizard, 1, wx.EXPAND)
self.SetAutoLayout(True)
self.SetSizer(lyt_main)
self.Layout()
## Retrieves menu by ID
def GetMenu(self, menuId):
return self.GetMenuBar().GetMenuById(menuId)
## Retrieves the Wizard instance
#
# \return
# wiz.wizard.Wizard
def GetWizard(self):
return self.Wizard
## Sets the pages in the wiz.wizard.Wizard instance
def InitWizard(self):
self.Wizard.AddPage(PageInit(self.Wizard))
self.Wizard.SetModeBin(0) #初始化添加页面
## TODO: Doxygen
def IsNewProject(self):
title = self.GetTitle()
if title == default_title:
return True
else:
return False
## TODO: Doxygen
def IsSaved(self):
title = self.GetTitle()
if title[-1] == u'*':
return False
else:
return True
## Opens a dialog box with information about the program
def OnAbout(self, event=None): #@UnusedVariable
about = AboutDialog(self)
about.SetGraphic(LOGO)
about.SetVersion(VERSION_string)
about.SetDescription(GT(u'基于UOS系统的打包软件'))
about.SetAuthor(AUTHOR_name)
about.SetWebsites((
(GT(u'Homepage'), APP_homepage),
#(GT(u'Gitee Project'), APP_project_gh),
#(GT(u'Sourceforge Project'), APP_project_sf),
))
about.AddJobs(
AUTHOR_name,
(
GT(u'开发'),
GT(u'打包'),
u'{} (cn)'.format(GT(u'翻译')),
),
AUTHOR_email
)
about.AddJobs(
GT(u'Jordan Irwin'),
(
GT(u'开发'),
GT(u'打包'),
u'{} (es, it)'.format(GT(u'翻译')),
),
)
about.AddJobs(
u'Hugo Posnic',
(
GT(u'Code Contributor'),
GT(u'Website Designer & Author'),
),
)
about.AddJob(u'Lander Usategui San Juan', GT(u'General Contributor'), u'[email protected]')
about.AddTranslator(u'Karim Oulad Chalha', u'[email protected]', u'ar', )
about.AddTranslator(u'Philippe Dalet', u'[email protected]', u'fr')
about.AddTranslator(u'Zhmurkov Sergey', u'[email protected]', u'ru')
about.AddJob(u'Benji Park', GT(u'Button Base Image Designer'))
about.SetChangelog()
about.SetLicense()
about.ShowModal()
about.Destroy()
## Checks for new release availability
def OnCheckUpdate(self, event=None): #@UnusedVariable
update_test = u'update-fail' in GetTestList()
if UsingDevelopmentVersion() and not update_test:
DetailedMessageDialog(self, GT(u'更新'),
text=GT(u'请使用商店或者到gitee网站上寻找新的版本')).ShowModal()
return
wx.SafeYield()
if update_test:
# Set a bad url to force error
current = GetCurrentVersion(u'http://dummyurl.blah/')
else:
current = GetCurrentVersion()
Logger.Debug(__name__, GT(u'URL request result: {}').format(current))
error_remote = GT(u'尝试访问远端网站发生错误')
if isinstance(current, (URLError, HTTPError)):
current = GS(current)
ShowErrorDialog(error_remote, current)
elif isinstance(current, tuple) and current > VERSION_tuple:
current = u'{}.{}.{}'.format(current[0], current[1], current[2])
l1 = GT(u'版本 {} 可用!').format(current)
l2 = GT(u'您是要访问 DebreateForUos的网站吗?')
if ConfirmationDialog(self, GT(u'更新'), u'{}\n\n{}'.format(l1, l2)).Confirmed():
wx.LaunchDefaultBrowser(APP_homepage)
elif isinstance(current, (unicode, str)):
ShowErrorDialog(error_remote, current)
else:
DetailedMessageDialog(self, GT(u'DebreateForUos'), text=GT(u'DebreateForUos版本已经是最新的了!')).ShowModal()
def __cacheManualFiles(self, args):
url_manual = args[0]
manual_cache = args[1]
manual_index = args[2]
main_dir = os.getcwd()
os.chdir(manual_cache)
try:
subprocess.Popen([u'wget', u'-rkp', u'-nd', u'-np', u'-H', u'-D',
u'debreate.wordpress.com,antumdeluge.github.io', url_manual]).communicate()
# FIXME: use Python commands
subprocess.Popen([u'sed', u'-i', u'-e', u's|<a.*>||g', u'-e', u's|</a>||g', manual_index]).communicate()
except:
# FIXME: show error message
pass
os.chdir(main_dir)
self.timer.Stop()
## Calls Pulse method on progress dialog when timer event occurs
def __onTimerEvent(self, event=None):
if self.progress:
self.progress.Pulse()
def __onTimerStop(self, event=None):
if self.progress:
self.progress.EndModal(0)
self.progress = None
if not self.IsEnabled():
self.Enable()
return not self.progress
## Action to take when 'Help' is selected from the help menu
#
# Opens a help dialog if using 'alpha' test. Otherwise, opens
# PDF usage document. If openening usage document fails, attempts
# to open web browser in remote usage page.
# TODO: Use dialog as main method
def OnHelp(self, event=None): #@UnusedVariable
if u'alpha' in GetTestList():
HelpDialog(self).ShowModal()
else:
# FIXME: files should be re-cached when Debreate upgraded to new version
# TODO: trim unneeded text
cached = False
manual_cache = ConcatPaths(PATH_cache, u'manual')
manual_index = ConcatPaths(manual_cache, u'index.html')
if not os.path.isdir(manual_cache):
os.makedirs(manual_cache)
elif os.path.isfile(manual_index):
cached = True
url_manual = u'https://debreate.wordpress.com/manual/'
# NOTE: use urllib.request.urlopen for Python 3
manual_data = urllib.urlopen(url_manual)
url_state = manual_data.getcode()
if url_state == 200:
# cache files
if not cached:
self.progress = ProgressDialog(self, message=GT(u'Caching manual files'),
style=wx.PD_APP_MODAL|wx.PD_AUTO_HIDE)
self.Disable()
self.timer.Start(100)
Thread(self.__cacheManualFiles, (url_manual, manual_cache, manual_index,)).Start()
self.progress.ShowModal()
manual_dialog = wx.Dialog(self, title=u'Debreate 手册', size=(800,500), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
manual = wx.html.HtmlWindow(manual_dialog)
wx.Yield()
if manual.LoadFile(manual_index):
manual_dialog.CenterOnParent()
manual_dialog.ShowModal()
else:
wx.Yield()
webbrowser.open(url_manual)
manual_dialog.Destroy()
else:
# open local document
wx.Yield()
subprocess.call([u'xdg-open', u'{}/docs/usage.pdf'.format(PATH_app)])
## Opens the logs directory in the system's default file manager
def OnLogDirOpen(self, event=None): #@UnusedVariable
Logger.Debug(__name__, GT(u'Opening log directory ...'))
subprocess.check_output([GetExecutable(u'xdg-open'), u'{}/logs'.format(PATH_local)], stderr=subprocess.STDOUT)
## Changes wizard page from menu
def OnMenuChangePage(self, event=None):
if isinstance(event, int):
page_id = event
else:
page_id = event.GetId()
self.Wizard.ShowPage(page_id)
if page_id ==pgid.FILES or page_id == pgid.ICONS:#file页面,刷新选择项目
self.Wizard.RenewDest()
## TODO: Doxygen
def OnProjectNew(self, event=None): #@UnusedVariable
self.ResetPages()
## TODO: Doxygen
def OnProjectOpen(self, event=None): #@UnusedVariable
projects_filter = u'|*.{};*.{}'.format(PROJECT_ext, PROJECT_txt)
d = GT(u'DebreateForUos project files')
dia = wx.FileDialog(self, GT(u'打开DebreateForUos工程'), os.getcwd(), u'',
u'{}{}'.format(d, projects_filter), wx.FD_CHANGE_DIR)
if dia.ShowModal() != wx.ID_OK:
return
# Get the path and set the saved project
project = dia.GetPath()
filename = os.path.basename(project)
if self.OpenProject(filename):
# Only set project open in memory if loaded completely
self.LoadedProject = project
else:
self.LoadedProject = None
## TODO: Doxygen
def OnProjectSave(self, event=None):
event_id = event.GetId()
def SaveIt(path):
# Gather data from different pages
data = (
GetPage(pgid.CONTROL).GetSaveData(),
GetPage(pgid.INFO).GetSaveData(),
GetPage(pgid.ICONS).GetSaveData(),
GetPage(pgid.FILES).GetSaveData(),
GetPage(pgid.SCRIPTS).GetSaveData(),
GetPage(pgid.CHANGELOG).GetSaveData(),
GetPage(pgid.COPYRIGHT).GetSaveData(),
GetPage(pgid.MENU).GetSaveData(),
GetPage(pgid.BUILD).GetSaveData(),
)
# Create a backup of the project
overwrite = False
if os.path.isfile(path):
backup = u'{}.backup'.format(path)
shutil.copy(path, backup)
overwrite = True
# This try statement can be removed when unicode support is enabled
try:
WriteFile(path, u'[DEBREATEFORUOS-{}]\n{}'.format(VERSION_string, u'\n'.join(data)))
if overwrite:
os.remove(backup)
except UnicodeEncodeError:
detail1 = GT(u'不幸的是DebreateForUos已经不支持unicode.')
detail2 = GT(u'从你的工程里移除掉任何非ASCII字符.')
ShowErrorDialog(GT(u'保存失败'), u'{}\n{}'.format(detail1, detail2), title=GT(u'Unicode Error'))
if overwrite:
os.remove(path)
# Restore project backup
shutil.move(backup, path)
def OnSaveAs():
dbp = u'|*.dbp'
d = GT(u'DebreateForUos project files')
dia = wx.FileDialog(self, GT(u'保存Debreate工程'), os.getcwd(), u'', u'{}{}'.format(d, dbp),
wx.FD_SAVE|wx.FD_CHANGE_DIR|wx.FD_OVERWRITE_PROMPT)
if dia.ShowModal() == wx.ID_OK:
filename = dia.GetFilename()
if filename.split(u'.')[-1] == u'dbp':
filename = u'.'.join(filename.split(u'.')[:-1])
self.LoadedProject = u'{}/{}.dbp'.format(os.path.split(dia.GetPath())[0], filename)
SaveIt(self.LoadedProject)
if event_id == wx.ID_SAVE:
# Define what to do if save is pressed
# If project already exists, don't show dialog
if not self.IsSaved() or not self.LoadedProject or not os.path.isfile(self.LoadedProject):
OnSaveAs()
else:
SaveIt(self.LoadedProject)
else:
# If save as is press, show the save dialog
OnSaveAs()
## TODO: Doxygen
def OnQuickBuild(self, event=None): #@UnusedVariable
QB = QuickBuild(self)
QB.ShowModal()
QB.Destroy()
## Shows a dialog to confirm quit and write window settings to config file
def OnQuit(self, event=None): #@UnusedVariable
if ConfirmationDialog(self, GT(u'退出?'),
text=GT(u'你将会失去所有未保存的信息')).ShowModal() in (wx.ID_OK, wx.OK):
maximized = self.IsMaximized()
WriteConfig(u'maximize', maximized)
if maximized:
WriteConfig(u'position', GetDefaultConfigValue(u'position'))
WriteConfig(u'size', GetDefaultConfigValue(u'size'))
WriteConfig(u'center', True)
else:
WriteConfig(u'position', self.GetPositionTuple())
WriteConfig(u'size', self.GetSizeTuple())
WriteConfig(u'center', False)
WriteConfig(u'workingdir', os.getcwd())
self.Destroy()
## TODO: Doxygen
def OnToggleTheme(self, event=None): #@UnusedVariable
self.ToggleTheme(self)
## Shows or hides tooltips
def OnToggleToolTips(self, event=None): #@UnusedVariable
enabled = self.opt_tooltips.IsChecked()
wx.ToolTip.Enable(enabled)
WriteConfig(u'tooltips', enabled)
## Opens a dialog for creating/updating list of distribution names cache file
def OnUpdateDistNamesCache(self, event=None): #@UnusedVariable
DistNamesCacheDialog().ShowModal()
## Updates the page menu to reflect current page
def OnWizardBtnPage(self, event=None): #@UnusedVariable
ID = self.Wizard.GetCurrentPageId()
Logger.Debug(__name__, GT(u'Event: EVT_CHANGE_PAGE, Page ID: {}').format(ID))
menu_page = self.GetMenu(menuid.PAGE)
if not menu_page.IsChecked(ID):
menu_page.Check(ID, True)
## Deletes cache directory located at ~/.local/share/debreate/cache
def OnClearCache(self, event=None):
if os.path.isdir(PATH_cache):
shutil.rmtree(PATH_cache)
## Opens web links from the help menu
def OpenPolicyManual(self, event=None):
if isinstance(event, wx.CommandEvent):
event_id = event.GetId()
elif isinstance(event, int):
event_id = event
else:
Logger.Error(__name__,
u'Cannot open policy manual link with object type {}'.format(type(event)))
return
url = self.menu_policy.GetHelpString(event_id)
webbrowser.open(url)
## Retrieves filename of loaded project
def ProjectGetLoaded(self):
return self.LoadedProject
## Tests project type & calls correct method to read project file
#
# \param project_file
# \b \e unicode|str : Path to project file
def OpenProject(self, project_file):
Logger.Debug(__name__, u'Opening project: {}'.format(project_file))
if not os.path.isfile(project_file):
ShowErrorDialog(GT(u'不能打开工程文件'),
GT(u'文件不存在或者不是一个规律的文件: {}').format(project_file))
return False
data = ReadFile(project_file)
lines = data.split(u'\n')
# FIXME: Need a better way to determine valid project
app = lines[0].lstrip(u'[')
if not app.startswith(u'DEBREATEFORUOS'):
ShowErrorDialog(GT(u'不能打开工程文件'),
GT(u'不是一个有效的DebreateForUos工程: {}').format(project_file))
return False
if self.LoadedProject and not self.ResetPages():
return False
# *** Get Control Data *** #
control_data = data.split(u'<<CTRL>>\n')[1].split(u'\n<</CTRL>>')[0]
depends_data = self.Wizard.GetPage(pgid.CONTROL).Set(control_data)
self.Wizard.GetPage(pgid.DEPENDS).Set(depends_data)
# *** Get Info Data *** #
info_data = data.split(u'<<INFO>>\n')[1].split(u'\n<</INFO>>')[0]
self.Wizard.GetPage(pgid.INFO).Set(info_data)
# *** Get Files Data *** #
icons_data = data.split(u'<<ICONS>>\n')[1].split(u'\n<</ICONS>>')[0]
self.Wizard.GetPage(pgid.ICONS).Set(icons_data)
# *** Get Files Data *** #
files_data = data.split(u'<<FILES>>\n')[1].split(u'\n<</FILES>>')[0]
opened = self.Wizard.GetPage(pgid.FILES).Set(files_data)
# *** Get Scripts Data *** #
scripts_data = data.split(u'<<SCRIPTS>>\n')[1].split(u'\n<</SCRIPTS>>')[0]
self.Wizard.GetPage(pgid.SCRIPTS).Set(scripts_data)
# *** Get Changelog Data *** #
clog_data = data.split(u'<<CHANGELOG>>\n')[1].split(u'\n<</CHANGELOG>>')[0]
self.Wizard.GetPage(pgid.CHANGELOG).Set(clog_data)
# *** Get Copyright Data *** #
try:
cpright_data = data.split(u'<<COPYRIGHT>>\n')[1].split(u'\n<</COPYRIGHT')[0]
self.Wizard.GetPage(pgid.COPYRIGHT).Set(cpright_data)
except IndexError:
pass
# *** Get Menu Data *** #
m_data = data.split(u'<<MENU>>\n')[1].split(u'\n<</MENU>>')[0]
self.Wizard.GetPage(pgid.MENU).SetLauncherData(m_data, enabled=True)
# Get Build Data
build_data = data.split(u'<<BUILD>>\n')[1].split(u'\n<</BUILD')[0]#.split(u'\n')
self.Wizard.GetPage(pgid.BUILD).Set(build_data)
return opened
## TODO: Doxygen
def ProjectChanged(self, event=None):
if DebugEnabled():
Logger.Debug(__name__, u'MainWindow.OnProjectChanged:')
print(u' Object: {}'.format(event.GetEventObject()))
self.ProjectDirty = True
## TODO: Doxygen
def ResetPages(self):
warn_msg = GT(u'你将会失去所有未保存的信息.')
warn_msg = u'{}\n\n{}'.format(warn_msg, GT(u'继续?'))
if ConfirmationDialog(self, text=warn_msg).ShowModal() not in (wx.ID_OK, wx.OK):
return False
for page in self.Wizard.GetAllPages():
page.Reset()
self.SetTitle(default_title)
# Reset the saved project field so we know that a project file doesn't exists
self.LoadedProject = None
return True
## TODO: Doxygen
def SetSavedStatus(self, status):
if status: # If status is changing to unsaved this is True
title = self.GetTitle()
if self.IsSaved() and title != default_title:
self.SetTitle(u'{}*'.format(title))
## TODO: Doxygen
#
# TODO: Finish definition
def ToggleTheme(self, window):
for C in window.GetChildren():
self.ToggleTheme(C)
bg_color = window.GetBackgroundColour()
fg_color = window.GetForegroundColour()
window.SetBackgroundColour(fg_color)
window.SetForegroundColour(bg_color)
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/cuglujun/debreateforuos.git
[email protected]:cuglujun/debreateforuos.git
cuglujun
debreateforuos
debreateforuos
master

搜索帮助