plugins/SchedulGhost/__init__.py
# -*- coding: utf-8 -*-
version="0.1.19"
# plugins/SchedulGhost/__init__.py
#
# Copyright (C) 2010 Pako (lubos.ruckl@quick.cz)
#
# This file is a plugin for EventGhost.
# Copyright © 2005-2020 EventGhost Project <http://www.eventghost.net/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.
#
# Revision history:
# -----------------
# 0.1.19 by topic2k 2018-11-26
# - fix: setting the number of days from periodically schedules didn't worked
# 0.1.18 by topic2k 2017-05-01 11:00 UTC+2
# - fix eggtimer handling if two eggtimers are started in the same second
# 0.1.17 by topic2k 2017-04-29 13:01 UTC+2
# - some layout fixes in schedulerDialog
# 0.1.16 by Sem;colon 2016-03-26 01:15 UTC+1
# - bugfix "Do also trigger events for a non-chosen day if the next day happens to be a holiday" wasn't working
# 0.1.15 by Sem;colon 2015-12-07 20:30 UTC+1
# - added option "Do not trigger events for a chosen day if the next day happens to be a holiday" to schedule type "Weekly" and "Monthly / weekday"
# - added option "Do also trigger events for a non-chosen day if the next day happens to be a holiday" to schedule type "Weekly"
# - bugfix "Do also trigger events for a non-chosen day if it happens to be a holiday" wasn't working if no weekday has been selected
# 0.1.14 by Sem;colon 2015-10-15 20:00 UTC+1
# - removed the distinction between weekend days and workdays
# 0.1.13 by Pako 2015-03-03 17:51 UTC+1
# - Immediate start schedule now has no effect on the scheduled run
# 0.1.12 by Sem;colon 2014-11-26 22:00 UTC+1
# - added option "Update 'Last run' field when executed" to "Run schedule immediately"
# 0.1.11 by Pako 2014-06-08 10:00 UTC+1
# - changes caused by a new eg.Scheduler
# 0.1.10 by Pako 2014-06-06 15:20 UTC+1
# - added action "Force to run schedule immediately"
# 0.1.9 by Pako 2014-05-17 18:15 UTC+1
# - added option to abort egg-timer by name
# 0.1.8 by Pako 2014-03-09 10:48 UTC+1
# - http://www.eventghost.net/forum/viewtopic.php?f=9&t=2740&start=75#p30126
# 0.1.7 by Pako 2013-05-05 11:06 UTC+1
# - added ReloadXML action (rekall request)
# 0.1.6 by Pako 2012-09-06 06:46 UTC+1
# - bugfix - malfunction, when the action "Disable schedule"
# is executed between the start and stop events
# 0.1.5 by Pako 2012-08-16 19:09 UTC+1
# - added DataToXML action (EventGhost4ever request)
# 0.1.4 by Pako 2011-08-24 09:15 UTC+1
# - bugfix - wrong stored last position of scheduler frame
# 0.1.3 by Pako 2011-06-05 18:53 UTC+1
# - Used eg.EVT_VALUE_CHANGED instead of EVT_BUTTON_AFTER
# 0.1.2 by Pako 2011-02-12 10:03 GMT+1
# - FixedTimeCtrl replaced by eg.TimeCtrl
# 0.1.1 by Pako 2010-12-07 10:32 GMT+1
# - wx.lib.masked.TimeCtrl bug workaround (http://trac.wxwidgets.org/ticket/11171)
# 0.1.0 by Pako 2010-10-19 10:32 GMT+1
# - some textfixes by krambriw
# - first version, placed in SVN repository
# 0.0.6 by Pako 2010-10-16 18:50 GMT+1
# - added action "Show currently running egg-timers"
# - added "Time span" schedule type
# - titlebar of every window displays SchedulGhost icon
# - some bugfixes
# 0.0.5 by Pako 2010-10-09 10:04 GMT+1
# - added button "Show SchedulGhost manager ..." in the plugin configuration dialog
# - added action "Run schedule immediately"
# 0.0.4 by Pako 2010-09-21 18:28 GMT+1
# - Closing of popup window (egg timer) causes the stop of sound playback
# 0.0.3 by Pako 2010-09-11 19:07 GMT+1
# - added action "Start egg timer" (without the possibility of adjust of time to elapse)
# 0.0.2 by Pako 2010-09-02 18:52 GMT+1
# - bugfix: Egg timer - popup window is opened (blank), although it has been disabled
# 0.0.1 by Pako 2010-08-29 13:21 GMT+1
# - forum URL settings
# 0.0.0 by Pako 2010-08-28 13:07 GMT+1
# - initial version
#===============================================================================
eg.RegisterPlugin(
name = "SchedulGhost",
author = "Pako",
version = version,
kind = "other",
guid = "{39EFE2FF-6CA9-4450-B0E3-1AA125420B37}",
description = u'''<rst>This plugin is designed to easily schedule events ...
... to be triggered at any time of the day or night.
Events can be scheduled to be triggered periodically,
once only, daily, weekly, monthly or yearly.''',
createMacrosOnAdd = True,
url = "http://www.eventghost.net/forum/viewtopic.php?f=9&t=2740",
icon = (
"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAADAFBMVEUA//+tra1+fn5q"
"ampnZ2ePj49mZmYuLi4ICAgAAAAvLy+lpaVPT08PDw8QEBCGhoYmJiYAAgACHAEIPgMO"
"TQQRVwUTXwYUWwcSVAcMRAQEHQEAAQB/f38gICACKAEKYAMVhgcfpQomswwsvw4wyQ8z"
"yREzxhEwvhAmnA0VbQgFKwKAgICFhYUAEQAERAEPigUbuAklwgsrwQ0uww4yyA81zRE5"
"0xM+2hRD5BZE7hc75BUlqw4NUAWkpKQlJSUADAAFTQIQngUatgggrwoksAsotQwsug0w"
"wQ8zxhA2yxI60BM91RRC3BZH6BlG9hg0zhMTXQhOTk4AEAAESwEOkgQXqgYbpQcfqQok"
"rwtA2hVD3xdI6BhN9ho7yxYUXQgCQQEJlQMRogQWngYaowcfqgpC3hdF4xdK7BlP+Rw3"
"0BQOUQZlZWUAJgAFfgILowMQlwQVnQYapAdI5xhN8RtM+xsqrRAGLgOsrKwtLS0ABAAC"
"VgEGnQMKkwMQlQRK7BpR9hxF7Bkabgp9fX0AGwACbQEGmAMKjwMQlgRJ7BpO8xtU+x0x"
"nhEFHwIANAACfgEGjwNM8BpV+B0/yxcRTAcAOwACggEGjQNT+BxG4RoaYgoAQAAChgEG"
"jANS+BwebQsARgACiwFK8hofcwtK7RppaWkANQA/zBd8fHwHBwcGlwMxnxEFIAKrq6sG"
"nAMabwoLogMqrhCOjo4CQgEJlgMRowRP+Bw40RQPUQZNTU0ETAEOkwQVXggBEQCjo6MQ"
"nwU0zxMUXgiEhIQfHx8ERQEPiwUuwg4yxw850hNC5BY75RUmrA4NUQYfpgonswwswA4w"
"yhAzyhE0yBExwBEnng4VbggFLAICHQEIPwMOTgQSWQYUYAcUXQcTVgcNRgUEHgIAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAABtdwAqfClmbXdQTUIuKigpcG1iLipQfHBhdHIgZWx3"
"dGUga3JwYXJzY2kuKigpZ25wLipGfGdpaGNpIHJlZ2FFUEoqKCBncGouKnzebTjnAAAA"
"AXRSTlMAQObYZgAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAfVJREFUeNpjYIADRiZmFhBg"
"ZmJkwAJY2dg5OCGAg4uNFV2am4eXExnw8XCjyPMLAAUFhYRFRMXEJSSlpIE8AX4keRlZ"
"oIicvIKikrKKqpq6hqYWkC+rDZfXAcrr6ukbGBoZm5iamVtYWlnb6AJVwMywtePktHdw"
"dHJ2cXVz9/D08vbx9fMPsAfaAnVHICdnUHBIaFh4BFRBZFR0TGwc0AweiP+A7o9PSExK"
"ToGZEJmalp6RmQX0C9i32ZycObl5+QWFyAqKiktKyzg52YDy5RWclVXVNbVoCurqGxo5"
"ObmAYdrEwdnc0trWjqago7Oru4eTg4mBgZmTs7evH1PBhImTJnNyMjMwsHFyTpk6DYuC"
"6TNmcnKygBXMmj0Hi4K5dfNgCuYvwKpg4SICJiyGm4DfDUs4OZdi98UyiC+WrwCGw0ps"
"4bBqNTgc1oBCci22kFwnzcleDouL9ZhxsQEaFwwbgbG5afMWtNjcum07JycvJO3uAKan"
"nbvQ08PuPbD0wLAXnKL2oaSo/QeQUhTDwUNAMw4fAabJo8dMj5ufsDx56jRymgRG+SFI"
"qj5z9tz5CxcvXb5yFZSqZZDS/UE7UL64dv3GzVu379y9Jwjk2emg5Jy9O1BzFm+gLXrm"
"25hdsQKWNyuyMfImCKxpYmYDAeamcgYSAADyQe0psesepAAAAABJRU5ErkJggg=="
),
)
#===============================================================================
import os
import wx.lib.masked as maskedlib
import wx.calendar as wxCal
from wx.lib.mixins.listctrl import CheckListCtrlMixin
from eg.WinApi.Dynamic import BringWindowToTop
from calendar import day_name, month_name, monthrange
from datetime import datetime as dt
from datetime import timedelta as td
from time import mktime, strptime, localtime
from copy import deepcopy as cpy
from xml.dom import minidom as miniDom
from win32gui import MessageBox, GetWindowPlacement
from codecs import lookup
from codecs import open as openFile
from winsound import PlaySound, SND_ASYNC
SYS_VSCROLL_X = wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X)
#===============================================================================
class ConfigData(eg.PersistentData):
pos = None
plcmnt = None
class Text:
Suspend = "System session suspend."
Resume = "System session resume."
SessionLock = "System session lock."
SessionUnlock = "System session unlock."
soundProblem = 'A problem was found when trying to open or playing the file "%s"'
label2 = "SchedulGhost.xml folder:"
prefLabel = "Default\nevent prefix:"
browseTitle = "Selected folder:"
toolTipFolder = "Press button and browse to select a folder ..."
boxTitle = 'Folder "%s" is incorrect'
toolTipFile = "Press button and browse to select a logfile ..."
browseFile = 'Select the logfile'
logLabel = "Log scheduler events to the following logfile:"
nextRun = "Next run: %s"
none = "None"
execut = 'Schedule "%s" - Start event triggered. Next time: %s.'
execStop = 'Schedule "%s" - Stop event triggered.'
cancAndDel = 'Schedule "%s" canceled and deleted.'
cancAndDis = 'Schedule "%s" canceled (disabled).'
newSched = 'Schedule "%s" scheduled. Next time: %s.'
re_Sched = 'Schedule "%s" re-scheduled. New next time: %s.'
start = 'SchedulGhost plugin started. All valid schedules will be scheduled:'
stop = 'SchedulGhost plugin stoped. All running schedules and egg timers will be canceled:'
canc = 'Schedule "%s" canceled.'
holidButton_1 = "Public"
holidButton_2 = "holidays ..."
managerButton_1 = "Show SchedulGhost"
managerButton_2 = "manager ... "
fixBoxLabel = "Fixed public holidays:"
varBoxLabel = "Variable public holidays:"
ok = "OK"
cancel = "Cancel"
add = "Add"
delete = "Delete"
first_day = "The first day\nof the week:"
xmlComment = "SchedulGhost configuration file. Updated at %s."
eggStart = 'Egg timer "%s.%s" (%s) started.'
eggElaps = 'Egg timer "%s.%s" - time %s has elapsed.'
eggCancel = 'Egg timer "%s: %s.%s" (%s) canceled.'
popupTitle = 'Egg Timer Popup Window'
popupTip1 = 'Right click to close window and stop playing the sound \nTime elapsed at %s'
popupTip2 = 'Drag-and-move to setup of window position'
mess = """In the folder "%s"
is name "Log.txt" reserved for system logfile of EventGhost.
Change the file name or folder !"""
class ShowSchedulGhost:
dialogTitle = "SchedulGhost"
header = (
"Enabled",
"Schedule title",
"Last run",
"Next run",
)
sched_type = (
"Only once (or yearly)",
"Daily",
"Weekly",
"Monthly / weekday",
"Monthly / day",
"Periodically",
"Time span",
)
serial_num = (
"first",
"second",
"third",
"fourth",
"fifth",
"last"
)
the = "The"
in_ = "in"
buttons = (
"Add new",
"Duplicate",
"Delete",
"OK",
"Cancel",
"Apply"
)
type_label = "Schedule type:"
chooseDay = "Choose day"
theEvery = "The every"
yearly = "Every year on the same day"
chooseTime = "Choose start event time and span"
chooseTime6 = "Choose time span"
choosePeriod = "Choose period"
andThenEvery = "Repeat event every"
units = (
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years",
)
start = "Start event time:"
length = "Span (00:00:00 = only start event):"
boxTitle = "Your setup is not properly configured !"
boxTexts = (
"The schedule title may not be a empty !",
"The schedule title must be unique !",
'A schedule type must be selected !',
'The event prefix may not be empty !',
"The period cannot be shorter than the span !",
)
testButton = "Test now"
testRun = 'Schedule "%s" - TEST execution. Possible next time: %s'
evtPrefix = "Event prefix:"
evtPayload = "Event payload:"
startSuffix = "Start event suffix:"
stopSuffix = "Stop event suffix:"
holidCheck_1 = "Do not trigger events for a chosen day if it happens to be a holiday"
holidCheck_2 = "Do also trigger events for a non-chosen day if it happens to be a holiday"
holidCheck_3 = "Do not trigger events for a chosen day if the next day happens to be a holiday"
holidCheck_4 = "Do also trigger events for a non-chosen day if the next day happens to be a holiday"
#===============================================================================
def Ticks2Delta(start, end):
delta = td(microseconds = 1000000 * (end - start)).seconds
hh = delta / 3600
mm = (delta - 3600 * hh) / 60
ss = delta - 3600 * hh - 60 * mm
return '%02d:%02d:%02d' % (hh, mm, ss)
#===============================================================================
def FindMonthDay(year, month, weekday, index):
"""weekday = what day of the week looking for (numbered 0-6, 0 = monday)
index = how many occurrence of looking for (numbered 0-4 and 5 for the last day)
Returns the day of the month (date) or 0 (if no such date exists)"""
first_wd, length = monthrange(year, month)
day = 1 + weekday - first_wd
if day < 1:
day += 7
if index == 5:
index = 4 if day <= length % 7 else 3
day += 7 * index
if day > length:
day = 0
return day
#===============================================================================
class MySpinIntCtrl(eg.SpinIntCtrl):
def SetNumCtrlId(self, id):
self.numCtrl.SetId(id)
#===============================================================================
class MyDirBrowseButton(eg.DirBrowseButton):
def GetTextCtrl(self): # now I can make build-in textCtrl
return self.textControl # non-editable !!!
#===============================================================================
class MyFileBrowseButton(eg.FileBrowseButton):
def __init__(self,*args,**kwargs):
if 'defaultFile' in kwargs:
self.defaultFile = kwargs['defaultFile']
del kwargs['defaultFile']
else:
self.defaultFile = ""
eg.FileBrowseButton.__init__(self, *args, **kwargs)
def GetValue(self):
if self.textControl.GetValue():
res = self.textControl.GetValue()
else:
res = "%s\\%s" % (self.startDirectory, self.defaultFile)
return res
def GetTextCtrl(self): # now I can make build-in textCtrl
return self.textControl # non-editable !!!
#===============================================================================
class HolidaysFrame(wx.Dialog):
fixWin = None
varWin = None
fixHolidays = []
varHolidays = []
def __init__(self, parent, plugin):
self.plugin = plugin
wx.Dialog.__init__(
self,
parent,
-1,
style = wx.DEFAULT_DIALOG_STYLE,
name = self.plugin.text.holidButton_1+" "+self.plugin.text.holidButton_2
)
self.SetIcon(self.plugin.info.icon.GetWxIcon())
self.panel = parent
self.fixHolidays, self.varHolidays = cpy(self.panel.holidays)
self.Bind(wxCal.EVT_CALENDAR_DAY, self.OnChangeDay)
def ShowHolidaysFrame(self):
text = self.plugin.text
self.SetTitle(self.plugin.text.holidButton_1+" "+self.plugin.text.holidButton_2)
self.fixWin = CalendarPopup(self, False, self.plugin.first_day)
self.varWin = CalendarPopup(self, True, self.plugin.first_day)
calW, calH = self.fixWin.GetWinSize()
fixLbl = wx.StaticText(self, -1, text.fixBoxLabel)
variableLbl = wx.StaticText(self, -1, text.varBoxLabel)
widthList = [self.GetTextExtent("30. %s 2000" % month)[0] +
SYS_VSCROLL_X for month in list(month_name)]
widthList.append(fixLbl.GetSize()[0])
widthList.append(variableLbl.GetSize()[0])
w = max(widthList) + 5
self.SetMinSize((w + calW + 30, 2 * calH + 128))
self.fixListBox = HolidaysBox(
self,
-1,
size = wx.Size(w, 130),
style = wx.LB_SINGLE|wx.LB_NEEDED_SB
)
self.fix_add_Btn = wx.Button(self, -1, text.add)
self.fix_del_Btn = wx.Button(self, -1, text.delete)
self.fix_del_Btn.Enable(False)
self.varListBox = HolidaysBox(
self,
-1,
size = wx.Size(w, 130),
style = wx.LB_SINGLE|wx.LB_NEEDED_SB
)
self.var_add_Btn = wx.Button(self, -1, text.add)
self.var_del_Btn = wx.Button(self, -1, text.delete)
self.var_del_Btn.Enable(False)
line = wx.StaticLine(self, -1, style = wx.LI_HORIZONTAL)
sizer = wx.BoxSizer(wx.VERTICAL)
fixSizer = wx.GridBagSizer(2, 8)
fixSizer.SetMinSize((w + 8 + calW, -1))
varSizer = wx.GridBagSizer(2, 8)
varSizer.SetMinSize((w + 8 + calW, -1))
fixSizer.Add(fixLbl, (0, 0))
fixSizer.Add(self.fixListBox, (1, 0), (3, 1))
fixSizer.Add(self.fix_add_Btn, (1, 1))
fixSizer.Add((-1, 15), (2, 1))
fixSizer.Add(self.fix_del_Btn, (3, 1))
varSizer.Add(variableLbl, (0, 0))
varSizer.Add(self.varListBox, (1, 0), (3,1))
varSizer.Add(self.var_add_Btn, (1, 1))
varSizer.Add((-1, 15), (2, 1))
varSizer.Add(self.var_del_Btn, (3, 1))
sizer.Add(fixSizer, 0, wx.EXPAND|wx.ALL, 8)
sizer.Add((-1, 12))
sizer.Add(varSizer, 0, wx.EXPAND|wx.ALL, 8)
sizer.Add((1, 16))
btn1 = wx.Button(self, wx.ID_OK)
btn1.SetLabel(text.ok)
btn1.SetDefault()
btn2 = wx.Button(self, wx.ID_CANCEL)
btn2.SetLabel(text.cancel)
btnsizer = wx.StdDialogButtonSizer()
btnsizer.AddButton(btn1)
btnsizer.AddButton(btn2)
btnsizer.Realize()
sizer.Add(line, 0, wx.EXPAND)
sizer.Add((1,5))
sizer.Add(btnsizer, 0, wx.EXPAND|wx.RIGHT, 10)
sz = self.GetMinSize()
self.SetSize(sz)
self.fixListBox.Reset(self.fixHolidays)
self.varListBox.Reset(self.varHolidays)
self.Bind(wx.EVT_CLOSE, self.onClose)
btn2.Bind(wx.EVT_BUTTON, self.onCancel)
btn1.Bind(wx.EVT_BUTTON, self.onOK)
self.fix_add_Btn.Bind(wx.EVT_BUTTON, self.onFixAddBtn)
self.var_add_Btn.Bind(wx.EVT_BUTTON, self.onVarAddBtn)
self.fix_del_Btn.Bind(wx.EVT_BUTTON, self.onFixDelBtn)
self.var_del_Btn.Bind(wx.EVT_BUTTON, self.onVarDelBtn)
self.Bind(wx.EVT_LISTBOX, self.onHolBoxSel)
sizer.Layout()
self.SetSizer(sizer)
self.MakeModal(True)
self.Show(True)
def onClose(self, evt):
self.MakeModal(False)
self.GetParent().GetParent().Raise()
self.Destroy()
def onCancel(self, evt):
self.Close()
def onOK(self, evt):
self.panel.holidays = (self.fixHolidays, self.varHolidays)
self.Close()
def onHolBoxSel(self, evt):
if evt.GetId() == self.fixListBox.GetId():
self.fix_del_Btn.Enable(True)
else:
self.var_del_Btn.Enable(True)
evt.Skip()
def onFixAddBtn(self, evt):
pos = self.ClientToScreen(self.fix_add_Btn.GetPosition())
self.fixWin.PopUp(pos, self.fixHolidays)
def onVarAddBtn(self, evt):
pos = self.ClientToScreen(self.var_add_Btn.GetPosition())
self.varWin.PopUp(pos, self.varHolidays)
def onFixDelBtn(self, evt):
self.fixHolidays.pop(self.fixListBox.GetSelection())
if self.fixListBox.Reset(self.fixHolidays):
self.fix_del_Btn.Enable(False)
def onVarDelBtn(self, evt):
self.varHolidays.pop(self.varListBox.GetSelection())
if self.varListBox.Reset(self.varHolidays):
self.var_del_Btn.Enable(False)
def OnChangeDay(self, evt):
if evt.GetId() == self.fixWin.GetCalId():
self.fixListBox.Reset(self.fixHolidays)
else:
self.varListBox.Reset(self.varHolidays)
evt.Skip()
#===============================================================================
class HolidaysBox(wx.ListBox):
def __init__ (self, parent, id, size, style):
wx.ListBox.__init__(
self,
parent = parent,
id = id,
size = size,
style = style
)
self.sel = -1
self.Bind(wx.EVT_LISTBOX, self.onHolBoxSel)
def Reset(self, list):
tmpList = []
for item in list:
day = item[-1]
day = " %i" % day if day < 10 else "%i" % day
if len(item) == 2:
tmpList.append("%s. %s" % (day, month_name[item[0]]))
else:
tmpList.append("%s. %s %i" % (day, month_name[item[1]], item[0]))
self.Set(tmpList)
if self.sel > -1 and self.sel < self.GetCount():
self.SetSelection(self.sel)
return False
else:
return True
def onHolBoxSel(self, evt):
self.sel = evt.GetSelection()
evt.Skip()
#===============================================================================
class CalendarPopup(wx.PopupWindow):
yearChange = True
def __init__(self, parent, yearChange, first_day):
self.yearChange = yearChange
wx.PopupWindow.__init__(self, parent)
startDate = wx.DateTime()
startDate.Set(1, 0)
self.cal = wxCal.GenericCalendarCtrl(
self,
-1,
startDate,
style = (wxCal.CAL_MONDAY_FIRST, wxCal.CAL_SUNDAY_FIRST)[first_day]
| wxCal.CAL_SHOW_HOLIDAYS
| wxCal.CAL_SEQUENTIAL_MONTH_SELECTION
| wxCal.CAL_SHOW_SURROUNDING_WEEKS
)
self.cal.EnableYearChange(yearChange)
sz = self.cal.GetBestSize()
self.SetSize(sz)
self.cal.Bind(wxCal.EVT_CALENDAR_DAY, self.OnChangeDay)
self.cal.Bind(wxCal.EVT_CALENDAR_MONTH, self.OnChangeMonth)
self.cal.Bind(wxCal.EVT_CALENDAR_YEAR, self.OnChangeMonth)
self.cal.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
def OnLeaveWindow(self, evt):
self.PopDown()
evt.Skip()
def GetCalId(self):
return self.cal.GetId()
def GetWinSize(self):
return self.GetSize()
def OnChangeDay(self, evt):
date = evt.GetDate()
day, month, year = date.GetDay(), 1 + date.GetMonth(), date.GetYear()
newHoliday = (year, month, day) if self.yearChange else (month, day)
if not newHoliday in self.holidays:
self.holidays.append(newHoliday)
self.holidays.sort()
date = self.cal.GetDate()
self.cal.SetHoliday(day)
date.AddDS(wx.DateSpan.Day())
self.cal.SetDate(date)
self.Refresh()
evt.Skip()
def OnChangeMonth(self, evt = None):
date = self.cal.GetDate()
cur_month = date.GetMonth() + 1 # convert wx.DateTime 0-11 => 1-12
if self.yearChange:
cur_year = date.GetYear()
for year, month, day in self.holidays:
if year == cur_year and month == cur_month:
self.cal.SetHoliday(day)
else:
for month, day in self.holidays:
if month == cur_month:
self.cal.SetHoliday(day)
def PopUp(self, position, holidays):
self.cal.EnableHolidayDisplay(False)
self.cal.EnableHolidayDisplay(True)
self.SetPosition(position)
self.holidays = holidays
self.OnChangeMonth()
self.Show(True)
def PopDown(self):
self.Show(False)
self.Close()
#===============================================================================
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin):
def __init__(self, parent, text, width):
wx.ListCtrl.__init__(
self,
parent,
-1,
size = (width, -1),
style = wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES|wx.LC_SINGLE_SEL
)
self.selRow = -1
self.back = self.GetBackgroundColour()
self.fore = self.GetForegroundColour()
self.selBack = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
self.selFore = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
for i in range(len(text.header)):
self.InsertColumn(i, text.header[i])
self.SetColumnWidth(0, wx.LIST_AUTOSIZE_USEHEADER)
self.SetColumnWidth(
1,
width - self.GetColumnWidth(0) - 2 * 116 - SYS_VSCROLL_X - self.GetWindowBorderSize()[0]
)
self.SetColumnWidth(2, 116)
self.SetColumnWidth(3, 116)
CheckListCtrlMixin.__init__(self)
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
def OnItemSelected(self, evt):
self.SelRow(evt.m_itemIndex)
evt.Skip()
# this is called by the base class when an item is checked/unchecked !!!!!!!
def OnCheckItem(self, index, flag):
evt = eg.ValueChangedEvent(self.GetId(), value = (index, flag))
wx.PostEvent(self, evt)
def SelRow(self, row):
if row != self.selRow:
if self.selRow in range(self.GetItemCount()):
item = self.GetItem(self.selRow)
item.SetTextColour(self.fore)
item.SetBackgroundColour(self.back)
self.SetItem(item)
self.selRow = row
if self.GetItemBackgroundColour(row) != self.selBack:
item = self.GetItem(row)
item.SetTextColour(self.selFore)
item.SetBackgroundColour(self.selBack)
self.SetItem(item)
self.SetItemState(row, 0, wx.LIST_STATE_SELECTED)
def AppendRow(self):
ix = self.GetItemCount()
self.InsertStringItem(ix, "")
self.CheckItem(ix)
self.EnsureVisible(ix)
self.SelRow(ix)
#===============================================================================
class schedulerDialog(wx.Dialog):
lastRow = -1
data = []
def __init__(self, text, plugin):
wx.Dialog.__init__(
self,
None,
-1,
text.dialogTitle,
style = wx.DEFAULT_DIALOG_STYLE|wx.MINIMIZE_BOX|wx.CLOSE_BOX,
)
# import locale as l
# l.setlocale(l.LC_ALL, "us") # only for testing !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
bttns = []
self.ctrls = []
self.plugin = plugin
self.SetIcon(self.plugin.info.icon.GetWxIcon())
self.plugin.dialog = self
self.tmpData = self.plugin.tmpData = cpy(self.plugin.data)
self.text = text
dynamicSizer = wx.BoxSizer(wx.VERTICAL)
typeSizer = wx.StaticBoxSizer(
wx.StaticBox(self, -1, ""),
wx.VERTICAL
)
sizer = wx.BoxSizer(wx.VERTICAL)
def fillDynamicSizer(type, data = None, old_type = 255):
flag = old_type != type
if flag:
dynamicSizer.Clear(True)
self.ctrls = []
self.ctrls.append(wx.NewId())
self.ctrls.append(wx.NewId())
if type == -1:
return
if type != 1 and type != 6 and flag:
topSizer = wx.StaticBoxSizer(
wx.StaticBox(self, -1, self.text.chooseDay),
wx.HORIZONTAL
)
if type == 0:
if flag:
self.ctrls.append(wx.NewId())
dp = wx.DatePickerCtrl(self, self.ctrls[2], size = (86, -1),
style = wx.DP_DROPDOWN | wx.DP_SHOWCENTURY)
topSizer.Add(dp,0,wx.EXPAND)
self.ctrls.append(wx.NewId())
yearlyCtrl = wx.CheckBox(self, self.ctrls[3], self.text.yearly)
topSizer.Add(yearlyCtrl, 0, wx.EXPAND|wx.LEFT, 30)
dynamicSizer.Add(topSizer, 0, wx.EXPAND|wx.TOP, 2)
else:
dp = wx.FindWindowById(self.ctrls[2])
yearlyCtrl = wx.FindWindowById(self.ctrls[3])
if data:
if not data[2]:
val = wx.DateTime_Now()
data[2] = str(dt.now())[:10]
wxDttm = wx.DateTime()
wxDttm.Set(
int(data[2][8:10]),
int(data[2][5:7]) - 1,
int(data[2][:4])
)
dp.SetValue(wxDttm)
yearlyCtrl.SetValue(data[3])
elif type == 2:
if flag:
if self.plugin.first_day:
choices = list(day_name)[:-1]
choices.insert(0, list(day_name)[-1])
else:
choices = list(day_name)
self.ctrls.append(wx.NewId())
weekdayCtrl = wx.CheckListBox(
self,
self.ctrls[2],
choices = choices,
)
self.ctrls.append(wx.NewId())
holidCheck_2 = wx.CheckBox(
self,
self.ctrls[3],
self.text.holidCheck_2
)
self.ctrls.append(wx.NewId())
holidCheck_1 = wx.CheckBox(
self,
self.ctrls[4],
self.text.holidCheck_1
)
self.ctrls.append(wx.NewId())
holidCheck_4 = wx.CheckBox(
self,
self.ctrls[5],
self.text.holidCheck_4
)
self.ctrls.append(wx.NewId())
holidCheck_3 = wx.CheckBox(
self,
self.ctrls[6],
self.text.holidCheck_3
)
topSizer.Add((40,1), 0, wx.ALIGN_CENTER)
topSizer.Add(
wx.StaticText(
self,
-1,
self.text.theEvery
),
0,
wx.ALIGN_CENTER | wx.RIGHT, 10
)
topSizer.Add(weekdayCtrl, 0, wx.TOP)
dynamicSizer.Add(topSizer, 0, wx.EXPAND | wx.TOP,2)
dynamicSizer.Add(holidCheck_1, 0, wx.TOP, 2)
dynamicSizer.Add(holidCheck_2, 0, wx.TOP, 2)
dynamicSizer.Add(holidCheck_3, 0, wx.TOP, 2)
dynamicSizer.Add(holidCheck_4, 0, wx.TOP, 2)
else:
weekdayCtrl = wx.FindWindowById(self.ctrls[2])
holidCheck_2 = wx.FindWindowById(self.ctrls[3])
holidCheck_1 = wx.FindWindowById(self.ctrls[4])
holidCheck_4 = wx.FindWindowById(self.ctrls[5])
holidCheck_3 = wx.FindWindowById(self.ctrls[6])
val = 127 if not data else data[2]
if self.plugin.first_day:
exp = [6, 0, 1, 2, 3, 4, 5]
else:
exp = [0, 1, 2, 3, 4, 5, 6]
for i in range(7):
weekdayCtrl.Check(i, bool(val & (2 ** exp[i])))
enable = data[3]==0
holidCheck_1.Enable(enable)
check = 0 if (not data or not enable) else data[4]
holidCheck_1.SetValue(check)
if enable:
enable = data[4]==0
else:
enable = True
holidCheck_2.Enable(enable)
check = 0 if (not data or not enable) else data[3]
holidCheck_2.SetValue(check)
enable = data[5]==0
holidCheck_3.Enable(enable)
check = 0 if (not data or not enable) else data[6]
holidCheck_3.SetValue(check)
if enable:
enable = data[6]==0
else:
enable = True
holidCheck_4.Enable(enable)
check = 0 if (not data or not enable) else data[5]
holidCheck_4.SetValue(check)
elif type == 3: # Monthly/weekday ...
if flag:
dateSizer = wx.BoxSizer(wx.HORIZONTAL)
dateSizer.Add(
wx.StaticText(
self,
-1,
self.text.the
),
0,
wx.ALIGN_CENTER
)
topSizer.Add(dateSizer, 0, wx.EXPAND)
dynamicSizer.Add(topSizer, 0, wx.EXPAND | wx.TOP,2)
self.ctrls.append(wx.NewId())
serialCtrl = wx.CheckListBox(
self,
self.ctrls[2],
choices = self.text.serial_num,
)
dateSizer.Add(serialCtrl, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
if self.plugin.first_day:
choices = list(day_name)[0:-1]
choices.insert(0, list(day_name)[-1])
else:
choices = list(day_name)
self.ctrls.append(wx.NewId())
weekdayCtrl = wx.CheckListBox(
self,
self.ctrls[3],
choices = choices,
)
dateSizer.Add(weekdayCtrl, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
dateSizer.Add(
wx.StaticText(
self,
-1,
self.text.in_
),
0,
wx.ALIGN_CENTER | wx.LEFT, 10
)
self.ctrls.append(wx.NewId())
monthsCtrl_1 = wx.CheckListBox(
self,
self.ctrls[4],
choices = list(month_name)[1:7],
)
dateSizer.Add(monthsCtrl_1, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
self.ctrls.append(wx.NewId())
monthsCtrl_2 = wx.CheckListBox(
self,
self.ctrls[5],
choices = list(month_name)[7:],
)
dateSizer.Add(monthsCtrl_2, 0, wx.ALIGN_CENTER | wx.LEFT, -1)
self.ctrls.append(wx.NewId())
holidCheck_1 = wx.CheckBox(
self,
self.ctrls[6],
self.text.holidCheck_1
)
dynamicSizer.Add(holidCheck_1, 0, wx.TOP, 2)
self.ctrls.append(wx.NewId())
holidCheck_3 = wx.CheckBox(
self,
self.ctrls[7],
self.text.holidCheck_3
)
dynamicSizer.Add(holidCheck_3, 0, wx.TOP, 2)
else:
serialCtrl = wx.FindWindowById(self.ctrls[2])
weekdayCtrl = wx.FindWindowById(self.ctrls[3])
monthsCtrl_1 = wx.FindWindowById(self.ctrls[4])
monthsCtrl_2 = wx.FindWindowById(self.ctrls[5])
holidCheck_1 = wx.FindWindowById(self.ctrls[6])
holidCheck_3 = wx.FindWindowById(self.ctrls[7])
val = 0 if not data else data[2]
for i in range(6):
serialCtrl.Check(i, bool(val & (2 ** i)))
val = 0 if not data else data[3]
if self.plugin.first_day:
exp = [6, 0, 1, 2, 3, 4, 5]
else:
exp = [0, 1, 2, 3, 4, 5, 6]
for i in range(7):
weekdayCtrl.Check(i, bool(val & (2 ** exp[i])))
val = 63 if not data else data[4]
for i in range(6):
monthsCtrl_1.Check(i, bool(val & (2 ** i)))
val = 63 if not data else data[5]
for i in range(6):
monthsCtrl_2.Check(i, bool(val & (2 ** i)))
enable = True
holidCheck_1.Enable(enable)
check = 0 if (not data or not enable) else data[6]
holidCheck_1.SetValue(check)
enable = True
holidCheck_3.Enable(enable)
check = 0 if (not data or not enable) else data[7]
holidCheck_3.SetValue(check)
elif type == 4: # Monthly/day ...
if flag:
dateSizer = wx.BoxSizer(wx.HORIZONTAL)
topSizer.Add(dateSizer, 0, wx.EXPAND)
dynamicSizer.Add(topSizer, 0, wx.EXPAND | wx.TOP, 2)
self.ctrls.append(wx.NewId())
q_1_Ctrl = wx.CheckListBox(
self,
self.ctrls[2],
choices = [str(i) + '.' for i in range(1, 9)],
)
dateSizer.Add(q_1_Ctrl, 0, wx.LEFT, 5)
self.ctrls.append(wx.NewId())
q_2_Ctrl = wx.CheckListBox(
self,
self.ctrls[3],
choices = [str(i) + '.' for i in range(9, 17)],
)
dateSizer.Add(q_2_Ctrl, 0, wx.LEFT, -1)
self.ctrls.append(wx.NewId())
q_3_Ctrl = wx.CheckListBox(
self,
self.ctrls[4],
choices = [str(i) + '.' for i in range(17, 25)],
)
dateSizer.Add(q_3_Ctrl, 0, wx.LEFT, -1)
self.ctrls.append(wx.NewId())
q_4_Ctrl = wx.CheckListBox(
self,
self.ctrls[5],
choices = [str(i) + '.' for i in range(25, 32)],
)
dateSizer.Add(q_4_Ctrl, 0, wx.LEFT, -1)
dateSizer.Add((-1, 1), 1, wx.EXPAND)
self.ctrls.append(wx.NewId())
monthsCtrl_1 = wx.CheckListBox(
self,
self.ctrls[6],
choices = list(month_name)[1:7],
)
dateSizer.Add(monthsCtrl_1, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
self.ctrls.append(wx.NewId())
monthsCtrl_2 = wx.CheckListBox(
self,
self.ctrls[7],
choices = list(month_name)[7:],
)
dateSizer.Add(monthsCtrl_2, 0, wx.ALIGN_CENTER | wx.LEFT, -1)
dateSizer.Add((5, 1), 0)
else:
q_1_Ctrl = wx.FindWindowById(self.ctrls[2])
q_2_Ctrl = wx.FindWindowById(self.ctrls[3])
q_3_Ctrl = wx.FindWindowById(self.ctrls[4])
q_4_Ctrl = wx.FindWindowById(self.ctrls[5])
monthsCtrl_1 = wx.FindWindowById(self.ctrls[6])
monthsCtrl_2 = wx.FindWindowById(self.ctrls[7])
val = 0 if not data else data[2]
for i in range(8):
q_1_Ctrl.Check(i, bool(val & (2 ** i)))
val = 0 if not data else data[3]
for i in range(8):
q_2_Ctrl.Check(i, bool(val & (2 ** i)))
val = 0 if not data else data[4]
for i in range(8):
q_3_Ctrl.Check(i, bool(val & (2 ** i)))
val = 0 if not data else data[5]
for i in range(7):
q_4_Ctrl.Check(i, bool(val & (2 ** i)))
val = 63 if not data else data[6]
for i in range(6):
monthsCtrl_1.Check(i, bool(val & (2 ** i)))
val = 63 if not data else data[7]
for i in range(6):
monthsCtrl_2.Check(i, bool(val & (2 ** i)))
elif type == 5:
if flag:
self.ctrls.append(wx.NewId())
dp = wx.DatePickerCtrl(self, self.ctrls[2], size = (86, -1),
style = wx.DP_DROPDOWN | wx.DP_SHOWCENTURY)
topSizer.Add(dp, 0, wx.EXPAND)
dynamicSizer.Add(topSizer, 0, wx.EXPAND | wx.TOP, 2)
else:
dp = wx.FindWindowById(self.ctrls[2])
if data:
if not data[2]:
val = wx.DateTime_Now()
data[2] = str(dt.now())[:10]
wxDttm = wx.DateTime()
wxDttm.Set(
int(data[2][8:10]),
int(data[2][5:7])-1,
int(data[2][:4])
)
dp.SetValue(wxDttm)
elif type == 6: # timer
stEvLbl = None
#elif type == 1: # daily
# pass
if flag:
timeSizer = wx.GridBagSizer(0, 0)
bottomSizer = wx.StaticBoxSizer(
wx.StaticBox(self, -1, self.text.chooseTime6 if type == 6 else self.text.chooseTime),
wx.HORIZONTAL
)
dynamicSizer.Add(bottomSizer, 0, wx.EXPAND | wx.TOP, 16 if type != 2 else 5)
bottomSizer.Add(timeSizer, 0, wx.EXPAND)
stEvLbl = wx.StaticText(self, -1, self.text.start)
timeSizer.Add(stEvLbl, (0, 0), (1, 2))
durLabel = wx.StaticText(self, -1, self.text.length)
timeSizer.Add(durLabel, (0, 3), (1, 2))
spinBtn = wx.SpinButton(
self,
-1,
wx.DefaultPosition,
(-1, 22),
wx.SP_VERTICAL
)
initTime = wx.DateTime_Now()
initTime.SetSecond(0)
initTime.AddTS(wx.TimeSpan.Minute())
val = data[0] if data and data[0] else initTime
timeCtrl = eg.TimeCtrl(
self,
self.ctrls[0],
val,
fmt24hr = True,
spinButton = spinBtn
)
timeSizer.Add(timeCtrl, (1, 0), (1, 1))
timeSizer.Add(spinBtn, (1, 1), (1, 1))
timeSizer.Add((40, -1), (1, 2), (1, 1))
spinBtn2 = wx.SpinButton(
self,
-1,
wx.DefaultPosition,
(-1, 22),
wx.SP_VERTICAL
)
val = data[1] if data and data[1] else "00:00:00"
lenCtrl = eg.TimeCtrl_Duration(
self,
self.ctrls[1],
val,
fmt24hr = True,
spinButton = spinBtn2
)
timeSizer.Add(lenCtrl, (1, 3), (1, 1))
timeSizer.Add(spinBtn2, (1, 4), (1, 1))
bottomSizer.Add((-1,-1), 1, wx.EXPAND)
testBttn = wx.Button(
self,
-1 if len(bttns) == 0 else bttns[-1],
self.text.testButton
)
bottomSizer.Add(testBttn, 0, wx.EXPAND | wx.RIGHT)
else:
timeCtrl = wx.FindWindowById(self.ctrls[0])
val = data[0] if data and data[0] else wx.DateTime_Now()
timeCtrl.SetValue(val)
lenCtrl = wx.FindWindowById(self.ctrls[1])
val = data[1] if data and data[1] else "00:00:00"
lenCtrl.SetValue(val)
OnTimeChange() #enable / disable handle for duplicate
if type == 5: #periodically
if flag:
bottomSizer = wx.StaticBoxSizer(
wx.StaticBox(self, -1, self.text.choosePeriod),
wx.HORIZONTAL
)
self.ctrls.append(wx.NewId())
numCtrl = MySpinIntCtrl(self, -1, value = 1, min = 1)
numCtrl.SetNumCtrlId(self.ctrls[3])
bottomSizer.Add(
wx.StaticText(
self,
-1,
self.text.andThenEvery
),
0,
wx.ALIGN_CENTER
)
bottomSizer.Add(numCtrl, 0, wx.LEFT, 4)
self.ctrls.append(wx.NewId())
unitCtrl = wx.Choice(
self,
self.ctrls[4],
choices = self.text.units
)
bottomSizer.Add(unitCtrl, 0, wx.LEFT, 8)
dynamicSizer.Add(bottomSizer, 0, wx.EXPAND|wx.TOP, 16)
self.Fit()
else:
numCtrl = wx.FindWindowById(self.ctrls[3])
unitCtrl = wx.FindWindowById(self.ctrls[4])
if data:
numCtrl.SetValue(data[3])
unitCtrl.SetSelection(data[4])
elif flag:
self.Fit()
if type == 6:
if stEvLbl:
stEvLbl.Show(False)
timeCtrl.Show(False)
spinBtn.Show(False)
def Diff():
applyBttn = wx.FindWindowById(bttns[5])
flg = self.tmpData != self.plugin.data
applyBttn.Enable(flg)
def onCheckListBox(evt):
id = evt.GetId()
sel = evt.GetSelection()
box = self.FindWindowById(id)
ix = self.ctrls.index(id)
type = self.tmpData[self.lastRow][2]
cond = (type == 2 and ix == 2) or (type == 3 and ix == 3)
if cond and self.plugin.first_day:
exp = (6, 0, 1, 2, 3, 4, 5)[sel]
else:
exp = sel
if box.IsChecked(sel):
self.tmpData[self.lastRow][3][ix] |= 2 ** exp
else:
self.tmpData[self.lastRow][3][ix] &= 255 - 2 ** exp
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
Diff()
def OnTimeChange(evt = None):
if evt:
ix = self.ctrls.index(evt.GetId())
self.tmpData[self.lastRow][3][ix] = evt.GetValue()
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
else:
ix = 1
if ix == 1:
enable = self.tmpData[self.lastRow][3][1] != "00:00:00"
stopLabel.Enable(enable)
stopCtrl.Enable(enable)
stopTxt = self.tmpData[self.lastRow][7] if enable else ""
stopCtrl.ChangeValue(stopTxt)
Diff()
def onPeriodUnit(evt):
if len(self.ctrls) == 5 and evt.GetId() == self.ctrls[4]:
self.tmpData[self.lastRow][3][4] = evt.GetSelection()
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
else:
evt.Skip()
Diff()
def onDatePicker(evt):
val = str(dt.fromtimestamp(evt.GetDate().GetTicks()))[:10]
self.tmpData[self.lastRow][3][2] = val
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
Diff()
def onCheckBox(evt):
val = evt.IsChecked()
ix = self.ctrls.index(evt.GetId())
type = self.tmpData[self.lastRow][2]
if type == 2:
if ix == 3 or ix == 5:
self.tmpData[self.lastRow][3][ix] = int(val)
holidCheck_2 = wx.FindWindowById(self.ctrls[4])
holidCheck_4 = wx.FindWindowById(self.ctrls[6])
if int(val) == 1:
self.tmpData[self.lastRow][3][4] = 0
holidCheck_2.SetValue(0)
holidCheck_2.Enable(False)
self.tmpData[self.lastRow][3][6] = 0
holidCheck_4.SetValue(0)
holidCheck_4.Enable(False)
elif self.tmpData[self.lastRow][3][3] == 0 and self.tmpData[self.lastRow][3][5] == 0:
holidCheck_2.Enable(True)
holidCheck_4.Enable(True)
elif ix == 4 or ix == 6:
self.tmpData[self.lastRow][3][4] = int(val)
holidCheck_1 = wx.FindWindowById(self.ctrls[3])
holidCheck_3 = wx.FindWindowById(self.ctrls[5])
if int(val) == 1:
self.tmpData[self.lastRow][3][3] = 0
holidCheck_1.SetValue(0)
holidCheck_1.Enable(False)
self.tmpData[self.lastRow][3][5] = 0
holidCheck_3.SetValue(0)
holidCheck_3.Enable(False)
elif self.tmpData[self.lastRow][3][4] == 0 and self.tmpData[self.lastRow][3][6] == 0:
holidCheck_1.Enable(True)
holidCheck_3.Enable(True)
else:
self.tmpData[self.lastRow][3][ix] = int(val)
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
Diff()
def OnUpdateDialog(evt):
if self.lastRow == evt.GetId():
OpenSchedule()
def OnSelectCell(evt):
self.lastRow = evt.m_itemIndex
OpenSchedule()
Diff()
evt.Skip() # necessary !!!
def enableBttns(value):
for i in (1, 2):
bttn = self.FindWindowById(bttns[i])
bttn.Enable(value)
if not value:
bttn = self.FindWindowById(bttns[5])
bttn.Enable(False)
def FindNewTitle(title):
tmpLst = []
for item in self.tmpData:
if item[1].startswith(title + " ("):
tmpLst.append(item[1][2 + len(title):])
if len(tmpLst) == 0:
return "%s (1)" % title
tmpLst2 = []
for item in tmpLst:
if item[-1] == ")":
try:
tmpLst2.append(int(item[:-1]))
except:
pass
if len(tmpLst2) == 0:
return "%s (1)" % title
else:
return "%s (%i)" % (title, 1 + max(tmpLst2))
def testValidity(data, test):
mssgs = []
if test:
data = [data, ]
tempDict = dict([(item[1].strip(), item[2]) for item in data])
if "" in tempDict:
mssgs.append(self.text.boxTexts[0])
if not test and len(tempDict) < len(data):
mssgs.append(self.text.boxTexts[1])
if "" in [item[5].strip() for item in data]:
mssgs.append(self.text.boxTexts[3])
if -1 in [item[2] for item in data]:
mssgs.append(self.text.boxTexts[2])
for item in data:
if item[2] == 5 and item[3][4] < 4:
period = item[3][3] * (1, 60, 3600, 86400)[item[3][4]]
span = int(item[3][1][6:]) + 60 * int(item[3][1][3:5]) + 3600 * int(item[3][1][:2])
if period <= span:
if self.text.boxTexts[4] not in mssgs:
mssgs.append(self.text.boxTexts[4])
break
res = len(mssgs)
if res:
PlaySound('SystemExclamation', SND_ASYNC)
MessageBox(
self.GetHandle(),
"\n".join(mssgs),
self.text.boxTitle,
48
)
return res
def onButton(evt):
id = evt.GetId()
lngth = len(self.tmpData)
if id == bttns[0]: # Add new
empty = [1, "", -1, [], "", self.plugin.prefix, "", "", ""]
self.lastRow = lngth
self.tmpData.append(empty)
if lngth == 0:
enableBttns(True)
else:
Tidy()
grid.AppendRow()
prefixCtrl.ChangeValue(self.plugin.prefix)
grid.SelRow(self.lastRow)
EnableCtrls(True)
elif id == bttns[1]: # Duplicate
item = cpy(self.tmpData[self.lastRow])
item[4] = ""
self.lastRow = lngth
self.tmpData.append(item)
newTitle = FindNewTitle(self.tmpData[lngth][1])
self.tmpData[lngth][1] = newTitle
grid.AppendRow()
grid.SelRow(lngth)
grid.SetStringItem(lngth, 1, newTitle)
OpenSchedule()
elif id == bttns[2]: # Delete
self.tmpData.pop(self.lastRow)
grid.DeleteItem(self.lastRow)
if len(self.tmpData) > 0:
if self.lastRow == len(self.tmpData):
self.lastRow -= 1
OpenSchedule()
grid.SelRow(self.lastRow)
else:
self.lastRow = -1
Tidy()
EnableCtrls(False)
enableBttns(False)
elif id == bttns[3]: # OK
if testValidity(self.tmpData, False):
return
self.plugin.data = cpy(self.tmpData)
self.tmpData = []
self.plugin.dataToXml()
self.plugin.UpdateEGscheduler()
self.Close()
elif id == bttns[4]: # Cancel
self.tmpData = []
self.Close()
elif id == bttns[5]: # Apply
applyBttn = wx.FindWindowById(bttns[5])
applyBttn.Enable(False)
if testValidity(self.tmpData, False):
return
for i in range(len(self.tmpData)):
next = self.plugin.NextRun(
self.tmpData[i][2],
self.tmpData[i][3]
)
grid.SetStringItem(i, 3, next)
self.plugin.data = cpy(self.tmpData)
self.plugin.dataToXml()
self.plugin.UpdateEGscheduler()
def EnableCtrls(value):
typeChoice.Enable(value)
schedulerName.Enable(value)
name_label.Enable(value)
type_label.Enable(value)
prefixCtrl.Enable(value)
prefixLabel.Enable(value)
startCtrl.Enable(value)
startLabel.Enable(value)
payloadCtrl.Enable(value)
payloadLabel.Enable(value)
if not value:
stopCtrl.Enable(False)
stopLabel.Enable(False)
def OpenSchedule():
schedulerName.ChangeValue(self.tmpData[self.lastRow][1])
prefixCtrl.ChangeValue(self.tmpData[self.lastRow][5])
startCtrl.ChangeValue(self.tmpData[self.lastRow][6])
stopCtrl.ChangeValue(self.tmpData[self.lastRow][7])
payloadCtrl.ChangeValue(self.tmpData[self.lastRow][8])
type = self.tmpData[self.lastRow][2]
fillDynamicSizer(
type,
self.tmpData[self.lastRow][3],
typeChoice.GetSelection()
)
typeChoice.SetSelection(type)
def Tidy():
typeChoice.SetSelection(-1)
schedulerName.ChangeValue("")
fillDynamicSizer(-1)
prefixCtrl.ChangeValue("")
startCtrl.ChangeValue("")
stopCtrl.ChangeValue("")
payloadCtrl.ChangeValue("")
def onCheckListCtrl(evt):
index, flag = evt.GetValue()
if self.tmpData[index][0] != int(flag):
self.tmpData[index][0] = int(flag)
Diff()
def onSchedulerTitle(evt):
txt = evt.GetString()
grid.SetStringItem(self.lastRow, 1, txt)
self.tmpData[self.lastRow][1] = txt
Diff()
def onTypeChoice(evt):
type = evt.GetSelection()
if self.tmpData[self.lastRow][2] != type:
empty_data = [
["", "", 0, 0],
["", ""],
["", "", 127, 0, 0, 0, 0],
["", "", 0, 0, 63, 63, 0, 0],
["", "", 0, 0, 0, 0, 63, 63],
["", "", 0, 1, 0],
["", ""],
]
self.tmpData[self.lastRow][2] = type
data = empty_data[self.tmpData[self.lastRow][2]]
self.tmpData[self.lastRow][3] = data
fillDynamicSizer(type, data)
Diff()
def onPeriodNumber(evt):
if len(self.ctrls) == 5 and evt.GetId() == self.ctrls[3]:
self.tmpData[self.lastRow][3][3] = int(evt.GetString())
next = self.plugin.NextRun(
self.tmpData[self.lastRow][2],
self.tmpData[self.lastRow][3]
)
grid.SetStringItem(self.lastRow, 3, next)
Diff()
else:
evt.Skip()
def onPrefix(evt):
self.tmpData[self.lastRow][5] = evt.GetString()
Diff()
evt.Skip()
def onStart(evt):
self.tmpData[self.lastRow][6] = evt.GetString()
Diff()
evt.Skip()
def onStop(evt):
self.tmpData[self.lastRow][7] = evt.GetString()
Diff()
evt.Skip()
def onPayload(evt):
self.tmpData[self.lastRow][8] = evt.GetString()
Diff()
evt.Skip()
def onTestButton(evt):
data = self.tmpData[self.lastRow]
if testValidity(data, True):
return
ticks = mktime(localtime())
next = self.plugin.Execute(data, False, ticks, True)
next = next[:19] if next else self.plugin.text.none
self.plugin.updateLogFile(self.text.testRun % (data[1], next))
fillDynamicSizer(-1)
grid = self.grid = CheckListCtrl(self, text,-1)
sizer.Add(grid, 0, wx.ALL | wx.EXPAND, 5)
prefixLabel = wx.StaticText(self, -1, self.text.evtPrefix)
prefixCtrl = wx.TextCtrl(self, -1, "", size = (150,-1))
startLabel = wx.StaticText(self, -1, self.text.startSuffix)
startCtrl = wx.TextCtrl(self, -1, "", size = (150,-1))
stopLabel = wx.StaticText(self, -1, self.text.stopSuffix)
stopCtrl = wx.TextCtrl(self, -1, "", size = (150,-1))
payloadLabel = wx.StaticText(self, -1, self.text.evtPayload)
payloadCtrl = wx.TextCtrl(self, -1, "")
bttnSizer = wx.BoxSizer(wx.HORIZONTAL)
bttnSizer.Add((5, -1))
i = 0
for bttn in self.text.buttons:
id = wx.NewId()
bttns.append(id)
b = wx.Button(self, id, bttn)
bttnSizer.Add(b,1)
if i in (1, 2, 5):
b.Enable(False)
if i == 3:
b.SetDefault()
b.Bind(wx.EVT_BUTTON, onButton, id = id)
bttnSizer.Add((5, -1))
i += 1
sizer.Add(bttnSizer,0,wx.EXPAND)
schedulerName = wx.TextCtrl(self, -1, "")
typeChoice = wx.Choice(self, -1, choices = self.text.sched_type)
id = wx.NewId() #testBttn
bttns.append(id)
self.Bind(wx.EVT_BUTTON, onTestButton, id = id)
wx.EVT_CHECKLISTBOX(self, -1, onCheckListBox)
maskedlib.EVT_TIMEUPDATE(self, -1, OnTimeChange)
wx.EVT_TEXT(self, -1, onPeriodNumber)
wx.EVT_CHOICE(self, -1, onPeriodUnit)
wx.EVT_DATE_CHANGED(self, -1, onDatePicker)
wx.EVT_CHECKBOX(self, -1, onCheckBox)
self.Bind(eg.EVT_VALUE_CHANGED, OnUpdateDialog)
self.Bind(wx.EVT_LIST_ITEM_SELECTED, OnSelectCell)
typeChoice.Bind(wx.EVT_CHOICE, onTypeChoice)
schedulerName.Bind(wx.EVT_TEXT, onSchedulerTitle)
prefixCtrl.Bind(wx.EVT_TEXT, onPrefix)
startCtrl.Bind(wx.EVT_TEXT, onStart)
stopCtrl.Bind(wx.EVT_TEXT, onStop)
payloadCtrl.Bind(wx.EVT_TEXT, onPayload)
self.grid.Bind(eg.EVT_VALUE_CHANGED, onCheckListCtrl)
nameSizer = wx.FlexGridSizer(2, 0, 0, 20)
nameSizer.AddGrowableCol(0,1)
name_label = wx.StaticText(self, -1, self.text.header[1] + ":")
nameSizer.Add(name_label)
type_label = wx.StaticText(self, -1, self.text.type_label)
nameSizer.Add(type_label)
nameSizer.Add(schedulerName, 0, wx.EXPAND)
nameSizer.Add(typeChoice)
typeSizer.Add(nameSizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
typeSizer.Add(dynamicSizer, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 5)
sizer.Add(typeSizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
eventSizer = wx.FlexGridSizer(4, 2, 8, 3)
eventSizer.AddGrowableCol(1)
eventSizer.Add(prefixLabel, 0, wx.ALIGN_RIGHT | wx.TOP, 4)
eventSizer.Add(prefixCtrl, 0)
eventSizer.Add(startLabel,0, wx.ALIGN_RIGHT | wx.TOP, 4)
eventSizer.Add(startCtrl, 0)
eventSizer.Add(stopLabel, 0, wx.ALIGN_RIGHT | wx.TOP, 4)
eventSizer.Add(stopCtrl, 0)
eventSizer.Add(payloadLabel, 0, wx.ALIGN_RIGHT | wx.TOP, 4)
eventSizer.Add(payloadCtrl, 1, wx.EXPAND)
sizer.Add(eventSizer, 0, wx.ALL | wx.EXPAND, 5)
rows = len(self.tmpData)
if rows > 0:
for row in range(rows):
grid.InsertStringItem(row, "")
if self.tmpData[row][0]:
grid.CheckItem(row)
grid.SetStringItem(row, 1, self.tmpData[row][1])
grid.SetStringItem(row, 2, self.tmpData[row][4])
next = self.plugin.NextRun(self.tmpData[row][2], self.tmpData[row][3])
grid.SetStringItem(row, 3, next)
self.lastRow = 0
grid.SelRow(0)
OpenSchedule()
enableBttns(True)
else:
EnableCtrls(False)
grid.DeleteItem(0)
self.Bind(wx.EVT_CLOSE, self.onClose)
self.SetSizer(sizer)
sizer.Layout()
if ConfigData.pos:
self.SetPosition(ConfigData.pos)
else:
self.Center()
self.Fit()
self.Show(True)
def EnableAll(self, flag):
for ix in range(len(self.tmpData)):
self.tmpData[ix][0] = flag
if self.grid.GetItem(ix, 1).GetText() == self.tmpData[ix][1]:
if flag:
self.grid.CheckItem(ix)
elif self.grid.IsChecked(ix):
self.grid.ToggleItem(ix)
def EnableSchedule(self, schedule, flag):
tmpList = [item[1] for item in self.tmpData]
if schedule in tmpList:
ix = tmpList.index(schedule)
self.tmpData[ix][0] = flag
if self.grid.GetItem(ix, 1).GetText() == self.tmpData[ix][1]:
if flag:
self.grid.CheckItem(ix)
elif self.grid.IsChecked(ix):
self.grid.ToggleItem(ix)
def DeleteSchedule(self, schedule):
tmpList = [item[1] for item in self.tmpData]
if schedule in tmpList:
ix = tmpList.index(schedule)
if self.grid.GetItem(ix, 1).GetText() == self.tmpData[ix][1]:
self.grid.DeleteItem(ix)
self.grid.Refresh()
self.tmpData.pop(ix)
def AddSchedule(self, schedule):
tmpList = [item[1] for item in self.tmpData]
if schedule[1] in tmpList:
ix = tmpList.index(schedule[1])
self.tmpData[ix] = schedule
if not self.grid.GetItem(ix, 1).GetText() == self.tmpData[ix][1]:
return
else:
ix = len(self.tmpData)
self.tmpData.append(schedule)
self.grid.InsertStringItem(ix, "")
if schedule[0]:
self.grid.CheckItem(ix)
elif self.grid.IsChecked(ix):
self.grid.ToggleItem(ix)
self.grid.SetStringItem(ix, 1, schedule[1])
next = self.plugin.NextRun(schedule[2], schedule[3])
self.grid.SetStringItem(ix, 3, next)
if self.lastRow == ix:
evt = eg.ValueChangedEvent(ix)
wx.PostEvent(self, evt)
def RefreshGrid(self, ix, last, next):
if self.grid.GetItem(ix, 1).GetText() == self.tmpData[ix][1]:
self.grid.SetStringItem(ix, 2, last)
self.grid.SetStringItem(ix, 3, next)
def onClose(self, evt):
hwnd = self.GetHandle()
wp = GetWindowPlacement(hwnd)[4]
cdr = wx.GetClientDisplayRect()
pos = (wp[0] + cdr[0], wp[1] + cdr[1])
if pos != ConfigData.pos:
ConfigData.pos = pos
self.plugin.dialog = None
wx.CallAfter(self.Show, False)
wx.CallAfter(self.Destroy)
evt.Skip()
#===============================================================================
class SchedulGhost(eg.PluginBase):
text = Text
xmlpath = None
data = []
tmpData = []
dialog = None
pos = None
eggTimer = None
eggTimersList = None
# reminder = None
eggTimers = {}
# reminders = {}
eggPos = None
eggListPos = None
prefix = None
def __init__(self):
text=Text
self.AddActionsFromList(Actions)
def __start__(
self,
xmlpath = None,
logfile = None,
prefix = "SchedulGhost",
holidays = [[], []],
first_day = 0
):
self.holidays = holidays
self.logfile = logfile
self.prefix = prefix
self.first_day = first_day
self.data = []
self.tmpData = []
if xmlpath:
self.xmlpath = u"%s\\SchedulGhost.xml" % xmlpath
if os.path.exists(self.xmlpath):
self.data = self.xmlToData()
if logfile:
self.updateLogFile(self.text.start, True)
self.UpdateEGscheduler()
eg.Bind("System.Suspend", self.OnSystemMessage)
eg.Bind("System.Resume", self.OnSystemMessage)
eg.Bind("System.SessionLock", self.OnSystemMessage)
eg.Bind("System.SessionUnlock", self.OnSystemMessage)
def __stop__(self):
sched_list = eg.scheduler.__dict__['heap']
tmpLst = []
self.updateLogFile(self.text.stop, True)
for sched in sched_list:
if sched[1] == self.SchedulGhostScheduleRun:
tmpLst.append(sched)
if len(tmpLst) > 0:
for sched in tmpLst:
eg.scheduler.CancelTask(sched)
self.updateLogFile(self.text.canc % sched[2][0])
self.AbortEggTimers()
self.dataToXml()
eg.Unbind("System.Suspend", self.OnSystemMessage)
eg.Unbind("System.Resume", self.OnSystemMessage)
eg.Unbind("System.SessionLock", self.OnSystemMessage)
eg.Unbind("System.SessionUnlock", self.OnSystemMessage)
if self.dialog:
self.dialog.onClose(wx.CommandEvent())
if self.eggTimer:
self.eggTimer.onClose(wx.CommandEvent())
#if self.reminder:
# self.reminder.onClose(wx.CommandEvent())
if self.eggTimersList:
self.eggTimersList.onClose(wx.CommandEvent())
def Configure(
self,
xmlpath = "",
logfile = "",
prefix = "SchedulGhost",
holidays = [[], []],
first_day = 0
):
panel = eg.ConfigPanel(self)
panel.holidays = cpy(holidays)
del holidays
self.logfile = logfile
self.first_day = first_day
label2Text = wx.StaticText(panel, -1, self.text.label2)
xmlPathCtrl = MyDirBrowseButton(
panel,
toolTip = self.text.toolTipFolder,
dialogTitle = self.text.browseTitle,
buttonText = eg.text.General.browse
)
xmlPathCtrl.GetTextCtrl().SetEditable(False)
if xmlpath:
self.xmlpath = u"%s\\SchedulGhost.xml" % xmlpath
xmlPathCtrl.GetTextCtrl().ChangeValue(xmlpath)
else:
xmlPathCtrl.startDirectory = eg.configDir
logFileCtrl = MyFileBrowseButton(
panel,
toolTip = self.text.toolTipFile,
dialogTitle = self.text.browseFile,
buttonText = eg.text.General.browse,
startDirectory = eg.configDir,
defaultFile = "Sched_Log.txt"
)
logFileCtrl.GetTextCtrl().SetEditable(False)
logCheckBox = wx.CheckBox(panel, -1, self.text.logLabel)
defaultPrefLabel = wx.StaticText(panel, -1, self.text.prefLabel)
firstDayLabel = wx.StaticText(panel, -1, self.text.first_day)
firstDayCtrl = wx.Choice(
panel,
-1,
choices = (
day_name[0],
day_name[6]
),
size = (firstDayLabel.GetSize()[0], -1)
)
firstDayCtrl.SetSelection(first_day)
defaultPrefCtrl = wx.TextCtrl(panel, -1, prefix)
def AlignButtonLines(line_1, line_2):
l_1 = panel.GetTextExtent(line_1)[0]
l_2 = panel.GetTextExtent(line_2)[0]
if l_1 == l_2:
return line_1 + "\n" + line_2
Max = max(l_1, l_2)
if panel.GetTextExtent(line_1)[0] < Max:
flg = True
tmp = line_1
else:
flg = False
tmp = line_2
Len = panel.GetTextExtent(tmp)[0]
while Max > Len:
tmp += " "
Len = panel.GetTextExtent(tmp)[0]
if flg:
return tmp + "\n" + line_2
return line_1 + "\n" + tmp
panel.holidButton = wx.Button(panel, -1, AlignButtonLines(self.text.holidButton_1, self.text.holidButton_2))
managerButton = wx.Button(panel, -1, AlignButtonLines(self.text.managerButton_1, self.text.managerButton_2))
if not self.prefix: #First run after plugin insert
managerButton.Enable(False)
def OnApplyBtn(evt):
managerButton.Enable(True)
evt.Skip()
panel.dialog.buttonRow.applyButton.Bind(wx.EVT_BUTTON, OnApplyBtn)
def onManagerButton(evt):
if not self.dialog:
wx.CallAfter(schedulerDialog, self.text.ShowSchedulGhost, self)
else:
wx.CallAfter(self.dialog.Raise)
evt.Skip()
managerButton.Bind(wx.EVT_BUTTON, onManagerButton)
def onHolidButton(evt):
dlg = HolidaysFrame(
parent = panel,
plugin = self,
)
dlg.Centre()
wx.CallAfter(dlg.ShowHolidaysFrame)
evt.Skip()
panel.holidButton.Bind(wx.EVT_BUTTON, onHolidButton)
bottomSizer = wx.GridBagSizer(1, 1)
val = self.logfile != ""
logCheckBox.SetValue(val)
logFileCtrl.Enable(val)
logFileCtrl.GetTextCtrl().ChangeValue(self.logfile)
sizerAdd = panel.sizer.Add
sizerAdd(label2Text, 0, wx.TOP, 5)
sizerAdd(xmlPathCtrl,0,wx.TOP | wx.EXPAND, 2)
sizerAdd(logCheckBox, 0, wx.TOP, 15)
sizerAdd(logFileCtrl, 0, wx.TOP | wx.EXPAND, 2)
bottomSizer.Add(defaultPrefLabel, (0, 0))
bottomSizer.Add(firstDayLabel, (0, 1), flag = wx.LEFT, border = 10)
bottomSizer.Add((-1, -1), (0, 2), (2, 1), flag = wx.EXPAND)
bottomSizer.Add(defaultPrefCtrl, (1, 0))
bottomSizer.Add(firstDayCtrl, (1, 1), flag = wx.LEFT, border = 10)
bottomSizer.Add(panel.holidButton, (0, 3), (2, 1), flag = wx.EXPAND)
bottomSizer.Add(managerButton, (0, 4), (2, 1), flag = wx.EXPAND|wx.LEFT, border = 10)
bottomSizer.AddGrowableCol(2)
sizerAdd(bottomSizer, 0, wx.TOP | wx.EXPAND, 15)
def Validation():
flag1 = os.path.exists(xmlPathCtrl.GetValue())
flag2 = False
if not logCheckBox.IsChecked():
flag2 = True
else:
logFile = logFileCtrl.GetTextCtrl().GetValue()
egLog = u"%s\\Log.txt" % unicode(eg.configDir)
if logFile.lower() == egLog.lower():
PlaySound('SystemExclamation', SND_ASYNC)
MessageBox(
panel.GetHandle(),
self.text.mess % unicode(eg.configDir),
"SchedulGhost",
48
)
elif logFile != "":
flag2 = True
flag3 = defaultPrefCtrl.GetValue() != ""
flag = flag1 and flag2 and flag3
panel.dialog.buttonRow.okButton.Enable(flag)
panel.isDirty = True
panel.dialog.buttonRow.applyButton.Enable(flag)
def onXmlPathChange(event):
xmlpath = xmlPathCtrl.GetValue()
if xmlpath:
self.xmlpath = u"%s\\SchedulGhost.xml" % xmlpath
Validation()
event.Skip()
xmlPathCtrl.Bind(wx.EVT_TEXT, onXmlPathChange)
def logFileChange(event):
self.logfile = logFileCtrl.GetTextCtrl().GetValue()
Validation()
event.Skip()
logFileCtrl.Bind(wx.EVT_TEXT, logFileChange)
def ontPrefCtrl(event):
Validation()
event.Skip()
defaultPrefCtrl.Bind(wx.EVT_TEXT, ontPrefCtrl)
def onLogCheckBox(evt):
val = evt.IsChecked()
logFileCtrl.Enable(val)
if not val:
logFileCtrl.SetValue("")
else:
Validation()
evt.Skip()
logCheckBox.Bind(wx.EVT_CHECKBOX, onLogCheckBox)
Validation()
while panel.Affirmed():
panel.SetResult(
xmlPathCtrl.GetValue(),
logFileCtrl.GetTextCtrl().GetValue(),
defaultPrefCtrl.GetValue(),
panel.holidays,
firstDayCtrl.GetSelection()
)
def NextRun(self, type, data):
def FindRunDateTime(runList, cond, cond2):
runList.sort()
runDateTime = ""
if len(runList) > 0:
if not cond and not cond2:
return runList[0]
for item in runList:
found1 = True
if cond:
found1 = False
if (item.month, item.day) in self.holidays[0]:
continue
elif (item.year, item.month, item.day) in self.holidays[1]:
continue
else:
found1 = True
found2 = True
if cond2:
found2 = False
tmpItem=item + td(days = 1)
if (tmpItem.month, tmpItem.day) in self.holidays[0]:
continue
elif (tmpItem.year, tmpItem.month, tmpItem.day) in self.holidays[1]:
continue
else:
found2 = True
if found1 and found2:
runDateTime = item
break
return runDateTime
now = dt.now()
now = now.replace(microsecond = 999999)
runTime = dt.strptime(data[0], "%H:%M:%S").time()
if type == 0: # once or yearly
runDate = dt.strptime(data[2], '%Y-%m-%d')
runDateTime = dt.combine(runDate, runTime)
if now < runDateTime:
return str(runDateTime)
elif not data[3]:
return ""
else:
if runDateTime.replace(year = now.year) < now:
return str(runDateTime.replace(year = now.year + 1))
else:
return str(runDateTime.replace(year = now.year))
elif type == 1: # daily
runDateTime = dt.combine(now.date(), runTime)
if now.time() > runTime:
runDateTime += td(days = 1)
return str(runDateTime)
elif type == 2: # weekly
if not data[2] and (len(self.holidays[0])==0 or not data[3] and not data[5]):
#print len(self.holidays[0])
return ""
runDateTime = dt.combine(now.date(), runTime)
weekdaysLower = []
weekdaysLarger = []
nowDay = now.weekday()
for weekday in range(7):
if 2**weekday & data[2]:
if weekday < nowDay or (weekday == nowDay and now.time() > runTime):
weekdaysLower.append(weekday)
else:
weekdaysLarger.append(weekday)
if not data[4] and not data[3] and not data[6] and not data[5]: # without holiday check
if len(weekdaysLarger) > 0:
delta = weekdaysLarger[0] - nowDay
return str(runDateTime + td(days = delta))
delta = 7 + weekdaysLower[0] - nowDay
return str(runDateTime + td(days = delta))
if data[4] or data[6]: # holiday check
found = False
shift = 0
while True:
for day in weekdaysLarger:
delta = day + shift - nowDay
tmpRunDT = runDateTime + td(days = delta)
found1=True
if data[4]:
found1=False
if (tmpRunDT.month, tmpRunDT.day) in self.holidays[0]:
continue
elif (tmpRunDT.year, tmpRunDT.month, tmpRunDT.day) in self.holidays[1]:
continue
else:
found1 = True
found2=True
if data[6]:
found2=False
delta += 1
tmpRunDT2 = runDateTime + td(days = delta)
if (tmpRunDT2.month, tmpRunDT2.day) in self.holidays[0]:
continue
elif (tmpRunDT2.year, tmpRunDT2.month, tmpRunDT2.day) in self.holidays[1]:
continue
else:
found2 = True
if found1 and found2:
found = True
break
if found:
break
shift += 7
for day in weekdaysLower:
delta = day + shift - nowDay
tmpRunDT = runDateTime + td(days = delta)
found1=True
if data[4]:
found1=False
if (tmpRunDT.month, tmpRunDT.day) in self.holidays[0]:
continue
elif (tmpRunDT.year, tmpRunDT.month, tmpRunDT.day) in self.holidays[1]:
continue
else:
found1 = True
found2=True
if data[6]:
found2=False
delta += 1
tmpRunDT2 = runDateTime + td(days = delta)
if (tmpRunDT2.month, tmpRunDT2.day) in self.holidays[0]:
continue
elif (tmpRunDT2.year, tmpRunDT2.month, tmpRunDT2.day) in self.holidays[1]:
continue
else:
found2 = True
if found1 and found2:
found = True
break
if found:
break
else: # holiday_2 check
if len(weekdaysLarger) > 0:
Delta = weekdaysLarger[0] - nowDay
elif len(weekdaysLower) > 0:
Delta = 7 + weekdaysLower[0] - nowDay
else:
Delta =-1
delta = 0 if now.time() < runTime else 1
while True:
if Delta!=-1 and delta>=Delta:
tmpRunDT = runDateTime + td(days = Delta)
break
tmpRunDT = runDateTime + td(days = delta)
if data[3]:
if (tmpRunDT.month, tmpRunDT.day) in self.holidays[0]:
break
elif (tmpRunDT.year, tmpRunDT.month, tmpRunDT.day) in self.holidays[1]:
break
if data[5]:
tmpRunDT2 = runDateTime + td(days = (delta+1))
if (tmpRunDT2.month, tmpRunDT2.day) in self.holidays[0]:
break
elif (tmpRunDT2.year, tmpRunDT2.month, tmpRunDT2.day) in self.holidays[1]:
break
delta+=1
return str(tmpRunDT)
elif type == 3: # monthly/weekday
if data[2] == 0 or data[3] == 0 or (data[4] + data[5]) == 0:
return ""
currMonth = now.month
currYear = now.year
monthsInt = data[4] + (data[5] << 6)
months = []
for month in range(1,13):
if 2 ** (month - 1) & monthsInt:
months.append(month)
if currMonth in months:
runList = []
for ix in range(6):
if 2 ** ix & data[2]:
for weekday in range(7):
if 2 ** weekday & data[3]:
day = FindMonthDay(currYear, currMonth, weekday, ix)
if day:
runDateTime = dt.combine(dt(currYear, currMonth, day).date(), runTime)
if now < runDateTime:
runList.append(runDateTime)
tmpRunDT = FindRunDateTime(runList, data[6], data[7])
if tmpRunDT:
return str(tmpRunDT)
lower = []
larger = []
for month in months:
if month > currMonth:
larger.append(month)
else: #month <= currMonth:
lower.append(month)
year = currYear
tmpRunDT = None
while True:
for month in larger:
runList = []
for ix in range(6):
if 2 ** ix & data[2]:
for weekday in range(7):
if 2 ** weekday & data[3]:
day = FindMonthDay(year, month, weekday, ix)
if day:
runDateTime = dt.combine(dt(year, month, day).date(), runTime)
runList.append(runDateTime)
tmpRunDT = FindRunDateTime(runList, data[6], data[7])
if tmpRunDT:
break
if tmpRunDT:
break
year += 1
for month in lower:
runList = []
for ix in range(6):
if 2 ** ix & data[2]:
for weekday in range(7):
if 2 ** weekday & data[3]:
day=FindMonthDay(year, month, weekday, ix)
if day:
runDateTime = dt.combine(dt(year, month, day).date(), runTime)
runList.append(runDateTime)
tmpRunDT = FindRunDateTime(runList, data[6], data[7])
if tmpRunDT:
break
if tmpRunDT:
break
return str(tmpRunDT)
elif type == 4: #monthly/day
if (data[2] + data[3] + data[4] + data[5]) == 0 or (data[6] + data[7]) == 0:
return ""
runList = []
currMonth = now.month
currYear = now.year
monthsInt = data[6] + (data[7] << 6)
daysInt = data[2] + (data[3] << 8) + (data[4] << 16) + (data[5] << 24)
days = []
for day in range(1, 32):
if 2 ** (day - 1) & daysInt:
days.append(day)
months = []
for month in range(1, 13):
if 2 ** (month - 1) & monthsInt:
months.append(month)
if currMonth in months:
for day in days:
if day > monthrange(currYear, currMonth)[1]:
break
runDateTime = dt.combine(dt(currYear, currMonth, day).date(), runTime)
if now < runDateTime:
runList.append(runDateTime)
if len(runList) == 0:
lower = []
larger = []
nextMonth = None
for month in months:
if month > currMonth:
larger.append(month)
else: #month<=currMonth:
lower.append(month)
if len(larger) > 0:
nextYear = currYear
for month in larger:
for day in days:
if day > monthrange(nextYear, month)[1]:
break
runDateTime = dt.combine(dt(nextYear, month, day).date(), runTime)
runList.append(runDateTime)
if len(runList) == 0 and len(lower) > 0:
nextYear = currYear + 1
for month in lower:
for day in days:
if day > monthrange(nextYear, month)[1]:
break
runDateTime = dt.combine(dt(nextYear, month, day).date(), runTime)
runList.append(runDateTime)
if len(runList) > 0:
return str(min(runList))
else:
return ""
elif type == 5: #periodically
runDate = dt.strptime(data[2], '%Y-%m-%d')
runDateTime = dt.combine(runDate, runTime)
if now < runDateTime:
return str(runDateTime)
elif data[4] < 3: #unit = second, minute, hour
period = data[3] * (1, 60, 3600)[data[4]]
if period < 86400 and not 86400 % period:
if now.time() > runTime:
date = now.date()
else:
date = now.date() - td(days = 1)
runDateTime = dt.combine(date, runTime)
delta = now - runDateTime
delta = delta.seconds + 86400 * delta.days
share = delta / period
share += 1
delta = td(seconds = share * period)
return str(runDateTime + delta)
elif data[4] == 3 or data[4] == 4: #unit = day or week
period = data[3] if data[4] == 3 else 7 * data[3]
delta = (now - runDateTime).days
share = delta / period
if not delta % period:
if now.time() < runTime:
return str(dt.combine(now.date(), runTime))
share += 1
delta = td(days = share * period)
return str(runDateTime + delta)
elif data[4] == 5: #unit = month
period = data[3]
month = runDateTime.month
year = runDateTime.year
while now > runDateTime:
year += period / 12
m = month+period % 12
if m > 12:
year += 1
month = m % 12
else:
month = m
runDateTime = runDateTime.replace(year = year).replace(month = month)
return str(runDateTime)
else: # data[4] == 6: #unit = year
period = data[3]
year = runDateTime.year
while now > runDateTime:
year += period
runDateTime = runDateTime.replace(year = year)
return str(runDateTime)
else: #6 = Time span
return ""
def updateLogFile(self, line, blank = False):
if not self.logfile:
return
f = openFile(self.logfile, encoding = 'utf-8', mode = 'a')
if blank:
f.write("\r\n")
f.write("%s %s\r\n" % (str(dt.now())[:19], line))
f.close()
def OnSystemMessage(self, event):
self.updateLogFile(self.text.__dict__[event.suffix], True)
def Execute(self, params, stopEvent, ticks, immed = False):
if not stopEvent:
span = params[3][1]
if span != "00:00:00":
stopTicks = ticks + int(span[6:]) + 60 * int(span[3:5]) + 3600 * int(span[:2])
eg.scheduler.AddShortTaskAbsolute(
stopTicks,
self.SchedulGhostScheduleRun,
params[1],
True
)
next = self.NextRun(params[2], params[3])
if not immed and next: # new schedule, if valid next run time and not TEST/IMMEDIATELY run
startTicks = mktime(strptime(next, "%Y-%m-%d %H:%M:%S"))
eg.scheduler.AddShortTaskAbsolute(
startTicks,
self.SchedulGhostScheduleRun,
params[1],
False,
startTicks
)
suffix = params[6]
else:
suffix = params[7]
next = ""
if params[8]:
payload = next if params[8] == "{Next run}" else eg.ParseString(params[8])
eg.TriggerEvent(
eg.ParseString(suffix),
prefix = eg.ParseString(params[5]),
payload = payload
)
else:
eg.TriggerEvent(
eg.ParseString(suffix),
prefix = eg.ParseString(params[5])
)
return next
def SchedulGhostScheduleRun(self, schedule, stopEvent, ticks = 0):
data = self.data
ix = [item[1] for item in data].index(schedule)
next = self.Execute(data[ix], stopEvent, ticks)
if stopEvent:
self.updateLogFile(self.text.execStop % data[ix][1])
else:
last = str(dt.now())[:19]
self.data[ix][4] = last
if self.dialog:
tmpList = [item[1] for item in self.tmpData]
if schedule in tmpList:
ixTmp = tmpList.index(schedule)
self.tmpData[ixTmp][4] = last
self.dialog.RefreshGrid(ixTmp, last, next)
nxt = next[:19] if next else self.text.none
self.updateLogFile(self.text.execut % (data[ix][1], nxt))
def UpdateEGscheduler(self):
data = self.data
tmpList = []
sched_list = eg.scheduler.__dict__['heap']
for sched in sched_list:
if sched[1] == self.SchedulGhostScheduleRun:
if sched[2][0] in [item[1] for item in data]:
if not sched[2][1]: # ignore stop events
tmpList.append(sched)
else: # delete schedule
self.updateLogFile(self.text.cancAndDel % sched[2][0])
eg.scheduler.CancelTask(sched) # schedule deleted !
sched_list = tmpList
for schedule in data:
startMoment = self.NextRun(schedule[2], schedule[3])
nameList = [item[2][0] for item in sched_list]
if schedule[1] in nameList:
sched = sched_list[nameList.index(schedule[1])]
if not schedule[0]: # schedule is disabled !
eg.scheduler.CancelTask(sched)
self.updateLogFile(self.text.cancAndDis % schedule[1])
if not startMoment:
continue
startTicks = mktime(strptime(startMoment, "%Y-%m-%d %H:%M:%S"))
if not sched[2][1] and sched[0] != startTicks: # re-scheduling
self.updateLogFile(self.text.re_Sched % (schedule[1], startMoment))
eg.scheduler.CancelTask(sched)
eg.scheduler.AddShortTaskAbsolute(
startTicks,
self.SchedulGhostScheduleRun,
schedule[1],
False,
startTicks
)
elif schedule[0] and startMoment: # new schedule
startTicks = mktime(strptime(startMoment, "%Y-%m-%d %H:%M:%S"))
eg.scheduler.AddShortTaskAbsolute(
startTicks,
self.SchedulGhostScheduleRun,
schedule[1],
False,
startTicks
)
self.updateLogFile(self.text.newSched % (schedule[1], startMoment))
def dataToXml(self):
data = self.data
impl = miniDom.getDOMImplementation()
dom = impl.createDocument(None, u'Document', None)
root = dom.documentElement
commentNode = dom.createComment(self.text.xmlComment % str(dt.now())[:19])
dom.insertBefore(commentNode, root)
for item in data:
schedNode = dom.createElement(u'Schedule')
schedNode.setAttribute(u'Name', unicode(item[1]))
schedNode.setAttribute(u'Type', unicode(item[2]))
enableNode = dom.createElement(u'Enable')
enableText = dom.createTextNode(unicode(item[0]))
enableNode.appendChild(enableText)
schedNode.appendChild(enableNode)
last_runNode = dom.createElement(u'Last_run')
last_runText = dom.createTextNode(unicode(item[4]))
last_runNode.appendChild(last_runText)
schedNode.appendChild(last_runNode)
prefixNode = dom.createElement(u'Prefix')
prefixText = dom.createTextNode(unicode(item[5]))
prefixNode.appendChild(prefixText)
schedNode.appendChild(prefixNode)
startNode = dom.createElement(u'Start')
startText = dom.createTextNode(unicode(item[6]))
startNode.appendChild(startText)
schedNode.appendChild(startNode)
stopNode = dom.createElement(u'Stop')
stopText = dom.createTextNode(unicode(item[7]))
stopNode.appendChild(stopText)
schedNode.appendChild(stopNode)
payloadNode = dom.createElement(u'Payload')
payloadText = dom.createTextNode(unicode(item[8]))
payloadNode.appendChild(payloadText)
schedNode.appendChild(payloadNode)
dateTimeNode = dom.createElement(u'Datetime')
start_timeNode = dom.createElement(u'Start_time')
start_timeText = dom.createTextNode(unicode(item[3][0]))
start_timeNode.appendChild(start_timeText)
dateTimeNode.appendChild(start_timeNode)
durationNode = dom.createElement(u'Duration')
durationText = dom.createTextNode(unicode(item[3][1]))
durationNode.appendChild(durationText)
dateTimeNode.appendChild(durationNode)
if item[2] == 0:
dateNode = dom.createElement(u'Date')
dateText = dom.createTextNode(unicode(item[3][2]))
dateNode.appendChild(dateText)
dateTimeNode.appendChild(dateNode)
yearlyNode = dom.createElement(u'Yearly')
yearlyText = dom.createTextNode(unicode(item[3][3]))
yearlyNode.appendChild(yearlyText)
dateTimeNode.appendChild(yearlyNode)
if item[2] == 2:
weekdayNode = dom.createElement(u'Weekday')
weekdayText = dom.createTextNode(unicode(item[3][2]))
weekdayNode.appendChild(weekdayText)
dateTimeNode.appendChild(weekdayNode)
holidayNode = dom.createElement(u'HolidayCheck')
holidayText = dom.createTextNode(unicode(item[3][4]))
holidayNode.appendChild(holidayText)
dateTimeNode.appendChild(holidayNode)
holiday2Node = dom.createElement(u'HolidayCheck_2')
holiday2Text = dom.createTextNode(unicode(item[3][3]))
holiday2Node.appendChild(holiday2Text)
dateTimeNode.appendChild(holiday2Node)
holiday3Node = dom.createElement(u'HolidayCheck_3')
holiday3Text = dom.createTextNode(unicode(item[3][6]))
holiday3Node.appendChild(holiday3Text)
dateTimeNode.appendChild(holiday3Node)
holiday4Node = dom.createElement(u'HolidayCheck_4')
holiday4Text = dom.createTextNode(unicode(item[3][5]))
holiday4Node.appendChild(holiday4Text)
dateTimeNode.appendChild(holiday4Node)
if item[2] == 3:
orderNode = dom.createElement(u'Order')
orderText = dom.createTextNode(unicode(item[3][2]))
orderNode.appendChild(orderText)
dateTimeNode.appendChild(orderNode)
weekdayNode = dom.createElement(u'Weekday')
weekdayText = dom.createTextNode(unicode(item[3][3]))
weekdayNode.appendChild(weekdayText)
dateTimeNode.appendChild(weekdayNode)
first_halfNode = dom.createElement(u'First_half')
first_halfText = dom.createTextNode(unicode(item[3][4]))
first_halfNode.appendChild(first_halfText)
dateTimeNode.appendChild(first_halfNode)
second_halfNode = dom.createElement(u'Second_half')
second_halfText = dom.createTextNode(unicode(item[3][5]))
second_halfNode.appendChild(second_halfText)
dateTimeNode.appendChild(second_halfNode)
holidayNode = dom.createElement(u'HolidayCheck')
holidayText = dom.createTextNode(unicode(item[3][6]))
holidayNode.appendChild(holidayText)
dateTimeNode.appendChild(holidayNode)
holiday3Node = dom.createElement(u'HolidayCheck_3')
holiday3Text = dom.createTextNode(unicode(item[3][7]))
holiday3Node.appendChild(holiday3Text)
dateTimeNode.appendChild(holiday3Node)
if item[2] == 4:
q_1_Node = dom.createElement(u'Q_1')
q_1_Text = dom.createTextNode(unicode(item[3][2]))
q_1_Node.appendChild(q_1_Text)
dateTimeNode.appendChild(q_1_Node)
q_2_Node = dom.createElement(u'Q_2')
q_2_Text = dom.createTextNode(unicode(item[3][3]))
q_2_Node.appendChild(q_2_Text)
dateTimeNode.appendChild(q_2_Node)
q_3_Node = dom.createElement(u'Q_3')
q_3_Text = dom.createTextNode(unicode(item[3][4]))
q_3_Node.appendChild(q_3_Text)
dateTimeNode.appendChild(q_3_Node)
q_4_Node = dom.createElement(u'Q_4')
q_4_Text = dom.createTextNode(unicode(item[3][5]))
q_4_Node.appendChild(q_4_Text)
dateTimeNode.appendChild(q_4_Node)
first_halfNode = dom.createElement(u'First_half')
first_halfText = dom.createTextNode(unicode(item[3][6]))
first_halfNode.appendChild(first_halfText)
dateTimeNode.appendChild(first_halfNode)
second_halfNode = dom.createElement(u'Second_half')
second_halfText = dom.createTextNode(unicode(item[3][7]))
second_halfNode.appendChild(second_halfText)
dateTimeNode.appendChild(second_halfNode)
if item[2] == 5:
dateNode = dom.createElement(u'Date')
dateText = dom.createTextNode(unicode(item[3][2]))
dateNode.appendChild(dateText)
dateTimeNode.appendChild(dateNode)
numberNode = dom.createElement(u'Number')
numberText = dom.createTextNode(unicode(item[3][3]))
numberNode.appendChild(numberText)
dateTimeNode.appendChild(numberNode)
unitNode = dom.createElement(u'Unit')
unitText = dom.createTextNode(unicode(item[3][4]))
unitNode.appendChild(unitText)
dateTimeNode.appendChild(unitNode)
schedNode.appendChild(dateTimeNode)
root.appendChild(schedNode)
f = file(self.xmlpath, 'wb')
writer = lookup('utf-8')[3](f)
dom.writexml(writer, encoding = 'utf-8')
f.close()
def xmlToData(self):
data = []
xmlfile = self.xmlpath
xmldoc = miniDom.parse(xmlfile)
document = xmldoc.getElementsByTagName('Document')[0]
schedules = document.getElementsByTagName('Schedule')
for schedule in schedules:
dataItem = []
enable = int(schedule.getElementsByTagName('Enable')[0].firstChild.data)
dataItem.append(enable)
name = schedule.attributes["Name"].value
dataItem.append(name)
type = int(schedule.attributes["Type"].value)
dataItem.append(type)
dateTime = schedule.getElementsByTagName('Datetime')[0]
params = []
start_time = dateTime.getElementsByTagName('Start_time')[0].firstChild.data
params.append(start_time)
duration = dateTime.getElementsByTagName('Duration')[0].firstChild.data
params.append(duration)
if type == 0:
date = dateTime.getElementsByTagName('Date')[0].firstChild.data
params.append(date)
date = int(dateTime.getElementsByTagName('Yearly')[0].firstChild.data)
params.append(date)
if type == 2:
weekday = int(dateTime.getElementsByTagName('Weekday')[0].firstChild.data)
params.append(weekday)
holiday2 = int(dateTime.getElementsByTagName('HolidayCheck_2')[0].firstChild.data)
params.append(holiday2)
holiday = int(dateTime.getElementsByTagName('HolidayCheck')[0].firstChild.data)
params.append(holiday)
holiday4 = int(dateTime.getElementsByTagName('HolidayCheck_4')[0].firstChild.data) if dateTime.getElementsByTagName('HolidayCheck_4') else 0
params.append(holiday4)
holiday3 = int(dateTime.getElementsByTagName('HolidayCheck_3')[0].firstChild.data) if dateTime.getElementsByTagName('HolidayCheck_3') else 0
params.append(holiday3)
if type == 3:
order = int(dateTime.getElementsByTagName('Order')[0].firstChild.data)
params.append(order)
weekday = int(dateTime.getElementsByTagName('Weekday')[0].firstChild.data)
params.append(weekday)
first_half = int(dateTime.getElementsByTagName('First_half')[0].firstChild.data)
params.append(first_half)
second_half = int(dateTime.getElementsByTagName('Second_half')[0].firstChild.data)
params.append(second_half)
holiday = int(dateTime.getElementsByTagName('HolidayCheck')[0].firstChild.data)
params.append(holiday)
holiday3 = int(dateTime.getElementsByTagName('HolidayCheck_3')[0].firstChild.data) if dateTime.getElementsByTagName('HolidayCheck_3') else 0
params.append(holiday3)
if type == 4:
q_1 = int(dateTime.getElementsByTagName('Q_1')[0].firstChild.data)
params.append(q_1)
q_2 = int(dateTime.getElementsByTagName('Q_2')[0].firstChild.data)
params.append(q_2)
q_3 = int(dateTime.getElementsByTagName('Q_3')[0].firstChild.data)
params.append(q_3)
q_4 = int(dateTime.getElementsByTagName('Q_4')[0].firstChild.data)
params.append(q_4)
first_half = int(dateTime.getElementsByTagName('First_half')[0].firstChild.data)
params.append(first_half)
second_half = int(dateTime.getElementsByTagName('Second_half')[0].firstChild.data)
params.append(second_half)
if type == 5:
date = dateTime.getElementsByTagName('Date')[0].firstChild.data
params.append(date)
number = int(dateTime.getElementsByTagName('Number')[0].firstChild.data)
params.append(number)
unit = int(dateTime.getElementsByTagName('Unit')[0].firstChild.data)
params.append(unit)
dataItem.append(params)
last_run = schedule.getElementsByTagName('Last_run')[0].firstChild
last_run = last_run.data if last_run else ""
dataItem.append(last_run)
prefix = schedule.getElementsByTagName('Prefix')[0].firstChild
prefix = prefix.data if prefix else ""
dataItem.append(prefix)
start = schedule.getElementsByTagName('Start')[0].firstChild
start = start.data if start else ""
dataItem.append(start)
stop = schedule.getElementsByTagName('Stop')[0].firstChild
stop = stop.data if stop else ""
dataItem.append(stop)
payload = schedule.getElementsByTagName('Payload')[0].firstChild
payload = payload.data if payload else ""
dataItem.append(payload)
data.append(dataItem)
return data
def SchedulGhost_EggFunction(self, key):
args = self.eggTimers[key]
now = mktime(localtime())
delta = Ticks2Delta(key, now)
self.updateLogFile(self.text.eggElaps % (args[1], args[2], delta))
eg.TriggerEvent(args[2], prefix = args[1])
sound = None
if len(args[3]) > 0:
sound = wx.Sound(args[3])
if os.path.isfile(args[3]) and sound.IsOk():
sound.Play(wx.SOUND_ASYNC)
else:
self.PrintError(self.text.soundProblem % args[3])
PlaySound('SystemExclamation', SND_ASYNC)
if len(args[4]) > 0:
wx.CallAfter(
PopupText,
None,
self,
args[4:],
None,
sound
)
del self.eggTimers[key]
def AddEggTimer(self, val, args):
self.updateLogFile(self.text.eggStart % (args[1], args[2], val))
val = int(val[6:]) + 60 * int(val[3:5]) + 3600 * int(val[:2])
now = mktime(localtime())
while now in self.eggTimers:
now += .01
self.eggTimers[now] = args
eg.scheduler.AddShortTask(val, self.SchedulGhost_EggFunction, now)
def AbortEggTimers(self, eggName = None):
egg_list = eg.scheduler.__dict__['heap']
tmpLst = []
for egg in egg_list:
if egg[1] == self.SchedulGhost_EggFunction:
tmpLst.append(egg)
if len(tmpLst) > 0:
for egg in tmpLst:
args = self.eggTimers[egg[2][0]]
if eggName is None or eggName == args[9]:
delta = Ticks2Delta(egg[2][0], egg[0])
self.updateLogFile(
self.text.eggCancel % (args[9], args[1], args[2], delta)
)
eg.scheduler.CancelTask(egg)
#===============================================================================
#cls types for Actions list:
#===============================================================================
class ShowSchedulGhost(eg.ActionBase):
def __call__(self):
if not self.plugin.dialog:
wx.CallAfter(schedulerDialog, self.text, self.plugin)
else:
wx.CallAfter(self.plugin.dialog.Raise)
#===============================================================================
class HideSchedulGhost(eg.ActionBase):
def __call__(self):
if self.plugin.dialog:
wx.CallAfter(self.plugin.dialog.Close)
#===============================================================================
class EnableSchedule(eg.ActionBase):
class text:
scheduleTitle = "Schedule title:"
notFound = 'Can not find schedule "%s" !'
def __call__(self, schedule=""):
schedule = eg.ParseString(schedule)
data = self.plugin.data
tmpLst = [item[1] for item in data]
if schedule in tmpLst:
ix = tmpLst.index(schedule)
if self.value > -1:
data[ix][0] = self.value
self.plugin.UpdateEGscheduler()
if self.plugin.dialog:
wx.CallAfter(self.plugin.dialog.EnableSchedule, schedule, self.value)
return data[tmpLst.index(schedule)]
else:
self.PrintError(self.text.notFound % schedule)
return self.text.notFound % schedule
def Configure(self, schedule = ""):
panel = eg.ConfigPanel()
data = self.plugin.data
choices = [item[1] for item in data]
textControl = wx.ComboBox(panel, -1, schedule, size = (300, -1), choices = choices)
panel.sizer.Add(
wx.StaticText(
panel,
-1,
self.text.scheduleTitle
),
0,
wx.LEFT | wx.TOP,
10
)
panel.sizer.Add(textControl, 0, wx.LEFT, 10)
while panel.Affirmed():
panel.SetResult(textControl.GetValue())
#===============================================================================
class EnableAll(eg.ActionBase):
def __call__(self):
data = self.plugin.data
for schedule in data:
schedule[0] = self.value
self.plugin.UpdateEGscheduler()
if self.plugin.dialog:
wx.CallAfter(self.plugin.dialog.EnableAll, self.value)
#===============================================================================
class DeleteSchedule(eg.ActionBase):
class text:
scheduleTitle = "Schedule title:"
notFound = 'Can not find schedule "%s" !'
def __call__(self, schedule=""):
schedule = eg.ParseString(schedule)
data = self.plugin.data
tmpLst = [item[1] for item in data]
if schedule in tmpLst:
ix = tmpLst.index(schedule)
data.pop(ix)
self.plugin.UpdateEGscheduler()
if self.plugin.dialog:
wx.CallAfter(self.plugin.dialog.DeleteSchedule, schedule)
else:
self.PrintError(self.text.notFound % schedule)
return self.text.notFound % schedule
def Configure(self, schedule = ""):
panel = eg.ConfigPanel()
data = self.plugin.data
choices = [item[1] for item in data]
textControl = wx.ComboBox(panel, -1, schedule, size = (300, -1), choices = choices)
panel.sizer.Add(wx.StaticText(panel, -1, self.text.scheduleTitle), 0, wx.LEFT | wx.TOP, 10)
panel.sizer.Add(textControl, 0, wx.LEFT, 10)
while panel.Affirmed():
panel.SetResult(textControl.GetValue())
#===============================================================================
class RunScheduleImmediately(eg.ActionBase):
class text:
scheduleTitle = "Schedule title:"
notFound = 'Can not find schedule "%s" !'
immedRun = 'Schedule "%s" - IMMEDIATELY execution. Possible next time: %s'
update = 'Update "Last run" field when executed'
def __call__(self, schedule="", update=False):
schedule = eg.ParseString(schedule)
data = self.plugin.data
tmpLst = [item[1] for item in data]
if schedule in tmpLst:
ix = tmpLst.index(schedule)
sched = self.plugin.data[ix]
if sched[0] or self.value: #enabled or force
eg.TriggerEvent(
sched[6],
sched[8],
sched[5]
)
span = sched[3][1]
if span != "00:00:00":
stopTicks = mktime(localtime()) + int(span[6:])\
+ 60 * int(span[3:5]) + 3600 * int(span[:2])
eg.scheduler.AddShortTaskAbsolute(
stopTicks,
eg.TriggerEvent,
sched[7],
sched[8],
sched[5]
)
#for sch in eg.scheduler.__dict__['heap']:
# if sch[1] == self.plugin.SchedulGhostScheduleRun:
# if sch[2][0] == sched[1]:
# eg.scheduler.CancelTask(sch)
# self.plugin.updateLogFile(self.plugin.text.canc % sch[2][0])
# break
#next = self.plugin.Execute(sched, False, mktime(localtime()), True)
if update:
last = str(dt.now())[:19]
self.plugin.data[ix][4] = last
#next = next[:19] if next else self.plugin.text.none
#self.plugin.updateLogFile(self.text.immedRun % (sched[1], next))
else:
self.PrintError(self.text.notFound % schedule)
return self.text.notFound % schedule
def Configure(self, schedule = "", update=False):
panel = eg.ConfigPanel()
data = self.plugin.data
choices = [item[1] for item in data]
textControl = wx.ComboBox(panel, -1, schedule, size = (300, -1), choices = choices)
updateCtrl = wx.CheckBox(panel, -1, self.text.update)
updateCtrl.SetValue(update)
panel.sizer.Add(wx.StaticText(panel, -1, self.text.scheduleTitle), 0, wx.LEFT | wx.TOP, 10)
panel.sizer.Add(textControl, 0, wx.LEFT, 10)
panel.sizer.Add(updateCtrl, 0, wx.LEFT|wx.TOP, 10)
while panel.Affirmed():
panel.SetResult(textControl.GetValue(),updateCtrl.GetValue())
#===============================================================================
class AddSchedule(eg.ActionBase):
class text:
python_expr = "Python expression:"
descr = u'''<rst>**Add schedule**.
| In the edit box, enter a python expression with the parameters of the plan.
| This may be for example *eg.result*, *eg.event.payload* or the entire list
(in the same format, what you get as a result of the action **"GetSchedule"**, see the documentation of
the python expression in this description.
| This action works in two ways (depending on the existence of the schedule):
| 1. If the schedule with the same title already exists, its parameters are overwritten by the new ones.
| 2. If the title does not yet exist, the schedule is created and added to the list.
| An added schedule will not be saved automatically in SchedulGhost.xml. To save the added schedule use the
SchedulGhost manager or the action "DataToXML".
This is the syntax of the python expression::
[enabled?, u'scheduleTitle', scheduleType, [expressionScheduleType], u'dateLastRun timeLastRun',
u'eventPrefix', u'startEventSuffix', u'stopEventSuffix', u'eventPayload']
| These are the different schedule types and them expressions:
* 0 (only once (or yearly)): u'startEventTime', u'span', u'date', repeatYearly?
* 1 (daily): u'startEventTime', u'span'
* 2 (weekly): u'startEventTime', u'span', daysWeek, DoNotTriggerOnAHoliday?,\
TriggerNotChosenDayOnAHoliday?
* 3 (monthly / weekday): u'startEventTime', u'span', orderOfDay, daysWeek, monthsYear(Jan-Jun),\
monthsYear(Jul-Dec), DoNoTriggerOnAHoliday?
* 4 (monthly / day): u'startEventTime', u'span', daysMonth(1-8), daysMonth(9-16),\
daysMonth(17-24), daysMonth(24-31), monthsYear(Jan-Jun), monthsYear(Jul-Dec)
* 5 (periodically): u'startEventTime', u'span', u'date', periodEventRepeat, timeFormat
* 6 (time span): u'00:00:00', u'span'
Explanation:
* enabled? = boolean expression if it is true or false (0 = false; 1 = true)
* u'scheduleTitle' = expression with a unicode string (wake_me_up)
* scheduleType = a number
* date = year-month-day (2012-12-31)
* time and span = hours:minutes:seconds (23:59:59)
* orderOfDay = sum of the days (first = 1, second = 2; thirt = 4, ..., last = 32)
* daysWeek = sum of the days (Monday = 1, Tuesday = 2; Wednesday = 4, ..., Sunday = 64)
* monthsYear(Jan-Jul) = sum of the months (January = 1, ..., June = 32)
* monthsYear(Jul-Dec) = sum of the months (July = 1, ..., December = 32)
* timeFormat: seconds = 0, minutes = 1, hours = 2, days = 3, weeks = 4, months = 5, years = 6
::
Make sure to use '\\\\' instead of '\\' within a string literal if you use this function in a python script.
'''
def __call__(self, expr = ""):
schedule = eg.ParseString(expr)
schedule = eval(schedule)
if len(schedule) == 9 and isinstance(schedule[1], unicode):
data = self.plugin.data
tmpLst = [item[1] for item in data]
if schedule[1] in tmpLst:
ix = tmpLst.index(schedule[1])
if data[ix][0]:
data[ix][0] = 0
self.plugin.UpdateEGscheduler()
data[ix] = cpy(schedule)
else:
data.append(schedule)
self.plugin.UpdateEGscheduler()
if self.plugin.dialog:
wx.CallAfter(self.plugin.dialog.AddSchedule, schedule)
def Configure(self, expr = ""):
panel = eg.ConfigPanel(resizable = True)
textControl = wx.TextCtrl(panel, -1, expr, size = (300,-1), style = wx.TE_MULTILINE )
panel.sizer.Add(wx.StaticText(panel,-1,self.text.python_expr), 0,wx.LEFT | wx.TOP, 10)
panel.sizer.Add(textControl, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 10)
while panel.Affirmed():
panel.SetResult(textControl.GetValue())
#===============================================================================
class PopupText(wx.Frame):
def __init__(
self,
parent,
plugin,
args,
panel,
sound = None
):
wx.Frame.__init__(
self,
parent,
-1,
'',
size = (120, 60),
style = wx.STAY_ON_TOP | wx.SIMPLE_BORDER
)
self.delta = (0,0)
self.args = args
self.panel = panel
self.sound = sound
self.SetTitle(plugin.text.popupTitle)
label = self.label = wx.StaticText(self, -1, "")
if panel:
panel.popupFrame = self
tip = plugin.text.popupTip2
else:
self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
label.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
tip = plugin.text.popupTip1 % str(dt.now())[:19]
label.SetToolTipString(tip)
self.SetColor(fore = self.args[2], back = self.args[1])
self.UpdateText(txt = self.args[0], font = wx.FontFromNativeInfoString(self.args[3]))
self.SetPosition(self.args[4])
self.Show(True)
BringWindowToTop(self.GetHandle())
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
label.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
label.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
label.Bind(wx.EVT_MOTION, self.OnMouseMove)
def OnCloseWindow(self, event):
if self.sound:
self.sound.Stop()
self.Destroy()
event.Skip()
def OnRightClick(self, evt):
self.Show(False)
self.Close()
def OnLeftDown(self, evt):
self.CaptureMouse()
x, y = self.ClientToScreen(evt.GetPosition())
originx, originy = self.GetPosition()
dx = x - originx
dy = y - originy
self.delta = ((dx, dy))
def OnLeftUp(self, evt):
if self.HasCapture():
self.ReleaseMouse()
if self.panel:
self.panel.SetIsDirty(True)
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
x, y = self.ClientToScreen(evt.GetPosition())
fp = (x - self.delta[0], y - self.delta[1])
self.Move(fp)
def UpdateText(self, txt = None, font = None):
border = 10
if font:
self.label.SetFont(font)
if txt is not None:
self.label.SetLabel(txt)
sz = self.label.GetSize()
self.SetClientSize((border + sz[0], border + sz[1]))
self.label.SetPosition((border / 2, border / 2))
def SetColor(self, fore = None, back = None):
if back:
self.SetBackgroundColour(back)
if fore:
self.label.SetForegroundColour(fore)
self.Refresh()
#===============================================================================
class EggTimerFrame(wx.Frame):
def __init__(self, text, plugin, args):
self.plugin = plugin
wx.Frame.__init__(
self,
None,
-1,
args[4] if args[4] else text.title,
style = wx.DEFAULT_DIALOG_STYLE | wx.CLOSE_BOX | wx.TAB_TRAVERSAL ,
name = text.title
)
self.SetIcon(self.plugin.info.icon.GetWxIcon())
self.plugin.eggTimer = self
self.text = text
self.args = args
self.val = args[0]
self.SetBackgroundColour(wx.NullColour)
durLabel = wx.StaticText(self, -1, text.timeLbl)
initTime = wx.DateTime_Now()
initTime.SetSecond(0)
initTime.AddTS(wx.TimeSpan.Minute())
timeCtrl = eg.TimeCtrl_Duration(self, -1, self.val, fmt24hr = True, style = wx.BORDER_SUNKEN)
fnt = timeCtrl.GetFont()
fnt.SetPointSize(4 * fnt.GetPointSize())
timeCtrl.SetFont(fnt)
h = timeCtrl.GetSize()[1]
spinBtn = wx.SpinButton(self, -1, (-1, -1), (h / 2, h), wx.SP_VERTICAL)
timeCtrl.BindSpinButton(spinBtn)
self.startBtn = wx.Button(self, -1, text.startBtn)
self.startBtn.SetDefault()
fnt = self.startBtn.GetFont()
fnt.SetPointSize(2 * fnt.GetPointSize())
self.startBtn.SetFont(fnt)
mainSizer = wx.GridBagSizer(2, 2)
mainSizer.Add(durLabel, (0, 0))
mainSizer.Add(timeCtrl, (1, 0))
mainSizer.Add(spinBtn, (1, 1))
mainSizer.Add((-1, 1), (2, 0))
mainSizer.Add(self.startBtn, (3, 0), (1,2), flag = wx.EXPAND)
Sizer = wx.BoxSizer(wx.VERTICAL)
Sizer.Add(mainSizer, 0, wx.ALL, 5)
self.SetSizer(Sizer)
Sizer.Layout()
self.SetClientSize(Sizer.GetMinSize())
if self.plugin.eggPos:
self.SetPosition(self.plugin.eggPos)
else:
self.Center()
self.Bind(wx.EVT_CLOSE, self.onClose)
self.startBtn.Bind(wx.EVT_BUTTON, self.onStart)
timeCtrl.Bind(maskedlib.EVT_TIMEUPDATE, self.OnTimeChange)
self.Bind(wx.EVT_CHAR_HOOK, self.onFrameCharHook)
#self.MakeModal(True)
self.Show(True)
self.startBtn.Show(self.val != "00:00:00")
timeCtrl.SetSelection(3, 5)
def onFrameCharHook(self, evt):
if evt.GetKeyCode() == wx.WXK_ESCAPE:
self.Close()
else:
evt.Skip()
def OnTimeChange(self, evt):
self.val = evt.GetValue()
self.startBtn.Show(self.val != "00:00:00")
evt.Skip()
def onStart(self, evt):
self.plugin.AddEggTimer(self.val, self.args)
self.Close()
evt.Skip()
def onClose(self, evt):
#self.MakeModal(False)
self.plugin.eggPos = self.GetPosition()
self.plugin.eggTimer = None
wx.CallAfter(self.Show, False)
wx.CallAfter(self.Destroy)
evt.Skip()
#===============================================================================
class EggTimersList(wx.Frame):
def __init__(self, text, plugin):
self.plugin = plugin
wx.Frame.__init__(
self,
None,
-1,
text.title,
style = wx.DEFAULT_DIALOG_STYLE | wx.CLOSE_BOX | wx.TAB_TRAVERSAL | wx.RESIZE_BORDER,
name = text.title
)
self.SetIcon(self.plugin.info.icon.GetWxIcon())
self.plugin.eggTimersList = self
self.text = text
self.SetBackgroundColour(wx.NullColour)
if self.plugin.eggListPos:
self.SetPosition(self.plugin.eggListPos)
else:
self.Center()
self.Bind(wx.EVT_CLOSE, self.onClose)
self.Bind(wx.EVT_CHAR_HOOK, self.onFrameCharHook)
mainSizer = wx.GridBagSizer(0, 0)
self.SetSizer(mainSizer)
eggListCtrl = wx.ListCtrl(
self,
-1,
style=wx.LC_REPORT|wx.VSCROLL|wx.HSCROLL|wx.LC_HRULES|wx.LC_VRULES
)
#WORKAROUND !!!
#wx.wx.LIST_FORMAT_RIGHT or wx.LIST_FORMAT_CENTRE for first column !!!
eggListCtrl.InsertColumn(0, "", wx.LIST_FORMAT_LEFT) #Dummy column 0 !!!
for i in range(1, len(text.header)+1):
eggListCtrl.InsertColumn(
i,
text.header[i-1],
wx.LIST_FORMAT_CENTRE if i in (2, 5) else wx.LIST_FORMAT_LEFT
)
size = 0
for i in range(6):
if i == 0:
eggListCtrl.SetColumnWidth(i, 0)
elif i == 3:
eggListCtrl.SetColumnWidth(i, 80)
else:
eggListCtrl.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
size += eggListCtrl.GetColumnWidth(i)
eggListCtrl.SetMinSize((size, -1))
eggListCtrl.InsertStringItem(0, "")
rect = eggListCtrl.GetItemRect(0, wx.LIST_RECT_BOUNDS)
hh = rect[1]
hi = rect[3]
self.SetClientSize((size, -1))
self.SetMinSize((1.5*size, -1))
rem2Size = size - eggListCtrl.GetColumnWidth(4) + 4
mainSizer.Add(eggListCtrl, (0,0), (1,1), flag = wx.EXPAND)
mainSizer.AddGrowableRow(0)
mainSizer.AddGrowableCol(0)
def OnSize(event):
eggListCtrl.SetColumnWidth(3, wx.LIST_AUTOSIZE)
w1 = eggListCtrl.GetColumnWidth(3)
eggListCtrl.SetColumnWidth(4, 80 + self.GetClientSize()[0] - rem2Size - w1)
event.Skip()
self.Bind(wx.EVT_SIZE, OnSize)
def FillListCtrl(event=None):
eggListCtrl.DeleteAllItems()
egg_list = eg.scheduler.__dict__['heap']
tmpLst = []
for egg in egg_list:
if egg[1] == self.plugin.SchedulGhost_EggFunction:
tmpLst.append(egg)
cnt = 0
if len(tmpLst) > 0:
tmpLst.sort()
cnt = len(tmpLst)
for row in range(cnt):
args = self.plugin.eggTimers[tmpLst[row][2][0]]
eggListCtrl.InsertStringItem(row, "") #Dummy column 0
eggListCtrl.SetStringItem(row, 1, args[9])
eggListCtrl.SetStringItem(row, 2, Ticks2Delta(mktime(localtime()), tmpLst[row][0]))
eggListCtrl.SetStringItem(row, 3, "%s.%s" % (args[1], args[2]))
eggListCtrl.SetStringItem(row, 4, args[4])
eggListCtrl.SetStringItem(row, 5, self.text.yes if len(args[3]) > 0 else "")
self.SetClientSize((self.GetClientSize()[0], 4 + hh + cnt * hi))
if event:
event.Skip()
self.Bind(wx.EVT_TIMER, FillListCtrl)
self.timer = wx.Timer(self)
self.timer.Start(1000)
FillListCtrl()
self.Show(True)
def onFrameCharHook(self, evt):
if evt.GetKeyCode() == wx.WXK_ESCAPE:
self.Close()
else:
evt.Skip()
def onClose(self, evt):
self.timer.Stop()
del self.timer
self.MakeModal(False)
self.plugin.eggListPos = self.GetPosition()
self.plugin.eggTimersList = None
wx.CallAfter(self.Show, False)
wx.CallAfter(self.Destroy)
evt.Skip()
#===============================================================================
class SetEggTimer(eg.ActionBase):
class text:
title = "SchedulGhost - egg timer"
timeLbl = "Set time to elapse (HH:MM:SS):"
prefLbl = "Event prefix:"
suffLbl = "Event suffix:"
wavLbl = "Play this wav file:"
popLbl = "Show pop-up window with this text:"
foreColour = 'Text colour'
backColour = 'Background colour'
fontBtn = "Pop-up font:"
startBtn = "Start now"
toolTipFile = "Press button and browse to select a wave file ..."
browseFile = 'Select the wav file'
playWav = "Wav file test"
defaultPopup = "Wake up, eggs are cooked !!!"
defaultTime = ("Default time:", "Time to elapse:")
treeLabel = "%s: %s: %s.%s: %s"
defSuffix = "EggTimer"
nameLbl = "Egg timer name:"
def __call__(self, args = [
"00:03:00",
"SchedulGhost",
"EggTimer",
"",
"",
(191, 191, 255),
(64, 0, 128),
"",
(10, 10),
"EggTimer"
]):
if len(args) == 9:
args=list(args)
args.append("EggTimer")
args=tuple(args)
if not self.value:
if not self.plugin.eggTimer:
wx.CallAfter(EggTimerFrame, self.text, self.plugin, args)
else:
self.plugin.AddEggTimer(args[0], args)
def GetLabel(self, args):
if len(args) == 9:
args=list(args)
args.append("EggTimer")
args=tuple(args)
return self.text.treeLabel % (
self.name,
args[9],
args[1],
args[2],
args[4]
)
def Configure(self, args = [
"00:03:00",
"SchedulGhost",
None,
"",
"",
(191, 191, 255),
(64, 0, 128),
"",
(10, 10),
"EggTimer"
]):
panel = self.panel = eg.ConfigPanel()
if len(args) == 9:
args=list(args)
args.append("EggTimer")
args=tuple(args)
self.args = cpy(args)
del args
self.panel.popupFrame = None
if self.args[2] is None:
self.args[2] = self.text.defSuffix
if not self.args[1]:
self.args[1] = self.plugin.prefix
prefCtrl = wx.TextCtrl(panel, -1, self.args[1], size = (100, -1))
suffCtrl = wx.TextCtrl(panel, -1, self.args[2], size = (100, -1))
nameCtrl = wx.TextCtrl(panel, -1, self.args[9], size = (100, -1))
topSizer = wx.GridBagSizer(1,1)
spinBtn = wx.SpinButton(
panel,
-1,
wx.DefaultPosition,
(-1, 22),
wx.SP_VERTICAL
)
defTime = eg.TimeCtrl_Duration(
panel,
-1,
self.args[0],
fmt24hr = True,
spinButton = spinBtn
)
defTime.SetFocus()
defTime.SetSelection(3, 5)
topSizer.Add(wx.StaticText(panel, -1, self.text.defaultTime[self.value]), (0, 0),(1,3))
topSizer.Add(defTime, (1, 0))
topSizer.Add(spinBtn, (1, 1))
topSizer.Add(wx.StaticText(panel, -1, self.text.prefLbl), (0, 3),(1,2))
topSizer.Add(wx.StaticText(panel, -1, self.text.suffLbl), (0, 5))
topSizer.Add(wx.StaticText(panel, -1, self.text.nameLbl), (0, 7))
topSizer.Add(prefCtrl, (1, 3))
topSizer.Add(suffCtrl, (1, 5))
topSizer.Add(nameCtrl, (1, 7))
topSizer.AddGrowableCol(2,1)
topSizer.AddGrowableCol(4,1)
topSizer.AddGrowableCol(6,1)
sizerAdd = panel.sizer.Add
sizerAdd(topSizer,0,wx.LEFT|wx.RIGHT|wx.EXPAND, 10)
sizerAdd((-1,10))
wavCheckBox = wx.CheckBox(panel, -1, self.text.wavLbl)
sizerAdd(wavCheckBox, 0, wx.LEFT| wx.TOP, 10)
wavFileCtrl = MyFileBrowseButton(
panel,
toolTip = self.text.toolTipFile,
dialogTitle = self.text.browseFile,
buttonText = eg.text.General.browse,
startDirectory = eg.folderPath.Music,
fileMask = "*.wav",
)
wavFileCtrl.GetTextCtrl().SetEditable(False)
wavFileCtrl.GetTextCtrl().SetValue(self.args[3])
flg = len(self.args[3]) != 0
wavCheckBox.SetValue(flg)
wavFileCtrl.Enable(flg)
panel.dialog.buttonRow.testButton.SetLabel(self.text.playWav)
panel.dialog.buttonRow.testButton.Enable(flg)
sizerAdd(wavFileCtrl, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
popCheckBox = wx.CheckBox(panel, -1, self.text.popLbl)
popTxtCtrl = wx.TextCtrl(panel, -1, self.args[4])
backColorLbl = wx.StaticText(panel, -1, self.text.backColour + ":")
foreColorLbl = wx.StaticText(panel, -1, self.text.foreColour + ":")
fontLbl = wx.StaticText(panel, -1, self.text.fontBtn)
backColorBtn = eg.ColourSelectButton(
panel,
self.args[5],
title = self.text.backColour
)
foreColorBtn = eg.ColourSelectButton(
panel,
self.args[6],
title = self.text.foreColour
)
fontInfo = self.args[7]
if fontInfo == "":
font = fontLbl.GetFont()
font.SetPointSize(42)
fontInfo = font.GetNativeFontInfoDesc()
fontBtn = eg.FontSelectButton(panel, value = fontInfo)
popSizer = wx.FlexGridSizer(2,5,0,0)
popSizer.AddGrowableCol(1,1)
popSizer.AddGrowableCol(3,1)
popSizer.Add(fontLbl)
popSizer.Add((-1,1))
popSizer.Add(foreColorLbl)
popSizer.Add((-1,1))
popSizer.Add(backColorLbl)
popSizer.Add(fontBtn)
popSizer.Add((-1,1))
popSizer.Add(foreColorBtn)
popSizer.Add((-1,1))
popSizer.Add(backColorBtn)
sizerAdd((-1,8))
sizerAdd(popCheckBox, 0, wx.TOP | wx.LEFT | wx.EXPAND, 10)
sizerAdd((-1,1))
sizerAdd(popTxtCtrl, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
sizerAdd((-1,8))
sizerAdd(popSizer, 0, wx.EXPAND |wx.LEFT| wx.RIGHT, 10)
panel.sizer.Layout()
def EnablePopUp(enable):
popTxtCtrl.Enable(enable)
fontLbl.Enable(enable)
fontBtn.Enable(enable)
foreColorLbl.Enable(enable)
foreColorBtn.Enable(enable)
backColorLbl.Enable(enable)
backColorBtn.Enable(enable)
val = len(self.args[4]) != 0
popCheckBox.SetValue(val)
EnablePopUp(val)
if val:
wx.CallAfter(
PopupText,
None,
self.plugin,
self.args[4:],
self.panel,
)
def onPopCheckBox(evt):
val = evt.IsChecked()
EnablePopUp(val)
if val:
popTxtCtrl.ChangeValue(self.text.defaultPopup)
wx.CallAfter(
PopupText,
None,
self.plugin,
( popTxtCtrl.GetValue(),
backColorBtn.GetValue(),
foreColorBtn.GetValue(),
fontBtn.GetValue(),
self.args[8]),
self.panel,
)
else:
popTxtCtrl.ChangeValue("")
self.panel.popupFrame.Close()
evt.Skip()
popCheckBox.Bind(wx.EVT_CHECKBOX, onPopCheckBox)
def OnPopTxtChange(evt):
if self.panel.popupFrame:
self.panel.popupFrame.UpdateText(txt = evt.GetString())
evt.Skip()
popTxtCtrl.Bind(wx.EVT_TEXT, OnPopTxtChange)
def onWavCheckBox(evt):
val = evt.IsChecked()
wavFileCtrl.Enable(val)
if not val:
wavFileCtrl.GetTextCtrl().ChangeValue("")
panel.dialog.buttonRow.testButton.Enable(False)
evt.Skip()
wavCheckBox.Bind(wx.EVT_CHECKBOX, onWavCheckBox)
def OnWavFile(evt):
val = evt.GetString() != ""
panel.dialog.buttonRow.testButton.Enable(val)
evt.Skip()
wavFileCtrl.Bind(wx.EVT_TEXT, OnWavFile)
def OnFontBtn(evt):
if self.panel.popupFrame:
font = wx.FontFromNativeInfoString(evt.GetValue())
self.panel.popupFrame.UpdateText(font = font)
evt.Skip()
fontBtn.Bind(eg.EVT_VALUE_CHANGED, OnFontBtn)
def OnColourBtn(evt):
if self.panel.popupFrame:
id = evt.GetId()
value = evt.GetValue()
if id == foreColorBtn.GetId():
self.panel.popupFrame.SetColor(fore = value)
else:
self.panel.popupFrame.SetColor(back = value)
evt.Skip()
foreColorBtn.Bind(eg.EVT_VALUE_CHANGED, OnColourBtn)
backColorBtn.Bind(eg.EVT_VALUE_CHANGED, OnColourBtn)
def OnCancelBtn(evt):
if self.panel.popupFrame:
self.panel.popupFrame.Close()
self.panel.popupFrame = None
evt.Skip()
panel.dialog.buttonRow.cancelButton.Bind(wx.EVT_BUTTON, OnCancelBtn)
def OnApplyBtn(evt):
panel.dialog.buttonRow.applyButton.Enable(False)
panel.dialog.buttonRow.applyButton.Bind(wx.EVT_BUTTON, OnApplyBtn)
def OnTestBtn(evt):
file = wavFileCtrl.GetTextCtrl().GetValue()
sound = wx.Sound(file)
if os.path.isfile(file) and sound.IsOk():
sound.Play(wx.SOUND_ASYNC)
else:
self.PrintError(self.plugin.text.soundProblem % file)
PlaySound('SystemExclamation', SND_ASYNC)
panel.dialog.buttonRow.testButton.Bind(wx.EVT_BUTTON, OnTestBtn)
def OnCloseBox(evt):
if self.panel.popupFrame:
self.panel.popupFrame.Close()
self.panel.popupFrame = None
evt.Skip()
panel.dialog.Bind(wx.EVT_CLOSE, OnCloseBox)
while panel.Affirmed():
if self.panel.popupFrame:
popPos = self.panel.popupFrame.GetPosition()
self.panel.popupFrame.Close()
self.panel.popupFrame = None
else:
popPos = self.args[8]
panel.SetResult((
defTime.GetValue(),
prefCtrl.GetValue(),
suffCtrl.GetValue(),
wavFileCtrl.GetTextCtrl().GetValue(),
popTxtCtrl.GetValue(),
backColorBtn.GetValue(),
foreColorBtn.GetValue(),
fontBtn.GetValue(),
popPos,
nameCtrl.GetValue(),
),)
#===============================================================================
class ShowRunningEggTimers(eg.ActionBase):
class text:
title = "SchedulGhost: Currently running egg-timers"
yes = "Yes"
header = (
"Timer name",
"Remaining time",
"Event string",
"Pop-up text",
"Play wave",
)
def __call__(self):
if not self.plugin.eggTimersList:
wx.CallAfter(EggTimersList, self.text, self.plugin)
else:
wx.CallAfter(self.plugin.eggTimersList.Raise)
#===============================================================================
class AbortEggTimers(eg.ActionBase):
def __call__(self):
self.plugin.AbortEggTimers()
#===============================================================================
class DataToXML(eg.ActionBase):
def __call__(self):
self.plugin.dataToXml()
#===============================================================================
class ReloadXML(eg.ActionBase):
def __call__(self):
self.plugin.data = self.plugin.xmlToData()
self.plugin.tmpData = cpy(self.plugin.data)
self.plugin.UpdateEGscheduler()
if self.plugin.dialog:
self.plugin.dialog.onClose(wx.CommandEvent())
wx.CallAfter(
schedulerDialog,
self.plugin.text.ShowSchedulGhost,
self.plugin
)
#===============================================================================
class AbortEggTimer(eg.ActionBase):
class text:
lbl = "Egg timer name:"
def __call__(self, ttl = ""):
ttl = eg.ParseString(ttl)
self.plugin.AbortEggTimers(ttl)
def Configure(self, ttl = ""):
panel = eg.ConfigPanel()
lbl = wx.StaticText(panel, -1, self.text.lbl)
eggCtrl = wx.TextCtrl(panel, -1, ttl)
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
mainSizer.Add(lbl,0,wx.ALIGN_CENTER_VERTICAL)
mainSizer.Add(eggCtrl,1,wx.EXPAND|wx.LEFT, 8)
panel.sizer.Add(mainSizer,0,wx.EXPAND|wx.ALL, 10)
while panel.Affirmed():
panel.SetResult(
eggCtrl.GetValue(),
)
#===============================================================================
Actions = (
(SetEggTimer, "SetEggTimer", "Adjust and start egg timer", "Adjust and start egg timer.", 0),
(SetEggTimer, "StartEggTimer", "Start egg timer", "Start egg timer immediately (without the possibility to adjust the time to elapse).", 1),
(ShowRunningEggTimers, "ShowRunningEggTimers", "Show currently running egg-timers", "Shows currently running egg-timers.", None),
(AbortEggTimer, "AbortEggTimer", "Abort egg timer by name", "Aborts egg timer by name.", None),
(AbortEggTimers, "AbortEggTimers", "Abort egg timer(s)", "Abort egg timer(s).", None),
(ShowSchedulGhost, "ShowSchedulGhost", "Show SchedulGhost", "Show SchedulGhost manager.", None),
(HideSchedulGhost, "HideSchedulGhost", "Hide SchedulGhost", "Hide SchedulGhost manager.", None),
(EnableSchedule, "EnableSchedule", "Enable schedule", "Enable schedule.", 1),
(EnableSchedule, "DisableSchedule", "Disable schedule", "Disable schedule.", 0),
(EnableAll, "EnableAll", "Enable all schedules", "Enable all schedules.", 1),
(EnableAll, "DisableAll", "Disable all schedules", "Disable all schedules.", 0),
(EnableSchedule, "GetSchedule", "Get schedule", "Get schedule.", -1),
(AddSchedule, "AddSchedule", "Add schedule", AddSchedule.text.descr, None),
(DeleteSchedule, "DeleteSchedule", "Delete schedule", "Delete schedule.", None),
(RunScheduleImmediately, "RunScheduleImmediately", "Run schedule immediately", "Runs schedule immediately.", None),
(RunScheduleImmediately, "ForceScheduleImmediately", "Force to run schedule immediately", "Force starts schedule immediately.", True),
(DataToXML, "DataToXML", "Save data to xml", "Saves data to xml.", None),
(ReloadXML, "ReloadXML", "Reload data from xml", "Reloads data from xml.", None),
)