""" This file is part of RuneOptimizer. RuneOptimizer 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 3 of the License, or (at your option) any later version. RuneOptimizer 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 RuneOptimizer. If not, see . """ class PanelTeams(wx.Panel): """ The team management Panel. Lists teams, and allows for team creation and deletion, and for ading and removing units to and from teams. """ _selected_team = None _title_change_pending = False _priority_change_pending = False _team_list = None _details_sizer = None _title_text = None _priority_text = None _team_unit_list = None _all_unit_list = None _filter_name_text = None _filter_name_texts = None _filter_no_runes_check = None _filter_no_teams_check = None _title_timer = None _priority_time = None def __init__(self, parent, id=wx.ID_ANY): """Initializes the panel. Sets upt all the widgets. Parameters ---------- parent : wx.* Panel parent. id : int, optional ID for the panel (default wx.ID_ANY). """ # Parent constructor wx.Panel.__init__(self, parent=parent, id=id) # Prepare some fonts bold_font = wx.Font( pointSize=10, family=wx.FONTFAMILY_DEFAULT, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_BOLD ) team_list_box = wx.StaticBox( self, label="Select unit:", id=wx.ID_ANY, pos=(0, 0), size=(270, 590) ) wx.StaticText( parent=team_list_box, id=wx.ID_ANY, label="Name Prio.", pos=(10, 10), size=(240, 20) ).SetFont(bold_font) self._team_list = wx.ListCtrl( parent=team_list_box, id=wx.ID_ANY, pos=(10, 30), size=(250, 460), style=wx.LC_REPORT|wx.LC_NO_HEADER ) self._team_list.InsertColumn(0, "Name", width=200) self._team_list.InsertColumn(1, "Prio.", width=40) self._populate_team_list(event=None) self._team_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self._team_selected) new_team_button = wx.Button( parent=team_list_box, id=wx.ID_ANY, pos=(50, 510), size=(170, 40), style=wx.LC_REPORT, label="New team" ) new_team_button.Bind(wx.EVT_BUTTON, self._create_team) # Sizer for all team details. Will be hidden until a team is selected self._details_sizer = wx.BoxSizer(wx.VERTICAL) # Team title and priority editors self._title_text = wx.TextCtrl( parent=self, id=wx.ID_ANY, pos=(300, 30), size=(200, 25), style=wx.TE_RICH|wx.TE_MULTILINE ) self._details_sizer.Add(self._title_text) self._title_text.Bind(wx.EVT_TEXT, self._change_title); self._details_sizer.Add( wx.StaticText( parent=self, id=wx.ID_ANY, label="Priority:", pos=(310, 80), size=(80, 30) ) ) self._priority_text = wx.TextCtrl( parent=self, id=wx.ID_ANY, pos=(360, 80), size=(30, 25), style=wx.TE_RICH|wx.TE_MULTILINE) self._details_sizer.Add(self._priority_text) self._priority_text.Bind(wx.EVT_TEXT, self._change_priority); # Team unit list team_units_box = wx.StaticBox( parent=self, label="Units in team:", id=wx.ID_ANY, pos=(300, 130), size=(150, 380) ) self._team_unit_list = wx.ListCtrl( parent=team_units_box, id=wx.ID_ANY, pos=(5, 5), size=(140, 360), style=wx.LC_REPORT|wx.LC_NO_HEADER ) self._details_sizer.Add(team_units_box) self._team_unit_list.InsertColumn(0, "Name", width=140) self._team_unit_list.InsertColumn(1, "Level", width=140) # All unit selector all_units_box = wx.StaticBox( parent=self, label="Other units:", id=wx.ID_ANY, pos=(600, 130), size=(210, 380) ) self._details_sizer.Add(all_units_box) wx.StaticText( parent=all_units_box, id=wx.ID_ANY, label="Name Prio. Sto.", pos=(10, 10), size=(190, 20) ).SetFont(bold_font) self._all_unit_list = wx.ListCtrl( parent=all_units_box, id=wx.ID_ANY, pos=(10, 30), size=(190, 165), style=wx.LC_REPORT|wx.LC_NO_HEADER ) self._details_sizer.Add(self._all_unit_list) self._all_unit_list.InsertColumn(0, "Name", width=120) self._all_unit_list.InsertColumn(1, "Prio.", width=40) self._all_unit_list.InsertColumn(2, "Sto.", width=30) # List filters filter_box = wx.StaticBox( parent=all_units_box, label="Filters:",id=wx.ID_ANY, pos=(10, 200), size=(190, 150) ) self._details_sizer.Add(filter_box) wx.StaticText( parent=filter_box, label="Monster name", pos=(5, 5), size=(180, 20) ) self._filter_name_text = wx.TextCtrl( parent=filter_box, id=wx.ID_ANY, value="", pos=(5, 25), size=(177, 20), style=wx.TE_PROCESS_ENTER|wx.TE_PROCESS_TAB ) self._filter_name_text.Bind(wx.EVT_TEXT, self._populate_unit_list) self._filter_storage_check = wx.CheckBox( parent=filter_box, id=wx.ID_ANY, label="Monsters in storage", pos=(5, 55), size=(180, 20) ) self._filter_storage_check.SetValue(True) self._filter_storage_check.Bind(wx.EVT_CHECKBOX, self._populate_unit_list) self._filter_no_runes_check = wx.CheckBox( parent=filter_box, id=wx.ID_ANY, label="Monsters without runes", pos=(5, 75), size=(180, 20) ) self._filter_no_runes_check.SetValue(True) self._filter_no_runes_check.Bind( wx.EVT_CHECKBOX, self._populate_unit_list ) self._filter_no_teams_check = wx.CheckBox( parent=filter_box, id=wx.ID_ANY, label="Monsters not in teams", pos=(5, 95), size=(180, 20) ) self._filter_no_teams_check.SetValue(True) self._filter_no_teams_check.Bind( wx.EVT_CHECKBOX, self._populate_unit_list ) self._populate_unit_list(None) add_button = wx.Button( parent=self, id=wx.ID_ANY, pos=(450, 200), size=(150, 40), style=wx.LC_REPORT, label="<<< Add <<<" ) self._details_sizer.Add(add_button) add_button.Bind(wx.EVT_BUTTON, self._add_to_team) remove_button = wx.Button( parent=self, id=wx.ID_ANY, pos=(450, 250), size=(150, 40), style=wx.LC_REPORT, label=">>> Remove >>>" ) self._details_sizer.Add(remove_button) remove_button.Bind(wx.EVT_BUTTON, self._remove_from_team) delete_button = wx.Button( parent=self, id=wx.ID_ANY, pos=(300, 530), size=(150, 40), style=wx.LC_REPORT, label="Delete team" ) self._details_sizer.Add(delete_button) delete_button.Bind(wx.EVT_BUTTON, self._delete_team) # By default, hide all details self._details_sizer.ShowItems(False) def _populate_team_list(self, event=None): """Populates the team list. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ self._team_list.DeleteAllItems() i = 0 for team in teams.values(): self._team_list.InsertItem(i, team.name) self._team_list.SetItem(i, 1, str(team.priority)) self._team_list.SetItemData(i, int(team.id)) i = i + 1 def _populate_unit_list(self, event=None): """Populates the list of all units. Uses the filters. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ # Loop all units i = 0 filter_name = self._filter_name_text.GetValue() opt_storage = self._filter_storage_check.GetValue() opt_no_runes = self._filter_storage_check.GetValue() opt_no_teams = self._filter_no_teams_check.GetValue() self._all_unit_list.DeleteAllItems() for unit in units.values(): if opt_storage == False and unit.in_storage == True: continue if opt_no_runes == False and unit.has_runes == False: continue if opt_no_teams == False and unit.in_teams == False: continue if len(filter_name) > 0: if filter_name.upper() not in unit.name.upper(): continue self._all_unit_list.InsertItem(i, unit.name) self._all_unit_list.SetItem(i, 1, str(unit.priority)) if (unit.in_storage): self._all_unit_list.SetItem(i, 2, "X") else: self._all_unit_list.SetItem(i, 2, " ") # TODO Items can't hold too much data in Windows, store the first # nine digits and rerieve it from database with LIKE self._all_unit_list.SetItemData(i, int(unit.id)) i = i + 1 def _populate_team_unit_list(self, event=None): """Populates the list of units in the selected team. Uses the filters. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ i = 0 self._team_unit_list.DeleteAllItems() for unit in self._team_selected.units: self._team_unit_list.InsertItem(i, unit.name) self._team_unit_list.SetItem(i, 1, "Lv." + str(unit.level)) self._team_unit_list.SetItemData(i, int(unit.id)) i = i + 1 def _create_team(self, event=None): """Opens a dialog to create a new team. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ with DialogNewTeam(parent=self) as dlg: if dlg.ShowModal() == wx.ID_OK: reload_teams() self._populate_team_list() def _delete_team(self, event=None): """Deletes a team. Shows a confirmation dialog first. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ message = "Are you sure you want to delete the team " + \ self._team_selected.name + "?\n\nThis can't be undone." with DialogConfirm(parent=self, message=message) as dlg: if dlg.ShowModal() == wx.ID_OK: # TODO: Do this with a command cursor = conn.execute( "DELETE FROM units_teams WHERE team = ?", (self._team_selected.id,)) cursor = conn.execute( "DELETE FROM teams WHERE id = ?", (self._team_selected.id,) ) conn.commit() reload_teams() # Clear the selection and hide the details self._details_sizer.ShowItems(False) self._populate_team_list(event=None) self.GetParent().panel_units.populate_unit_list(event=None) def _add_to_team(self, event=None): """Adds unit to the currently selected team. Adds all the units selected in self._all_unit_list. Refreshes both unit lists and also the unit list in the units panel. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ selected_index = self._all_unit_list.GetFirstSelected() while (selected_index != -1): unitId = self._all_unit_list.GetItemData(selected_index) # TODO: Do this with a command query = "INSERT INTO units_teams (team, unit) VALUES (?, ?)"; cursor = conn.execute(query, (self._team_selected.id, unitId)) selected_index = self._all_unit_list.GetNextSelected(selected_index) conn.commit() reload_teams(); self._populate_team_unit_list(event=None) self._populate_unit_list(event=None) self.GetParent().panel_units.populate_unit_list(event=None) def _remove_from_team(self, event=None): """Removes units the currently selected team. Removes all the units selected in self._team_unit_list. Refreshes both unit lists and also the unit list in the units panel. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ selected_index = self._team_unit_list.GetFirstSelected() while (selected_index != -1): unitId = self._team_unit_list.GetItemData(selected_index) # TODO: Do this with a command query = "DELETE FROM units_teams WHERE team = ? AND unit = ?"; cursor = conn.execute(query, (self._team_selected.id, unitId)) selected_index = self._team_unit_list.GetNextSelected(selected_index) conn.commit() reload_teams() self._populate_team_unit_list(event=None) self._populate_unit_list(event=None) self.GetParent().panel_units.populate_unit_list(event=None) def _team_selected(self, event=None): """Shows the team details. Called when a team is selected. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ selected_team_id = \ str(self._team_list.GetItemData(self._team_list.GetFirstSelected())) self._team_selected = teams[selected_team_id] self._populate_team_unit_list(event=None) # Unbind for the automatic change self._title_text.Unbind(wx.EVT_TEXT) self._title_text.SetValue(self._team_selected.name) # Rebind self._title_text.Bind(wx.EVT_TEXT, self._change_title); # Unbind for the automatic change self._priority_text.Unbind(wx.EVT_TEXT); self._priority_text.SetValue(str(self._team_selected.priority)) # Rebind self._priority_text.Bind(wx.EVT_TEXT, self._change_priority); # Show details self._details_sizer.ShowItems(True) def _change_title(self, event): """Prepares for a title change. Called everytime the selected team name is changed. It schedules a call to self._save_new_title in two seconds, to give the user time to enter the full title. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ self._title_change_pending = True self._title_timer = wx.Timer(self) self._title_timer.Bind(wx.EVT_TIMER, self._save_new_title) self._title_timer.StartOnce(2000) def _save_new_title(self, event=None): """Saves the team name to the database. Called two seconds after the last change in self._title_text. If the name is not valid (i.e. less than two characters), it doesn't apply the change and sets the font color to red to indicate error. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ if (self._title_change_pending): new_title = self._title_text.GetValue().replace("\n", "").strip() self._title_change_pending = False if len(new_title.replace(" ", "")) > 2: self._title_text.SetStyle( 0, len(self._title_text.GetValue()), wx.TextAttr(colText=wx.BLACK) ) # TODO: Do this with a command query = "UPDATE teams SET name = ? WHERE id = ?"; cursor = conn.execute(query, (new_title, self._team_selected.id)) conn.commit() reload_teams() self._populate_team_list(event=None) else: monospaceFont = wx.Font( pointSize=8, family=wx.FONTFAMILY_TELETYPE, style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_NORMAL ) self._title_text.SetStyle( 0, len(self._title_text.GetValue()), wx.TextAttr(colText=wx.RED) ) def _change_priority(self, event): """Prepares for a priority change. Called everytime the selected team priority is changed. It schedules a call to self._save_new_priority in two seconds, to give the user time to enter the full text. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ self._priority_change_pending = True self._priority_time = wx.Timer(self) self._priority_time.Bind(wx.EVT_TIMER, self._save_new_priority) self._priority_time.StartOnce(2000) def _save_new_priority(self, event=None): """Saves the team priority to the database. Called two seconds after the last change in self._priority_text. If the priority is not valid (i.e. not a number, lower than 0 or greater than 50), it doesn't apply the change and sets the font color to red to indicate error. Parameters ---------- event : wx.Event, optional The event that triggered the call (default is None). """ if (self._priority_change_pending): new_priority = self._priority_text.GetValue().replace("\n", "").strip() self._priority_change_pending = False if new_priority.isnumeric() and \ int(new_priority) >= 0 and int(new_priority) <= 50: self._priority_text.SetStyle( 0, len(self._priority_text.GetValue()), wx.TextAttr(colText=wx.BLACK) ) # TODO Do this with a command, when there is a command to do it. query = "UPDATE teams SET priority = ? WHERE id = ?"; cursor = conn.execute(query, (new_priority, self._team_selected.id)) conn.commit() reload_teams() self._populate_team_list(event=None) self.GetParent().panel_units.populate_unit_list(event=None) else: self._priority_text.SetStyle( 0, len(self._priority_text.GetValue()), wx.TextAttr(colText=wx.RED) )