| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- """
- 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 <https://www.gnu.org/licenses/>.
- """
- 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)
- )
|