Commit | Line | Data |
---|---|---|
16a81ef7 | 1 | package be.nikiroo.fanfix.reader.tui; |
c1873e56 | 2 | |
bc2ea776 | 3 | import java.io.IOException; |
c1873e56 NR |
4 | import java.util.ArrayList; |
5 | import java.util.List; | |
6 | ||
5dd985cf | 7 | import jexer.TAction; |
ce424b19 | 8 | import jexer.TComboBox; |
bce88a00 NR |
9 | import jexer.TCommand; |
10 | import jexer.TField; | |
e2d017a3 | 11 | import jexer.TFileOpenBox.Type; |
bce88a00 | 12 | import jexer.TKeypress; |
ce424b19 | 13 | import jexer.TLabel; |
5dd985cf | 14 | import jexer.TList; |
bce88a00 | 15 | import jexer.TStatusBar; |
5dd985cf | 16 | import jexer.TWindow; |
cf9c5ed1 | 17 | import jexer.event.TCommandEvent; |
bce88a00 | 18 | import jexer.event.TKeypressEvent; |
e2d017a3 | 19 | import jexer.event.TMenuEvent; |
ce424b19 | 20 | import jexer.event.TResizeEvent; |
bc2ea776 | 21 | import be.nikiroo.fanfix.Instance; |
c1873e56 | 22 | import be.nikiroo.fanfix.data.MetaData; |
bc2ea776 | 23 | import be.nikiroo.fanfix.library.BasicLibrary; |
e2d017a3 | 24 | import be.nikiroo.fanfix.output.BasicOutput.OutputType; |
16a81ef7 | 25 | import be.nikiroo.fanfix.reader.Reader; |
0bcb5c7f | 26 | import be.nikiroo.jexer.TSizeConstraint; |
c1873e56 | 27 | |
6322ab64 NR |
28 | /** |
29 | * The library window, that will list all the (filtered) stories available in | |
bc2ea776 | 30 | * this {@link BasicLibrary}. |
6322ab64 NR |
31 | * |
32 | * @author niki | |
33 | */ | |
5dd985cf | 34 | class TuiReaderMainWindow extends TWindow { |
bce88a00 NR |
35 | public static final int MENU_SEARCH = 1100; |
36 | public static final TCommand CMD_SEARCH = new TCommand(MENU_SEARCH) { | |
37 | }; | |
38 | ||
b2274262 NR |
39 | public enum Mode { |
40 | SOURCE, AUTHOR, | |
41 | } | |
42 | ||
c1873e56 NR |
43 | private TList list; |
44 | private List<MetaData> listKeys; | |
45 | private List<String> listItems; | |
bc2ea776 | 46 | private Reader reader; |
b2274262 NR |
47 | |
48 | private Mode mode = Mode.SOURCE; | |
49 | private String target = null; | |
bce88a00 | 50 | private String filter = ""; |
b2274262 | 51 | |
ce424b19 NR |
52 | private List<TSizeConstraint> sizeConstraints = new ArrayList<TSizeConstraint>(); |
53 | ||
81a6120d | 54 | // The 2 comboboxes used to select by source/author |
41627937 NR |
55 | private TComboBox selectTargetBox; |
56 | private TComboBox selectBox; | |
6322ab64 NR |
57 | |
58 | /** | |
59 | * Create a new {@link TuiReaderMainWindow} without any stories in the list. | |
60 | * | |
61 | * @param reader | |
62 | * the reader and main application | |
63 | */ | |
64 | public TuiReaderMainWindow(TuiReaderApplication reader) { | |
c1873e56 | 65 | // Construct a demo window. X and Y don't matter because it will be |
bc2ea776 | 66 | // centred on screen. |
4f66bfa8 | 67 | super(reader, "Library", 0, 0, 60, 18, CENTERED | RESIZABLE); |
c1873e56 NR |
68 | |
69 | this.reader = reader; | |
70 | ||
c1873e56 NR |
71 | listKeys = new ArrayList<MetaData>(); |
72 | listItems = new ArrayList<String>(); | |
e9d43c7c | 73 | |
ce424b19 | 74 | addList(); |
41627937 | 75 | addSearch(); |
81a6120d | 76 | addSelect(); |
5dd985cf | 77 | |
bce88a00 NR |
78 | TStatusBar statusBar = reader.setStatusBar(this, "Library"); |
79 | statusBar.addShortcutKeypress(TKeypress.kbCtrlF, CMD_SEARCH, "Search"); | |
c1873e56 | 80 | |
ce424b19 NR |
81 | TSizeConstraint.resize(sizeConstraints); |
82 | ||
bc2ea776 NR |
83 | // TODO: remove when not used anymore |
84 | ||
85 | // addLabel("Label (1,1)", 1, 1); | |
86 | // addButton("&Button (35,1)", 35, 1, new TAction() { | |
87 | // public void DO() { | |
88 | // } | |
89 | // }); | |
90 | // addCheckbox(1, 2, "Checky (1,2)", false); | |
91 | // addProgressBar(1, 3, 30, 42); | |
92 | // TRadioGroup groupy = addRadioGroup(1, 4, "Radio groupy"); | |
93 | // groupy.addRadioButton("Fanfan"); | |
94 | // groupy.addRadioButton("Tulipe"); | |
95 | // addField(1, 10, 20, false, "text not fixed."); | |
96 | // addField(1, 11, 20, true, "text fixed."); | |
97 | // addText("20x4 Text in (12,20)", 1, 12, 20, 4); | |
98 | // | |
99 | // TTreeView tree = addTreeView(30, 5, 20, 5); | |
100 | // TTreeItem root = new TTreeItem(tree, "expended root", true); | |
101 | // tree.setSelected(root); // needed to allow arrow navigation without | |
102 | // // mouse-clicking before | |
103 | // | |
104 | // root.addChild("child"); | |
105 | // root.addChild("child 2").addChild("sub child"); | |
106 | } | |
c1873e56 | 107 | |
ce424b19 NR |
108 | private void addSearch() { |
109 | TLabel lblSearch = addLabel("Search: ", 0, 0); | |
110 | ||
111 | TField search = new TField(this, 0, 0, 1, true) { | |
112 | @Override | |
113 | public void onKeypress(TKeypressEvent keypress) { | |
114 | super.onKeypress(keypress); | |
115 | TKeypress key = keypress.getKey(); | |
116 | if (key.isFnKey() && key.getKeyCode() == TKeypress.ENTER) { | |
117 | TuiReaderMainWindow.this.filter = getText(); | |
118 | TuiReaderMainWindow.this.refreshStories(); | |
119 | } | |
120 | } | |
121 | }; | |
122 | ||
123 | TSizeConstraint.setSize(sizeConstraints, lblSearch, 5, 1, null, null); | |
124 | TSizeConstraint.setSize(sizeConstraints, search, 15, 1, -5, null); | |
125 | } | |
126 | ||
127 | private void addList() { | |
128 | list = addList(listItems, 0, 0, 10, 10, new TAction() { | |
129 | @Override | |
130 | public void DO() { | |
131 | MetaData meta = getSelectedMeta(); | |
132 | if (meta != null) { | |
133 | readStory(meta); | |
134 | } | |
135 | } | |
136 | }); | |
137 | ||
138 | TSizeConstraint.setSize(sizeConstraints, list, 0, 7, 0, 0); | |
139 | } | |
140 | ||
141 | private void addSelect() { | |
41627937 | 142 | // TODO: i18n |
b2274262 NR |
143 | final List<String> selects = new ArrayList<String>(); |
144 | selects.add("(show all)"); | |
41627937 NR |
145 | selects.add("Sources"); |
146 | selects.add("Author"); | |
147 | ||
148 | final List<String> selectTargets = new ArrayList<String>(); | |
149 | selectTargets.add(""); | |
ce424b19 NR |
150 | |
151 | TLabel lblSelect = addLabel("Select: ", 0, 0); | |
152 | ||
41627937 NR |
153 | TAction onSelect = new TAction() { |
154 | @Override | |
155 | public void DO() { | |
156 | String smode = selectBox.getText(); | |
41627937 NR |
157 | boolean showTarget; |
158 | if (smode == null || smode.equals("(show all)")) { | |
41627937 NR |
159 | showTarget = false; |
160 | } else if (smode.equals("Sources")) { | |
41627937 NR |
161 | selectTargets.clear(); |
162 | selectTargets.add("(show all)"); | |
163 | for (String source : reader.getLibrary().getSources()) { | |
164 | selectTargets.add(source); | |
ce424b19 | 165 | } |
41627937 NR |
166 | showTarget = true; |
167 | } else { | |
41627937 NR |
168 | selectTargets.clear(); |
169 | selectTargets.add("(show all)"); | |
170 | for (String author : reader.getLibrary().getAuthors()) { | |
171 | selectTargets.add(author); | |
172 | } | |
173 | ||
174 | showTarget = true; | |
175 | } | |
ce424b19 | 176 | |
41627937 NR |
177 | selectTargetBox.setVisible(showTarget); |
178 | selectTargetBox.setEnabled(showTarget); | |
179 | if (showTarget) { | |
180 | selectTargetBox.reflowData(); | |
181 | } | |
182 | ||
183 | selectTargetBox.setText(selectTargets.get(0)); | |
81a6120d NR |
184 | if (showTarget) { |
185 | TuiReaderMainWindow.this.activate(selectTargetBox); | |
186 | } else { | |
187 | TuiReaderMainWindow.this.activate(list); | |
188 | } | |
41627937 NR |
189 | } |
190 | }; | |
191 | ||
192 | selectBox = addComboBox(0, 0, 10, selects, 0, -1, onSelect); | |
41627937 NR |
193 | |
194 | selectTargetBox = addComboBox(0, 0, 0, selectTargets, 0, -1, | |
ce424b19 NR |
195 | new TAction() { |
196 | @Override | |
197 | public void DO() { | |
81a6120d NR |
198 | if (selectTargetBox.getText().equals( |
199 | selectTargets.get(0))) { | |
b2274262 NR |
200 | setMode(mode, null); |
201 | } else { | |
41627937 | 202 | setMode(mode, selectTargetBox.getText()); |
ce424b19 NR |
203 | } |
204 | } | |
205 | }); | |
41627937 NR |
206 | |
207 | // Set defaults | |
208 | onSelect.DO(); | |
ce424b19 NR |
209 | |
210 | TSizeConstraint.setSize(sizeConstraints, lblSelect, 5, 3, null, null); | |
41627937 NR |
211 | TSizeConstraint.setSize(sizeConstraints, selectBox, 15, 3, -5, null); |
212 | TSizeConstraint.setSize(sizeConstraints, selectTargetBox, 15, 4, -5, | |
213 | null); | |
ce424b19 NR |
214 | } |
215 | ||
216 | @Override | |
217 | public void onResize(TResizeEvent resize) { | |
218 | super.onResize(resize); | |
219 | TSizeConstraint.resize(sizeConstraints); | |
220 | } | |
221 | ||
4f66bfa8 NR |
222 | @Override |
223 | public void onClose() { | |
224 | setVisible(false); | |
225 | super.onClose(); | |
226 | } | |
227 | ||
e2d017a3 | 228 | /** |
bce88a00 NR |
229 | * Refresh the list of stories displayed in this library. |
230 | * <p> | |
231 | * Will take the current settings into account (filter, source...). | |
e2d017a3 | 232 | */ |
e2d017a3 | 233 | public void refreshStories() { |
b2274262 NR |
234 | List<MetaData> metas; |
235 | if (mode == Mode.SOURCE) { | |
236 | metas = reader.getLibrary().getListBySource(target); | |
237 | } else if (mode == Mode.AUTHOR) { | |
238 | metas = reader.getLibrary().getListByAuthor(target); | |
239 | } else { | |
240 | metas = reader.getLibrary().getList(); | |
241 | } | |
242 | ||
e2d017a3 NR |
243 | setMetas(metas); |
244 | } | |
245 | ||
bc2ea776 | 246 | /** |
b2274262 NR |
247 | * Change the author/source filter and display all stories matching this |
248 | * target. | |
bc2ea776 | 249 | * |
b2274262 NR |
250 | * @param mode |
251 | * the new mode or NULL for no sorting | |
252 | * @param target | |
253 | * the actual target for the given mode, or NULL for all of them | |
bc2ea776 | 254 | */ |
b2274262 NR |
255 | public void setMode(Mode mode, String target) { |
256 | this.mode = mode; | |
257 | this.target = target; | |
bce88a00 | 258 | refreshStories(); |
c1873e56 NR |
259 | } |
260 | ||
6322ab64 NR |
261 | /** |
262 | * Update the list of stories displayed in this {@link TWindow}. | |
bce88a00 NR |
263 | * <p> |
264 | * If a filter is set, only the stories which pass the filter will be | |
265 | * displayed. | |
6322ab64 NR |
266 | * |
267 | * @param metas | |
268 | * the new list of stories to display | |
269 | */ | |
e2d017a3 | 270 | private void setMetas(List<MetaData> metas) { |
6322ab64 NR |
271 | listKeys.clear(); |
272 | listItems.clear(); | |
273 | ||
274 | if (metas != null) { | |
275 | for (MetaData meta : metas) { | |
bce88a00 NR |
276 | String desc = desc(meta); |
277 | if (filter.isEmpty() | |
278 | || desc.toLowerCase().contains(filter.toLowerCase())) { | |
279 | listKeys.add(meta); | |
280 | listItems.add(desc); | |
281 | } | |
6322ab64 NR |
282 | } |
283 | } | |
284 | ||
285 | list.setList(listItems); | |
81a6120d NR |
286 | if (listItems.size() > 0) { |
287 | list.setSelectedIndex(0); | |
288 | } | |
6322ab64 NR |
289 | } |
290 | ||
e2d017a3 NR |
291 | public MetaData getSelectedMeta() { |
292 | if (list.getSelectedIndex() >= 0) { | |
293 | return listKeys.get(list.getSelectedIndex()); | |
294 | } | |
295 | ||
296 | return null; | |
297 | } | |
298 | ||
299 | public void readStory(MetaData meta) { | |
bc2ea776 NR |
300 | try { |
301 | reader.setChapter(-1); | |
302 | reader.setMeta(meta); | |
303 | reader.read(); | |
304 | } catch (IOException e) { | |
62c63b07 | 305 | Instance.getTraceHandler().error(e); |
bc2ea776 | 306 | } |
c1873e56 NR |
307 | } |
308 | ||
309 | private String desc(MetaData meta) { | |
310 | return String.format("%5s: %s", meta.getLuid(), meta.getTitle()); | |
311 | } | |
e2d017a3 | 312 | |
cf9c5ed1 NR |
313 | @Override |
314 | public void onCommand(TCommandEvent command) { | |
315 | if (command.getCmd().equals(TuiReaderApplication.CMD_EXIT)) { | |
316 | TuiReaderApplication.close(this); | |
317 | } else { | |
318 | // Handle our own event if needed here | |
319 | super.onCommand(command); | |
320 | } | |
321 | } | |
322 | ||
e2d017a3 NR |
323 | @Override |
324 | public void onMenu(TMenuEvent menu) { | |
325 | MetaData meta = getSelectedMeta(); | |
326 | if (meta != null) { | |
327 | switch (menu.getId()) { | |
328 | case TuiReaderApplication.MENU_OPEN: | |
329 | readStory(meta); | |
330 | ||
331 | return; | |
332 | case TuiReaderApplication.MENU_EXPORT: | |
333 | ||
334 | try { | |
335 | // TODO: choose type, pg, error | |
336 | OutputType outputType = OutputType.EPUB; | |
337 | String path = fileOpenBox(".", Type.SAVE); | |
338 | reader.getLibrary().export(meta.getLuid(), outputType, | |
339 | path, null); | |
340 | } catch (IOException e) { | |
341 | // TODO | |
342 | e.printStackTrace(); | |
343 | } | |
344 | ||
345 | return; | |
bce88a00 | 346 | |
e2d017a3 NR |
347 | case -1: |
348 | try { | |
349 | reader.getLibrary().delete(meta.getLuid()); | |
350 | } catch (IOException e) { | |
351 | // TODO | |
352 | } | |
353 | ||
354 | return; | |
355 | } | |
356 | } | |
357 | ||
358 | super.onMenu(menu); | |
359 | } | |
360 | } |