]> git.phdru.name Git - m_librarian.git/blob - m_librarian/wx/ListBooks.py
Feat(wx): Wrap long lines
[m_librarian.git] / m_librarian / wx / ListBooks.py
1 # coding: utf-8
2
3 import wx, wx.grid  # noqa: E401 multiple imports on one line
4 from ..compat import string_type, unicode_type
5 from ..download import download
6 from ..translations import translations
7 from .Grids import GridWindow, GridPanel
8
9
10 _ = getattr(translations, 'ugettext', None) or translations.gettext
11
12
13 class BooksDataTable(wx.grid.GridTableBase):
14     def __init__(self, rows_count, column_names):
15         wx.grid.GridTableBase.__init__(self)
16         self.rows_count = rows_count
17         self.column_names = column_names
18         self.data = []
19         for row in range(rows_count + 1):
20             row_data = []
21             self.data.append(row_data)
22             for col in range(len(column_names)):
23                 row_data.append('')
24
25     # required methods for the wxPyGridTableBase interface
26
27     def GetNumberRows(self):
28         return self.rows_count
29
30     def GetNumberCols(self):
31         return len(self.column_names)
32
33     def IsEmptyCell(self, row, col):
34         return False
35
36     # Get/Set values in the table.  The Python version of these
37     # methods can handle any data-type, (as long as the Editor and
38     # Renderer understands the type too,) not just strings as in the
39     # C++ version.
40     def GetValue(self, row, col):
41         return self.data[row][col]
42
43     def SetValue(self, row, col, value):
44         self.data[row][col] = value
45
46     # Optional methods
47
48     # Called when the grid needs to display labels
49     def GetRowLabelValue(self, row):
50         return str(row)
51
52     def GetColLabelValue(self, col):
53         return _(self.column_names[col])
54
55     # Called to determine the kind of editor/renderer to use by
56     # default, doesn't necessarily have to be the same type used
57     # natively by the editor/renderer if they know how to convert.
58     def GetTypeName(self, row, col):
59         if col == 0:
60             return wx.grid.GRID_VALUE_BOOL
61         else:
62             return wx.grid.GRID_VALUE_STRING
63
64     # Called to determine how the data can be fetched and stored by the
65     # editor and renderer.  This allows you to enforce some type-safety
66     # in the grid.
67     def CanGetValueAs(self, row, col, typeName):
68         colType = self.GetTypeName(row, col)
69         if typeName == colType:
70             return True
71         else:
72             return False
73
74     def CanSetValueAs(self, row, col, typeName):
75         return self.CanGetValueAs(row, col, typeName)
76
77
78 class ListBooksPanel(GridPanel):
79
80     def InitGrid(self):
81         books_by_author = self.param['books_by_author']
82         columns = self.param['columns']
83         columns.insert(0, u'Выбрать')
84         total_rows = 0
85         for author in books_by_author:
86             books = books_by_author[author]
87             series = {book.series for book in books}
88             total_rows += len(books) + len(series) + 1
89         grid = self.grid
90         grid.SetTable(
91             BooksDataTable(total_rows+1, columns),
92             takeOwnership=True,
93         )
94         grid.EnableEditing(False)
95         for col, col_name in enumerate(columns):
96             grid.AutoSizeColLabelSize(col)
97             if col == 0:
98                 cell_attr = wx.grid.GridCellAttr()
99                 cell_attr.SetAlignment(wx.ALIGN_CENTRE, wx. ALIGN_CENTRE)
100                 grid.SetColAttr(col, cell_attr)
101             elif col_name in ('ser_no', 'size'):
102                 cell_attr = wx.grid.GridCellAttr()
103                 cell_attr.SetAlignment(wx.ALIGN_RIGHT, wx. ALIGN_CENTRE)
104                 grid.SetColAttr(col, cell_attr)
105         row = 0
106         grid.SetCellAlignment(row, 1, wx.ALIGN_CENTRE, wx. ALIGN_CENTRE)
107         grid.SetCellSize(row, 1, 1, len(columns)-1)
108         row = 1
109         self.book_by_row = book_by_row = {}  # map {row: book}
110         self.toggle_rows = toggle_rows = {}  # map {row: [list of subrows]}
111         autowrap_renderer = wx.grid.GridCellAutoWrapStringRenderer()
112         for author in sorted(books_by_author):
113             grid.SetCellAlignment(row, 1, wx.ALIGN_LEFT, wx. ALIGN_CENTRE)
114             grid.SetCellSize(row, 1, 1, len(columns)-1)
115             grid.SetCellValue(row, 1, u'%s' % (author,))
116             author_row = row
117             toggle_rows[author_row] = []
118             row += 1
119             books = books_by_author[author]
120             series = None
121             for book in books:
122                 if book.series != series:
123                     if book.series:
124                         value = book.series
125                     else:
126                         value = u'Вне серий'
127                     grid.SetCellAlignment(row, 1,
128                                           wx.ALIGN_LEFT, wx. ALIGN_CENTRE)
129                     grid.SetCellSize(row, 1, 1, len(columns)-1)
130                     grid.SetCellValue(row, 1,
131                                       u'%s — %s' % (book.author1, value))
132                     series_row = row
133                     toggle_rows[author_row].append(row)
134                     toggle_rows[series_row] = []
135                     row += 1
136                     series = book.series
137                 for col, col_name in enumerate(columns[1:]):
138                     if col_name in (
139                         'author1', 'author_list', 'authors',
140                         'genre1name', 'genre1title', 'genre_name_list',
141                         'genres', 'title',
142                     ):
143                         grid.SetCellRenderer(row, col+1, autowrap_renderer)
144                     value = getattr(book, col_name)
145                     if value is None:
146                         value = u''
147                     elif not isinstance(value, (string_type, unicode_type)):
148                         value = str(value)
149                     grid.SetCellValue(row, col+1, value)
150                 book_by_row[row] = book
151                 toggle_rows[author_row].append(row)
152                 toggle_rows[series_row].append(row)
153                 row += 1
154         toggle_rows[0] = [row_ for row_ in range(1, row)]
155         grid.AutoSizeColumns()
156         grid.AutoSizeRows()
157         grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnClick)
158
159         search_button = wx.Button(self, label=u'Скачать')
160         self.GetSizer().Add(search_button, 0, wx.ALIGN_CENTER, 0)
161         search_button.Bind(wx.EVT_BUTTON, self.Download)
162
163     def toggleCB(self, row):
164         value = self.grid.GetCellValue(row, 0)
165         if value:
166             value = ''
167         else:
168             value = '1'
169         self.grid.SetCellValue(row, 0, value)
170         toggle_rows = self.toggle_rows
171         if row in toggle_rows:
172             for row_ in toggle_rows[row]:
173                 self.grid.SetCellValue(row_, 0, value)
174
175     def OnClick(self, event):
176         if event.GetCol() > 0:
177             return
178         self.toggleCB(event.GetRow())
179
180     def OnDClick(self, event):
181         if event.GetCol() == 0:
182             return
183         self.toggleCB(event.GetRow())
184
185     def OnKeyDown(self, event):
186         if event.GetKeyCode() == wx.WXK_ESCAPE:
187             self.Parent.Close()
188         else:
189             event.Skip()
190
191     def Download(self, event=None):
192         book_by_row = self.book_by_row
193         found_books = False
194         try:
195             for row in self.toggle_rows[0]:
196                 value = self.grid.GetCellValue(row, 0)
197                 if value and row in book_by_row:
198                     found_books = True
199                     download(book_by_row[row])
200         except Exception as e:
201             self.report_error(str(e))
202         else:
203             if found_books:
204                 self.report_success(u'Книги сохранены.')
205             else:
206                 self.report_error(u'Не выбрано книг для сохранения.')
207
208     def report_success(self, message):
209         wx.MessageBox(
210             message, caption='m_Librarian download finished',
211             style=wx.OK, parent=self.Parent)
212
213     def report_error(self, error):
214         wx.MessageBox(
215             error, caption='m_Librarian download error',
216             style=wx.OK | wx.ICON_ERROR, parent=self.Parent)
217
218
219 class ListBooksWindow(GridWindow):
220
221     session_config_section_name = 'list_books'
222     window_title = u"m_Librarian: Список книг"
223     GridPanelClass = ListBooksPanel
224
225     def InitMenu(self):
226         GridWindow.InitMenu(self)
227
228         download_menu = wx.Menu()
229         download = download_menu.Append(wx.ID_SAVE,
230                                         u"&Скачать", u"Скачать")
231         self.Bind(wx.EVT_MENU, self.OnDownload, download)
232         self.GetMenuBar().Append(download_menu, u"&Скачать")
233
234     def OnDownload(self, event):
235         self.panel.Download()