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