def __init__(self, configFileName, mode, time_cycle, d): # 多线程用,quit flag self.quit = False # 同步模式 self.mode = mode # 自动同步时间 self.time_cycle = time_cycle # 自动在同步前清空远端文件夹 self.autoDelete = d # RPC 端口 self.rpc_port = slave.PORT # 符合条件的路径会被排除 {dir:[re]} self.ignoreExp = defaultdict(list) # 文件对应的修改时间和md5 {file:(md5,time)} self.file2md5time = {} # 读取配置文件 self.config = ConfigData(configFileName) self.config.show() # 建立存放同步用数据的文件夹 self.infoDir = os.path.join(self.config.currentDir, self.INFO_DIR) if not os.path.exists(self.infoDir): os.makedirs(self.infoDir) self.remoteInfoDir = os.path.join(self.config.remoteDir, self.INFO_DIR) # 读取本地同步文件夹信息 self._loadDir()
def OnInit(self): """Called after instantiation Calls the Splash screen and returns true """ ConfigData.__init__(self) #self.doSplash() self.doMainFrame() return True
def __init__(self, *args, **kwargs): """Default Constructor for wx.Frame""" super(MainWindow, self).__init__(*args, **kwargs) icon = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAAE4AAABECAYAAAAvMQN7AAAD+klEQVR42u1cP08yMRg//6CA" "KEhCSBwY3VwcNOED8AHcTEx4+QysjHwBJjYSRhIkzk6EWROjm4sTMXyKvj6XKynH9dq7a3tt" "735JAxJp6a/Pvz7PA46TI4dWGI/H6O8BHR4euo/k86OjI/yaMXh5eXE/P94Dfl4oFNDBwUHy" "/by+vroTEZPt/E0+J0jVFsvlcmcvpCCQ+yH/J/Ii7XYblcvlnYlpAxY6Pj72v64NVqsVKpVK" "rnZgsnzkBO4J3nN6eop+fn649+MSwZo8bBCqkCpqtZpLGGFSYo3RaIS49D/JIn4C05DAAJVL" "NDziw6VNJHF4A7Dw1dUVc/Fer4cqlcqOhID0wxgOh8z3Y5UU9fnJfVA16Pr6Wugp+QfMT9vw" "5+en+8HC1sd2h3XwsgZ8vu/v7/31wR2LlDZe4sDbRT39NIgjnIu6RRkSF5k48HaqiSOih/SJ" "u7y8RHENOcXmIdnqqgVxxWIx9umDE8kscQKckdI9BNpXlleTZOPEbiINicuJY68HkYcuXtUo" "Vb27u0PK4yAbiAu9soi+59lAHNed++TkRMp9z1TiwK7RbNseLi4uhEueicTFze7gq03WVTU6" "np+ft8wnlT4TiMOCwpN/4wJMmJQ83YmDvYGJ6nQ64hOv1Wo1NoG6Ewd7k5qWDijMGE0ceMyz" "szM16X2ogEUNWXQlzsvQqAPEe1HshwrieDPYcOhESks9vBoAVzwUlLWNQj5PpiJK6h8cQWp1" "y/V6PQL7wHIWtFYJATWOWPk9WgpcOVjkEbeQQFWNYi8x2e/v7zvzPT4+8pClD2l+taMRGHJ9" "ESJtYLNYB8B951QNLxYKHb+/v//ikkerNdzf3zOLydpJmh9w6mFqG1JU9rda7ama1wi0g263" "y1RtTxv0Rr/fZ54+raj89va2tXnYLhKemxpThhHHUf3XB6yyHxAiIvBkpb4gBJpMJkY1PnKH" "Gk9PT5E31mq1EJlwpZEn/f4pAx8fH1xNfNhwh7Q1bNFsNgO7KYPmFJYaSkvqeLofiY26Kkwm" "EnCzixdKcOfVGo2GucQJuh2IqrkaB9WEoZubG/OJ22w2TdUS59gCVepK2EZroEzaZrOZVcQ5" "CiXOLpyfn0vthrLOvmGEXeBFedSgJIDxeHh4UCFx1iIPeuPm6mQRV6/X7SVOZjxnRLIyLqCo" "E7cTIJOhiApVtdo5JP0ebGadQ05cAucgS11vb2/tjuNkEbdYLOwlbjAYSPlOrA7f/zfu9kB0" "POXERR3T6TQTxDle66iwGoOTJXjNM7EHNAYaWXBOiq+vLyRA8jIN7hCF/DEpJ4fjQPBKSl9Q" "JR97z/l8npPmB/wGCbRAkE3ZkHL3ekZy5Mgw/gMoRoA7F6WE6gAAAABJRU5ErkJggg==" ) self.SetIcon(icon.GetIcon()) self.sx = 0 self.sy = 0 - 20 self.mainpan = wx.Panel(self) self.configs = ConfigData() self.online_status = False self.goodcolor = self.configs.colors['online'] self.warningcolor = self.configs.colors['offline'] self.on_off_flag = threading.Event() self.running_flag = threading.Event() self.configs.VK_CODE self.__init_ui() self._start_watcher_thread()
def __init__(self, parent, style=wx.FULL_REPAINT_ON_RESIZE, flag=wx.ADJUST_MINSIZE): wx.Frame.__init__(self, parent, -1, _(u"Template-Designer")) self.myConfig = ConfigData() self.myConfig.saveConfig() """ Set taskbar icon. If you remove this, do not forget to remove the RemoveIcon() and Destroy() methods in self.OnExitWindow() """ self.taskBarIcon = wx.TaskBarIcon() iconPath = self.myConfig.skinGraphics() + "/domtreeviewer.png" icon = wx.Icon(iconPath, wx.BITMAP_TYPE_PNG) self.taskBarIcon.SetIcon(icon, _(u"Template-Designer")) #Set titlebar icon self.SetIcon(icon) self.logoPanel = wx.Panel(self, -1) self.settingsPanel = wx.Panel(self, -1) self.fullRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Full Access"), name="fullAccess") self.fullRadio.SetValidator(WelcomeValidator(self)) self.restrictedRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Restricted Access"), name="restrictedAccess") self.restrictedRadio.SetValidator(WelcomeValidator(self)) self.viewRadio = wx.RadioButton(self.settingsPanel, -1, _(u"View available templates"), name="viewAccess") self.viewRadio.SetValidator(WelcomeValidator(self)) self.placeholderPanel = wx.Panel(self.settingsPanel, -1) self.passwordLabel = wx.StaticText(self.settingsPanel, -1, _(u"Password"), name="passwordLabel") self.passwordTextCtrl = wx.TextCtrl(self.settingsPanel, -1, "", style=wx.TE_PASSWORD, name="password") self.passwordTextCtrl.SetValidator(WelcomeValidator(self)) logo = wx.Bitmap("logo.png", wx.BITMAP_TYPE_ANY) self.logoBitmap = wx.StaticBitmap(self.logoPanel, -1, logo) self.staticLine = wx.StaticLine(self, -1) self.bitplantLabel = wx.StaticText(self, -1, _(u"Bitplant Template-Designer")) self.goButton = wx.Button(self, -1, _(u"OK"), name="goButton") self.goButton.SetValidator(WelcomeValidator(self)) self.exitButton = wx.Button(self, -1, _(u"Exit"), name="exitButton") self.__doProperties() self.__doBindings() self.__doLayout()
class TemplateDesignerWelcome(wx.Frame): """Generally called by class TemplateDesigner returns nothing but calls class TemplateDesignerFrame if user decides not to leave the dialog """ def __init__(self, parent, style=wx.FULL_REPAINT_ON_RESIZE, flag=wx.ADJUST_MINSIZE): wx.Frame.__init__(self, parent, -1, _(u"Template-Designer")) self.myConfig = ConfigData() self.myConfig.saveConfig() """ Set taskbar icon. If you remove this, do not forget to remove the RemoveIcon() and Destroy() methods in self.OnExitWindow() """ self.taskBarIcon = wx.TaskBarIcon() iconPath = self.myConfig.skinGraphics() + "/domtreeviewer.png" icon = wx.Icon(iconPath, wx.BITMAP_TYPE_PNG) self.taskBarIcon.SetIcon(icon, _(u"Template-Designer")) #Set titlebar icon self.SetIcon(icon) self.logoPanel = wx.Panel(self, -1) self.settingsPanel = wx.Panel(self, -1) self.fullRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Full Access"), name="fullAccess") self.fullRadio.SetValidator(WelcomeValidator(self)) self.restrictedRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Restricted Access"), name="restrictedAccess") self.restrictedRadio.SetValidator(WelcomeValidator(self)) self.viewRadio = wx.RadioButton(self.settingsPanel, -1, _(u"View available templates"), name="viewAccess") self.viewRadio.SetValidator(WelcomeValidator(self)) self.placeholderPanel = wx.Panel(self.settingsPanel, -1) self.passwordLabel = wx.StaticText(self.settingsPanel, -1, _(u"Password"), name="passwordLabel") self.passwordTextCtrl = wx.TextCtrl(self.settingsPanel, -1, "", style=wx.TE_PASSWORD, name="password") self.passwordTextCtrl.SetValidator(WelcomeValidator(self)) logo = wx.Bitmap("logo.png", wx.BITMAP_TYPE_ANY) self.logoBitmap = wx.StaticBitmap(self.logoPanel, -1, logo) self.staticLine = wx.StaticLine(self, -1) self.bitplantLabel = wx.StaticText(self, -1, _(u"Bitplant Template-Designer")) self.goButton = wx.Button(self, -1, _(u"OK"), name="goButton") self.goButton.SetValidator(WelcomeValidator(self)) self.exitButton = wx.Button(self, -1, _(u"Exit"), name="exitButton") self.__doProperties() self.__doBindings() self.__doLayout() def OnExitWindow(self, event=None): """close the Welcome dialog removes the taskbar icon and destroys the dialog if user clicked the exitButton """ self.taskBarIcon.RemoveIcon() self.taskBarIcon.Destroy() self.Destroy() def __doBindings(self): self.Bind(wx.EVT_CLOSE, self.OnExitWindow) self.Bind(wx.EVT_BUTTON, self.OnExitWindow, self.exitButton) def __doProperties(self): self.SetTitle(_(u"Bitplant Template-Designer")) self.SetMinSize((600, 250)) white = wx.Colour(255, 255, 255) self.logoPanel.SetBackgroundColour(white) font = wx.Font(9, wx.SWISS, wx.ITALIC, wx.LIGHT, 0, "") self.bitplantLabel.SetFont(font) self.goButton.Disable() self.passwordLabel.Disable() self.passwordTextCtrl.Disable() self.restrictedRadio.SetValue(True) def __doLayout(self): sizerStyle = wx.ALL | wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL radioSizer = wx.BoxSizer(wx.VERTICAL) radioSizer.Add(self.fullRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.restrictedRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.viewRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.placeholderPanel, 2, wx.EXPAND, 0) passwordSizer = wx.BoxSizer(wx.HORIZONTAL) passwordSizer.Add(self.passwordLabel, 0, wx.RIGHT, 4) passwordSizer.Add(self.passwordTextCtrl, 1, 0, 0) settingsSizer = wx.BoxSizer(wx.VERTICAL) settingsSizer.Add(radioSizer, 1, wx.ALL | wx.EXPAND, 0) settingsSizer.Add(passwordSizer, 0, sizerStyle, 4) self.settingsPanel.SetSizer(settingsSizer) logoSizer = wx.BoxSizer(wx.HORIZONTAL) logoSizer.Add(self.logoBitmap, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 24) self.logoPanel.SetSizer(logoSizer) settingsLogoSizer = wx.BoxSizer(wx.HORIZONTAL) settingsLogoSizer.Add(self.settingsPanel, 1, wx.ALL | wx.EXPAND, 4) settingsLogoSizer.Add(self.logoPanel, 0, sizerStyle, 0) buttonBoxSizer = wx.BoxSizer(wx.HORIZONTAL) buttonBoxSizer.Add(self.bitplantLabel, 1, wx.ALL | wx.ALIGN_BOTTOM, 4) buttonBoxSizer.Add(self.goButton, 0, wx.ALL, 4) buttonBoxSizer.Add(self.exitButton, 0, wx.ALL, 4) mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(settingsLogoSizer, 1, wx.ALL | wx.EXPAND, 0) mainSizer.Add(self.staticLine, 0, wx.ALL | wx.EXPAND, 4) mainSizer.Add(buttonBoxSizer, 0, wx.ALL | wx.EXPAND, 4) self.SetSizer(mainSizer) mainSizer.Fit(self) self.Layout()
class MainWindow(wx.Frame): """Primary Window""" def __init__(self, *args, **kwargs): """Default Constructor for wx.Frame""" super(MainWindow, self).__init__(*args, **kwargs) icon = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAAE4AAABECAYAAAAvMQN7AAAD+klEQVR42u1cP08yMRg//6CA" "KEhCSBwY3VwcNOED8AHcTEx4+QysjHwBJjYSRhIkzk6EWROjm4sTMXyKvj6XKynH9dq7a3tt" "735JAxJp6a/Pvz7PA46TI4dWGI/H6O8BHR4euo/k86OjI/yaMXh5eXE/P94Dfl4oFNDBwUHy" "/by+vroTEZPt/E0+J0jVFsvlcmcvpCCQ+yH/J/Ii7XYblcvlnYlpAxY6Pj72v64NVqsVKpVK" "rnZgsnzkBO4J3nN6eop+fn649+MSwZo8bBCqkCpqtZpLGGFSYo3RaIS49D/JIn4C05DAAJVL" "NDziw6VNJHF4A7Dw1dUVc/Fer4cqlcqOhID0wxgOh8z3Y5UU9fnJfVA16Pr6Wugp+QfMT9vw" "5+en+8HC1sd2h3XwsgZ8vu/v7/31wR2LlDZe4sDbRT39NIgjnIu6RRkSF5k48HaqiSOih/SJ" "u7y8RHENOcXmIdnqqgVxxWIx9umDE8kscQKckdI9BNpXlleTZOPEbiINicuJY68HkYcuXtUo" "Vb27u0PK4yAbiAu9soi+59lAHNed++TkRMp9z1TiwK7RbNseLi4uhEueicTFze7gq03WVTU6" "np+ft8wnlT4TiMOCwpN/4wJMmJQ83YmDvYGJ6nQ64hOv1Wo1NoG6Ewd7k5qWDijMGE0ceMyz" "szM16X2ogEUNWXQlzsvQqAPEe1HshwrieDPYcOhESks9vBoAVzwUlLWNQj5PpiJK6h8cQWp1" "y/V6PQL7wHIWtFYJATWOWPk9WgpcOVjkEbeQQFWNYi8x2e/v7zvzPT4+8pClD2l+taMRGHJ9" "ESJtYLNYB8B951QNLxYKHb+/v//ikkerNdzf3zOLydpJmh9w6mFqG1JU9rda7ama1wi0g263" "y1RtTxv0Rr/fZ54+raj89va2tXnYLhKemxpThhHHUf3XB6yyHxAiIvBkpb4gBJpMJkY1PnKH" "Gk9PT5E31mq1EJlwpZEn/f4pAx8fH1xNfNhwh7Q1bNFsNgO7KYPmFJYaSkvqeLofiY26Kkwm" "EnCzixdKcOfVGo2GucQJuh2IqrkaB9WEoZubG/OJ22w2TdUS59gCVepK2EZroEzaZrOZVcQ5" "CiXOLpyfn0vthrLOvmGEXeBFedSgJIDxeHh4UCFx1iIPeuPm6mQRV6/X7SVOZjxnRLIyLqCo" "E7cTIJOhiApVtdo5JP0ebGadQ05cAucgS11vb2/tjuNkEbdYLOwlbjAYSPlOrA7f/zfu9kB0" "POXERR3T6TQTxDle66iwGoOTJXjNM7EHNAYaWXBOiq+vLyRA8jIN7hCF/DEpJ4fjQPBKSl9Q" "JR97z/l8npPmB/wGCbRAkE3ZkHL3ekZy5Mgw/gMoRoA7F6WE6gAAAABJRU5ErkJggg==" ) self.SetIcon(icon.GetIcon()) self.sx = 0 self.sy = 0 - 20 self.mainpan = wx.Panel(self) self.configs = ConfigData() self.online_status = False self.goodcolor = self.configs.colors['online'] self.warningcolor = self.configs.colors['offline'] self.on_off_flag = threading.Event() self.running_flag = threading.Event() self.configs.VK_CODE self.__init_ui() self._start_watcher_thread() def _start_watcher_thread(self): logging.debug("Creating Key Watcher thread") # Start the Key_Watch thread self.key_watcher = dismantle_thread.DismantleThread( self._gather_settings_data(), self.configs, self.running_flag, self.on_off_flag) self.key_watcher.daemon = True self.key_watcher.start() self.running_flag.set() def __init_ui(self): self.sizers = {} self.gui_items = { "action_but": { "start": wx.Button(self.mainpan, wx.ID_ANY, "Start", name="Start", pos=(self.sx + 113, self.sy + 129), size=(203, 50)), "stop": wx.Button(self.mainpan, wx.ID_ANY, "Stop", name="Stop", pos=(self.sx + 113, self.sy + 129), size=(203, 50)) }, "online_box": wx.TextCtrl(self.mainpan, wx.ID_ANY, "", name="Offline", pos=(self.sx + 10, self.sy + 130), size=(100, 50), style=wx.TE_READONLY), "keybinds": { "labels": { "amount": wx.StaticText(self.mainpan, wx.ID_ANY, "Amount", pos=(self.sx + 10, self.sy + 25)), "keybind": wx.StaticText(self.mainpan, wx.ID_ANY, "Keybind", pos=(self.sx + 113, self.sy + 25)) }, "ten": { "amount_txt": wx.TextCtrl(self.mainpan, wx.ID_ANY, self.configs.bind_one['amount'], name="Amount to Dismantle", pos=(self.sx + 10, self.sy + 45), size=(100, 25)), "txt": wx.ComboBox( self.mainpan, size=(203, 25), choices=self.configs.VK_KEYS, value=self.configs.bind_one['keybind'], style=wx.CB_DROPDOWN | wx.TE_READONLY, name='Keybind 1', pos=(self.sx + 113, self.sy + 45), ) }, "twenty_five": { "amount_txt": wx.TextCtrl(self.mainpan, wx.ID_ANY, self.configs.bind_two['amount'], name="Amount to Dismantle", pos=(self.sx + 10, self.sy + 73), size=(100, 25)), "txt": wx.ComboBox( self.mainpan, size=(203, 25), choices=self.configs.VK_KEYS, value=self.configs.bind_two['keybind'], style=wx.CB_DROPDOWN | wx.TE_READONLY, name='Keybind 2', pos=(self.sx + 113, self.sy + 73), ) }, "fifty": { "amount_txt": wx.TextCtrl(self.mainpan, wx.ID_ANY, self.configs.bind_three['amount'], name="Amount to Dismantle", pos=(self.sx + 10, self.sy + 101), size=(100, 25)), "txt": wx.ComboBox( self.mainpan, size=(203, 25), choices=self.configs.VK_KEYS, value=self.configs.bind_three['keybind'], style=wx.CB_DROPDOWN | wx.TE_READONLY, name='Keybind 3', pos=(self.sx + 113, self.sy + 101), ) } } } self.gui_items['online_box'].SetBackgroundColour(self.warningcolor) self.gui_items['action_but']['stop'].Hide() # Binds self.Bind(wx.EVT_BUTTON, self.on_start_stop, self.gui_items['action_but']['start']) self.Bind(wx.EVT_BUTTON, self.on_start_stop, self.gui_items['action_but']['stop']) self.Bind(wx.EVT_COMBOBOX, self._on_bind_one_sel, self.gui_items['keybinds']['ten']['txt']) self.Bind(wx.EVT_TEXT, self._on_bind_one_amt, self.gui_items['keybinds']['ten']['amount_txt']) self.Bind(wx.EVT_COMBOBOX, self._on_bind_one_sel, self.gui_items['keybinds']['twenty_five']['txt']) self.Bind(wx.EVT_TEXT, self._on_bind_one_amt, self.gui_items['keybinds']['twenty_five']['amount_txt']) self.Bind(wx.EVT_COMBOBOX, self._on_bind_one_sel, self.gui_items['keybinds']['fifty']['txt']) self.Bind(wx.EVT_TEXT, self._on_bind_one_amt, self.gui_items['keybinds']['fifty']['amount_txt']) self.Bind(wx.EVT_CLOSE, self.on_close) self.SetMinSize((200, 115)) self.SetMaxSize((340, 205)) dw, dh = wx.DisplaySize() w, h = self.GetSize() x = (dw / 2) - w y = (dh / 2) - h self.SetPosition((x - 10 + 1400, y - 45)) self.Show() def on_start_stop(self, e): if self.online_status: # Switch to Offline self.gui_items['online_box'].SetBackgroundColour(self.warningcolor) self.gui_items['action_but']['stop'].Hide() self.gui_items['action_but']['start'].Show() self.SetTitle('Destiny 2 Auto-Dismantler - Offline') self.online_status = False # Stop the Key_Watch thread self.on_off_flag.clear() else: # Switch to Online self.gui_items['online_box'].SetBackgroundColour(self.goodcolor) self.gui_items['action_but']['start'].Hide() self.gui_items['action_but']['stop'].Show() self.SetTitle('Destiny 2 Auto-Dismantler - Online') self.online_status = True self.on_off_flag.set() self.Refresh() def _gather_settings_data(self): k_one = self.gui_items['keybinds']['ten']['txt'].GetValue() k_two = self.gui_items['keybinds']['twenty_five']['txt'].GetValue() k_three = self.gui_items['keybinds']['fifty']['txt'].GetValue() setting_data = { "ten": { "amount": int(self.gui_items['keybinds']['ten'] ['amount_txt'].GetValue()), "keybind": { "key": k_one, "key_code": self.configs.VK_CODE[k_one] } }, "twenty_five": { "amount": int(self.gui_items['keybinds']['twenty_five'] ['amount_txt'].GetValue()), "keybind": { "key": k_two, "key_code": self.configs.VK_CODE[k_two] } }, "fifty": { "amount": int(self.gui_items['keybinds']['fifty'] ['amount_txt'].GetValue()), "keybind": { "key": k_three, "key_code": self.configs.VK_CODE[k_three] } } } return setting_data def _on_bind_one_sel(self, e): logging.debug("Bind one changed to |{}|".format( self.gui_items['keybinds']['ten']['txt'].GetValue())) self.key_watcher.settings['ten']['keybind']['key'] = self.gui_items[ 'keybinds']['ten']['txt'].GetValue() def _on_bind_one_amt(self, e): if self.gui_items['keybinds']['ten']['amount_txt'].GetValue(): self.key_watcher.settings['ten']['amount'] = int( self.gui_items['keybinds']['ten']['amount_txt'].GetValue()) else: self.key_watcher.settings['ten']['amount'] = 10 def _on_bind_two_sel(self, e): logging.debug("Bind two changed to |{}|".format( self.gui_items['keybinds']['twenty_five']['txt'].GetValue())) self.key_watcher.settings['twenty_five']['keybind'][ 'key'] = self.gui_items['keybinds']['twenty_five']['txt'].GetValue( ) def _on_bind_two_amt(self, e): if self.gui_items['keybinds']['twenty_five']['amount_txt'].GetValue(): self.key_watcher.settings['twenty_five']['amount'] = int( self.gui_items['keybinds']['twenty_five'] ['amount_txt'].GetValue()) else: self.key_watcher.settings['twenty_five']['amount'] = 25 def _on_bind_three_sel(self, e): logging.debug("Bind three changed to |{}|".format( self.gui_items['keybinds']['fifty']['txt'].GetValue())) self.key_watcher.settings['fifty']['keybind']['key'] = self.gui_items[ 'keybinds']['fifty']['txt'].GetValue() def _on_bind_three_amt(self, e): if self.gui_items['keybinds']['fifty']['amount_txt'].GetValue(): self.key_watcher.settings['fifty']['amount'] = int( self.gui_items['keybinds']['fifty']['amount_txt'].GetValue()) else: self.key_watcher.settings['fifty']['amount'] = 50 def _save_settings(self): save_settings = { "keybinds": { "bind1": { "amount": str(self.gui_items['keybinds']['ten'] ['amount_txt'].GetValue()), "keybind": self.gui_items['keybinds']['ten']['txt'].GetValue() }, "bind2": { "amount": str(self.gui_items['keybinds']['twenty_five'] ['amount_txt'].GetValue()), "keybind": self.gui_items['keybinds']['twenty_five'] ['txt'].GetValue() }, "bind3": { "amount": str(self.gui_items['keybinds']['fifty'] ['amount_txt'].GetValue()), "keybind": self.gui_items['keybinds']['fifty']['txt'].GetValue() } }, "colors": { "online": [13, 255, 19], "offline": [255, 128, 0] } } self.configs.save_config_data(save_settings) def on_close(self, e): self._save_settings() if self.online_status: self.on_start_stop(None) logging.debug("Closing application...") self.Destroy()
parser = argparse.ArgumentParser() parser.add_argument('--config_file', help='path/to/config/file', default='./conf.xml') parser.add_argument('--mode', choices=['synchronize', 'echo'], help='synchronize mode', default='echo') args = parser.parse_args() confFile = args.config_file mode = args.mode conf = ConfigData(confFile) conf.show() md5FilePath = os.path.join(conf.currentDir, MD5FILE) conf.hashDict = {} # 初始化 if os.path.exists(md5FilePath): with open(md5FilePath) as f: for _line in f: _path, _md5 = _line.split() conf.hashDict[_path] = _md5 # 初始化更新文件md5 for root, dirs, files in os.walk(conf.currentDir): for name in files:
def __init__(self, parent, safetyMode="viewAccess", *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) self.safetyMode = safetyMode ConfigData.__init__(self, *args, **kwargs) StatusBar.__init__(self, parent, *args, **kwargs) MenuBar.__init__(self, parent, *args, **kwargs) ToolBar.__init__(self, parent, *args, **kwargs) TreeContextMenu.__init__(self, parent, *args, **kwargs) # Some actions which are not relevant for any specific area Actions.__init__(self, *args, **kwargs) # The functions to enable printing Printing.__init__(self, parent, *args, **kwargs) # The functions to enable the help system Help.__init__(self, *args, **kwargs) # The functions to enable the about dialog About.__init__(self, *args, **kwargs) # The functions to enable the about dialog Settings.__init__(self, *args, **kwargs) #Set main splitter MainSplitter.__init__(self, *args, **kwargs) #Add the xml tree Document.__init__(self, *args, **kwargs) #Fill xml tree GetData.__init__(self, *args, **kwargs) #Add functions to modify the view of the xml tree ViewData.__init__(self, *args, **kwargs) #Add functions to edit the xml tree EditData.__init__(self, *args, **kwargs) #Copy example files: Comment this out if Template-Designer is in productive use. #self.getExamples() #Some kind of self check self.saveConfig() #Set panels #self.propertiesPanel = wx.Panel(self.mainSplitter) self.propertiesPanel = wx.ScrolledWindow(self.mainSplitter) self.templatePanel = wx.Panel(self.mainSplitter) #Buttons on main frame self.applyButton = wx.Button(self.propertiesPanel, wx.ID_APPLY, _(u"Apply changes"), name="applyButton") self.defaultsButton = wx.Button(self.propertiesPanel, wx.ID_RESET, _(u"Restore settings"), name="defaultsButtons") expandAllButtonPath = self.documentTreeGraphics() + "/2downarrow.png" expandAllButtonBmp = wx.Image(expandAllButtonPath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() self.expandAllButton = wx.BitmapButton(self.templatePanel, -1, expandAllButtonBmp, name="expandButton") collapseAllButtonPath = self.documentTreeGraphics() + "/2uparrow.png" collapseAllButtonBmp = wx.Image(collapseAllButtonPath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() self.collapseAllButton = wx.BitmapButton(self.templatePanel, -1, collapseAllButtonBmp, name="collapseButton") addButtonPath = self.documentTreeGraphics() + "/filenew.png" addButtonBmp = wx.Image(addButtonPath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() self.addButton = wx.BitmapButton(self.templatePanel, -1, addButtonBmp, name="addButton") deleteButtonPath = self.documentTreeGraphics() + "/edit_delete.png" deleteButtonBmp = wx.Image(deleteButtonPath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() self.deleteButton = wx.BitmapButton(self.templatePanel, -1, deleteButtonBmp, name="deleteButton") """ Set taskbar icon. If you remove this, do not forget to remove the RemoveIcon() and Destroy() methods in self.onCloseWindow() """ self.taskBarIcon = wx.TaskBarIcon() iconPath = self.skinGraphics() + "/domtreeviewer.png" icon = wx.Icon(iconPath, wx.BITMAP_TYPE_PNG) self.taskBarIcon.SetIcon(icon, _(u"Template-Designer")) #Set titlebar icon self.SetIcon(icon) #Initiate the contents of the property panel self.pp = pp self.__doProperties() self.__doBindings() self.__doLayout() Safety(self)
class TemplateDesignerWelcome(wx.Frame): """Generally called by class TemplateDesigner returns nothing but calls class TemplateDesignerFrame if user decides not to leave the dialog """ def __init__(self, parent, style = wx.FULL_REPAINT_ON_RESIZE, flag = wx.ADJUST_MINSIZE): wx.Frame.__init__(self, parent, -1, _(u"Template-Designer")) self.myConfig = ConfigData() self.myConfig.saveConfig() """ Set taskbar icon. If you remove this, do not forget to remove the RemoveIcon() and Destroy() methods in self.OnExitWindow() """ self.taskBarIcon = wx.TaskBarIcon() iconPath = self.myConfig.skinGraphics() + "/domtreeviewer.png" icon = wx.Icon(iconPath, wx.BITMAP_TYPE_PNG) self.taskBarIcon.SetIcon(icon, _(u"Template-Designer")) #Set titlebar icon self.SetIcon(icon) self.logoPanel = wx.Panel(self, -1) self.settingsPanel = wx.Panel(self, -1) self.fullRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Full Access"), name="fullAccess") self.fullRadio.SetValidator(WelcomeValidator(self)) self.restrictedRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Restricted Access"), name="restrictedAccess") self.restrictedRadio.SetValidator(WelcomeValidator(self)) self.viewRadio = wx.RadioButton(self.settingsPanel, -1, _(u"View available templates"), name="viewAccess") self.viewRadio.SetValidator(WelcomeValidator(self)) self.placeholderPanel = wx.Panel(self.settingsPanel, -1) self.passwordLabel = wx.StaticText(self.settingsPanel, -1, _(u"Password"), name="passwordLabel") self.passwordTextCtrl = wx.TextCtrl(self.settingsPanel, -1, "", style=wx.TE_PASSWORD, name="password") self.passwordTextCtrl.SetValidator(WelcomeValidator(self)) logo = wx.Bitmap("logo.png", wx.BITMAP_TYPE_ANY) self.logoBitmap = wx.StaticBitmap(self.logoPanel, -1, logo) self.staticLine = wx.StaticLine(self, -1) self.bitplantLabel = wx.StaticText(self, -1, _(u"Bitplant Template-Designer")) self.goButton = wx.Button(self, -1, _(u"OK"), name="goButton") self.goButton.SetValidator(WelcomeValidator(self)) self.exitButton = wx.Button(self, -1, _(u"Exit"), name="exitButton") self.__doProperties() self.__doBindings() self.__doLayout() def OnExitWindow(self, event=None): """close the Welcome dialog removes the taskbar icon and destroys the dialog if user clicked the exitButton """ self.taskBarIcon.RemoveIcon() self.taskBarIcon.Destroy() self.Destroy() def __doBindings(self): self.Bind(wx.EVT_CLOSE, self.OnExitWindow) self.Bind(wx.EVT_BUTTON, self.OnExitWindow, self.exitButton) def __doProperties(self): self.SetTitle(_(u"Bitplant Template-Designer")) self.SetMinSize((600, 250)) white = wx.Colour(255, 255, 255) self.logoPanel.SetBackgroundColour(white) font = wx.Font(9, wx.SWISS, wx.ITALIC, wx.LIGHT, 0, "") self.bitplantLabel.SetFont(font) self.goButton.Disable() self.passwordLabel.Disable() self.passwordTextCtrl.Disable() self.restrictedRadio.SetValue(True) def __doLayout(self): sizerStyle = wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL radioSizer = wx.BoxSizer(wx.VERTICAL) radioSizer.Add(self.fullRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.restrictedRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.viewRadio, 1, wx.EXPAND, 0) radioSizer.Add(self.placeholderPanel, 2, wx.EXPAND, 0) passwordSizer = wx.BoxSizer(wx.HORIZONTAL) passwordSizer.Add(self.passwordLabel, 0, wx.RIGHT, 4) passwordSizer.Add(self.passwordTextCtrl, 1, 0, 0) settingsSizer = wx.BoxSizer(wx.VERTICAL) settingsSizer.Add(radioSizer, 1, wx.ALL|wx.EXPAND, 0) settingsSizer.Add(passwordSizer, 0, sizerStyle, 4) self.settingsPanel.SetSizer(settingsSizer) logoSizer = wx.BoxSizer(wx.HORIZONTAL) logoSizer.Add(self.logoBitmap, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 24) self.logoPanel.SetSizer(logoSizer) settingsLogoSizer = wx.BoxSizer(wx.HORIZONTAL) settingsLogoSizer.Add(self.settingsPanel, 1, wx.ALL|wx.EXPAND, 4) settingsLogoSizer.Add(self.logoPanel, 0, sizerStyle, 0) buttonBoxSizer = wx.BoxSizer(wx.HORIZONTAL) buttonBoxSizer.Add(self.bitplantLabel, 1, wx.ALL|wx.ALIGN_BOTTOM, 4) buttonBoxSizer.Add(self.goButton, 0, wx.ALL, 4) buttonBoxSizer.Add(self.exitButton, 0, wx.ALL, 4) mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(settingsLogoSizer, 1, wx.ALL|wx.EXPAND, 0) mainSizer.Add(self.staticLine, 0, wx.ALL|wx.EXPAND, 4) mainSizer.Add(buttonBoxSizer, 0, wx.ALL|wx.EXPAND, 4) self.SetSizer(mainSizer) mainSizer.Fit(self) self.Layout()
def __init__(self, parent, style = wx.FULL_REPAINT_ON_RESIZE, flag = wx.ADJUST_MINSIZE): wx.Frame.__init__(self, parent, -1, _(u"Template-Designer")) self.myConfig = ConfigData() self.myConfig.saveConfig() """ Set taskbar icon. If you remove this, do not forget to remove the RemoveIcon() and Destroy() methods in self.OnExitWindow() """ self.taskBarIcon = wx.TaskBarIcon() iconPath = self.myConfig.skinGraphics() + "/domtreeviewer.png" icon = wx.Icon(iconPath, wx.BITMAP_TYPE_PNG) self.taskBarIcon.SetIcon(icon, _(u"Template-Designer")) #Set titlebar icon self.SetIcon(icon) self.logoPanel = wx.Panel(self, -1) self.settingsPanel = wx.Panel(self, -1) self.fullRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Full Access"), name="fullAccess") self.fullRadio.SetValidator(WelcomeValidator(self)) self.restrictedRadio = wx.RadioButton(self.settingsPanel, -1, _(u"Restricted Access"), name="restrictedAccess") self.restrictedRadio.SetValidator(WelcomeValidator(self)) self.viewRadio = wx.RadioButton(self.settingsPanel, -1, _(u"View available templates"), name="viewAccess") self.viewRadio.SetValidator(WelcomeValidator(self)) self.placeholderPanel = wx.Panel(self.settingsPanel, -1) self.passwordLabel = wx.StaticText(self.settingsPanel, -1, _(u"Password"), name="passwordLabel") self.passwordTextCtrl = wx.TextCtrl(self.settingsPanel, -1, "", style=wx.TE_PASSWORD, name="password") self.passwordTextCtrl.SetValidator(WelcomeValidator(self)) logo = wx.Bitmap("logo.png", wx.BITMAP_TYPE_ANY) self.logoBitmap = wx.StaticBitmap(self.logoPanel, -1, logo) self.staticLine = wx.StaticLine(self, -1) self.bitplantLabel = wx.StaticText(self, -1, _(u"Bitplant Template-Designer")) self.goButton = wx.Button(self, -1, _(u"OK"), name="goButton") self.goButton.SetValidator(WelcomeValidator(self)) self.exitButton = wx.Button(self, -1, _(u"Exit"), name="exitButton") self.__doProperties() self.__doBindings() self.__doLayout()
class FileSync: INFO_DIR = '.filesync/' MD5_FILE = 'md5' IGNORE_FILE = '.fileignore' MODE_ECHO = 'echo' MODE_SYNCHRONIZE = 'synchronize' def __init__(self, configFileName, mode, time_cycle, d): # 多线程用,quit flag self.quit = False # 同步模式 self.mode = mode # 自动同步时间 self.time_cycle = time_cycle # 自动在同步前清空远端文件夹 self.autoDelete = d # RPC 端口 self.rpc_port = slave.PORT # 符合条件的路径会被排除 {dir:[re]} self.ignoreExp = defaultdict(list) # 文件对应的修改时间和md5 {file:(md5,time)} self.file2md5time = {} # 读取配置文件 self.config = ConfigData(configFileName) self.config.show() # 建立存放同步用数据的文件夹 self.infoDir = os.path.join(self.config.currentDir, self.INFO_DIR) if not os.path.exists(self.infoDir): os.makedirs(self.infoDir) self.remoteInfoDir = os.path.join(self.config.remoteDir, self.INFO_DIR) # 读取本地同步文件夹信息 self._loadDir() def _loadDir(self): """ 读取.fileignore文件 读取文件目录结构 导出.filesync文件 :return: """ self.__updateDirIgnore(self.config.currentDir) self.__updateDirMD5(self.config.currentDir) self.dumpMD5(self.infoDir) def updateIgnore(self, curDir): """ 读取`curDir`路径下的.fileignore文件 当文件不存在时,删除`self.ignoreExp`中对应键值对 :param curDir: :return: """ changed = False ignoreFile = os.path.join(curDir, self.IGNORE_FILE) if not os.path.exists(ignoreFile): if not self.ignoreExp[curDir]: return False else: del self.ignoreExp[curDir] return True with open(ignoreFile, 'r') as f: exps = f.read().split('\n') exps.sort() # 保证用户以不同顺序写的两组相同表达式不会影响`changed`变量 oldExps = self.ignoreExp.get(curDir, []) newExps = [] for exp in map(str.strip, exps): try: re.compile(exp) # 测试表达式 newExps.append(exp) # 无法处理 修改.fileignore事件 故取消预编译设计 except: print(traceback.format_exc()) if newExps != oldExps: # 这里的比较是逐元素比较 self.ignoreExp[curDir] = newExps changed = True return changed def __updateDirIgnore(self, curDir): """ DFS文件路径,读取所有的.fileignore文件 :param curDir: :return: """ if curDir[-1] != '/': curDir += '/' fileNames = os.listdir(curDir) if self.IGNORE_FILE in fileNames: self.updateIgnore(curDir) for filename in os.listdir(curDir): fullPath = os.path.join(curDir, filename) if os.path.isdir(fullPath): self.__updateDirIgnore(fullPath) def __DFSIncludedFile(self, curDir, fun): """ 辅助函数DFS遍历未被忽略的函数 :param curDir: :param fun: function(fullPath):void :return: """ if curDir[-1] != '/': curDir += '/' for filename in os.listdir(curDir): # 检查是否忽略 if self.__isIgnore(filename, curDir): continue fullPath = os.path.join(curDir, filename) if os.path.isdir(fullPath): self.__DFSIncludedFile(fullPath, fun) else: fun(fullPath) def updateMD5(self, fullPath): """ 当md5变化时,文件粒度更新`self.file2md5time` 当文件不存在时,删除`self.file2md5time`中对应键值对 :param fullPath: :return: bool 是否更新了self.file2md5time """ oldMd5, oldTime = self.file2md5time.get(fullPath, (None, None)) if not os.path.exists(fullPath): if oldMd5 is None: return False, oldMd5, oldTime else: del self.file2md5time[fullPath] return True, oldMd5, oldTime newMd5 = file2md5(fullPath) if oldMd5 != newMd5: time = os.stat(fullPath).st_mtime # 文件修改时间 时间戳 self.file2md5time[fullPath] = (newMd5, time) return True, oldMd5, oldTime return False, oldMd5, oldTime def __updateDirMD5(self, curDir): """ 文件夹粒度更新md5 :param curDir: :return: """ self.__DFSIncludedFile(curDir, self.updateMD5) def __isIgnore(self, fileName, parentDir): """ 检查一个文件是否符合忽略规则 !!!无法检测祖先文件夹是否被忽略,在此情况下失效 :param fileName: :param parentDir: :return: """ if fileName == self.INFO_DIR[:-1] or fileName == self.IGNORE_FILE: return True assert parentDir[-1] == '/' ignore = False # if not self.ignoreExp[parentDir] : skip for loop for exp in self.ignoreExp[parentDir]: if re.match(exp, fileName): ignore = True break return ignore def isIgnorePlus(self, fullPath): """ 检查一个文件是否符合忽略规则 :param fullPath: :return: """ curFile = os.path.basename(fullPath) curDir = os.path.dirname(fullPath) + '/' while True: ignore = self.__isIgnore(curFile, curDir) if ignore: return True if curDir == self.config.currentDir: break curFile = os.path.basename(curDir[:-1]) curDir = os.path.dirname(curDir[:-1]) + '/' return False def dumpMD5(self, path=None): """ 将self.file2md5time中的数据导出到文件 :param path: :return: """ if not path: path = self.infoDir if path[-1] != '/': path += '/' md5FilePath = os.path.join(path, self.MD5_FILE) data = [(fileName, md5, time) for fileName, (md5, time) in self.file2md5time.iteritems()] content = '\n'.join( ['|'.join(map(str, i)) for i in sorted(data, key=lambda x: x[0])]) with open(md5FilePath, 'w') as f: f.write(content) def _init(self): """ 初始化 将slave发送到对应目录下并运行 echo mode 检查文件夹是否为空并询问是否删除,结束 synchronize mode 检查文件夹是否为空并询问是否删除,开始运行 :return: """ # 暂时存放slave.py的位置 TEMP_DIR = '/tmp/filesync/' # create remore TEMP_DIR cmd = "mkdir -p %s" % TEMP_DIR doRemoteCmd(self.config, cmd, printOut=True) # 传输slave脚本并运行 # slaveDest = os.path.join(self.remoteInfoDir, 'slave.py') slaveDest = os.path.join(TEMP_DIR, 'slave.py') sftp_put('./slave.py', slaveDest, self.config) # 需要添加故障检测? # slaveLog = os.path.join(self.remoteInfoDir, 'slave.log') slaveLog = os.path.join(TEMP_DIR, 'slave.log') cmd = 'nohup python %s 1>%s 2>&1 &' # no mode flag doRemoteCmd(self.config, cmd % (slaveDest, slaveLog)) # check if the remote directory exists server = create_server(self.config.ssh_host, self.rpc_port) code = check_path(self.config.remoteDir, server) close_server(server) if code == slave.CODE_DIR_EMPTY: print('remote directory is empty') elif code == slave.CODE_DIR_NOT_EMPTY: print('remote directory %s is NOT empty!' % self.config.remoteDir) if self.autoDelete: agree = True else: agree = getAnswer('delete all before sync? y/n\n') if agree: doRemoteCmd(self.config, 'rm %s -rf' % self.config.remoteDir) else: exit(0) elif code == slave.CODE_FILE_EXIST: print('remote directory name conflicts with an existing file!') exit(1) else: print('can not understand return code') exit(1) print('\nstart sync now...\n') # create remore infoDir cmd = "mkdir -p %s" % self.remoteInfoDir doRemoteCmd(self.config, cmd, printOut=True) # scp all included file self.__DFSIncludedFile(self.config.currentDir, lambda path: doScp(path, self.config)) if self.mode == self.MODE_ECHO: pass elif self.mode == self.MODE_SYNCHRONIZE: self.__initSynchronize() def __initSynchronize(self): """ 将slave传到remoteInfoDir 启动slave,建立远端md5文件,开始远端的本地监听,在本地要求同步时,提供对应文件的md5和时间标记 todo 通信安全 :return: """ # 传输slave脚本并运行 slaveDest = os.path.join(self.remoteInfoDir, 'slave.py') sftp_put('./slave.py', slaveDest, self.config) # 需要添加故障检测? slaveLog = os.path.join(self.remoteInfoDir, 'slave.log') cmd = 'nohup python %s --mode %s --time_cycle %s --working_dir %s 1>%s 2>&1 &' doRemoteCmd( self.config, cmd % (slaveDest, self.mode, self.time_cycle, self.config.remoteDir, slaveLog)) def _run(self): """ 开始监听本地动作 :return: """ # do sync on modify event_handler = SyncHandler(self) observer = Observer() observer.schedule(event_handler, path=self.config.currentDir, recursive=True) observer.start() print("\n----watchdog start working----\n") try: while True: sleep(1) except KeyboardInterrupt: print('stop observer...') self.quit = True observer.stop() observer.join() server = create_server(self.config.ssh_host, self.rpc_port) close_server(server) def runforever(self): self._init() self._run()