Add progress reporting on GUI
[fanfix.git] / src / be / nikiroo / fanfix / reader / LocalReaderFrame.java
1 package be.nikiroo.fanfix.reader;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.Desktop;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.KeyEvent;
9 import java.awt.event.WindowEvent;
10 import java.io.File;
11 import java.io.IOException;
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import javax.swing.JFrame;
16 import javax.swing.JMenu;
17 import javax.swing.JMenuBar;
18 import javax.swing.JMenuItem;
19 import javax.swing.JOptionPane;
20 import javax.swing.JPanel;
21 import javax.swing.JScrollPane;
22 import javax.swing.SwingUtilities;
23
24 import be.nikiroo.fanfix.Instance;
25 import be.nikiroo.fanfix.bundles.UiConfig;
26 import be.nikiroo.fanfix.data.MetaData;
27 import be.nikiroo.fanfix.reader.LocalReaderBook.BookActionListener;
28 import be.nikiroo.utils.Progress;
29 import be.nikiroo.utils.ui.ProgressBar;
30 import be.nikiroo.utils.ui.WrapLayout;
31
32 class LocalReaderFrame extends JFrame {
33 private static final long serialVersionUID = 1L;
34 private LocalReader reader;
35 private List<MetaData> stories;
36 private List<LocalReaderBook> books;
37 private JPanel bookPane;
38 private String type;
39 private Color color;
40 private ProgressBar pgBar;
41 private JMenuBar bar;
42
43 public LocalReaderFrame(LocalReader reader, String type) {
44 super("Fanfix Library");
45
46 this.reader = reader;
47
48 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
49 setSize(800, 600);
50 setLayout(new BorderLayout());
51
52 books = new ArrayList<LocalReaderBook>();
53 bookPane = new JPanel(new WrapLayout(WrapLayout.LEADING, 5, 5));
54
55 color = Instance.getUiConfig().getColor(UiConfig.BACKGROUND_COLOR);
56
57 if (color != null) {
58 setBackground(color);
59 bookPane.setBackground(color);
60 }
61
62 JScrollPane scroll = new JScrollPane(bookPane);
63 scroll.getVerticalScrollBar().setUnitIncrement(16);
64 add(scroll, BorderLayout.CENTER);
65
66 pgBar = new ProgressBar();
67 add(pgBar, BorderLayout.SOUTH);
68
69 refreshBooks(type);
70 setJMenuBar(createMenu());
71
72 setVisible(true);
73 }
74
75 private void refreshBooks(String type) {
76 this.type = type;
77 stories = Instance.getLibrary().getList(type);
78 books.clear();
79 bookPane.removeAll();
80 for (MetaData meta : stories) {
81 LocalReaderBook book = new LocalReaderBook(meta);
82 if (color != null) {
83 book.setBackground(color);
84 }
85
86 books.add(book);
87 final String luid = meta.getLuid();
88 book.addActionListener(new BookActionListener() {
89 public void select(LocalReaderBook book) {
90 for (LocalReaderBook abook : books) {
91 abook.setSelected(abook == book);
92 }
93 }
94
95 public void action(LocalReaderBook book) {
96 final Progress pg = new Progress();
97 outOfUi(pg, new Runnable() {
98 public void run() {
99 try {
100 File target = LocalReaderFrame.this.reader
101 .getTarget(luid, pg);
102 Desktop.getDesktop().browse(target.toURI());
103 } catch (IOException e) {
104 Instance.syserr(e);
105 }
106 }
107 });
108 }
109 });
110
111 bookPane.add(book);
112 }
113
114 bookPane.validate();
115 bookPane.repaint();
116 }
117
118 private JMenuBar createMenu() {
119 bar = new JMenuBar();
120
121 JMenu file = new JMenu("File");
122
123 JMenuItem imprt = new JMenuItem("Import", KeyEvent.VK_I);
124 imprt.addActionListener(new ActionListener() {
125 public void actionPerformed(ActionEvent e) {
126 final String url = JOptionPane.showInputDialog(
127 LocalReaderFrame.this, "url of the story to import?",
128 "Importing from URL", JOptionPane.QUESTION_MESSAGE);
129 if (url != null && !url.isEmpty()) {
130 final Progress pg = new Progress("Importing " + url);
131 outOfUi(pg, new Runnable() {
132 public void run() {
133 Exception ex = null;
134 try {
135 Instance.getLibrary().imprt(
136 BasicReader.getUrl(url), pg);
137 } catch (IOException e) {
138 ex = e;
139 }
140
141 final Exception e = ex;
142
143 final boolean ok = (e == null);
144 SwingUtilities.invokeLater(new Runnable() {
145 public void run() {
146 if (!ok) {
147 JOptionPane.showMessageDialog(
148 LocalReaderFrame.this,
149 "Cannot import: " + url,
150 e.getMessage(),
151 JOptionPane.ERROR_MESSAGE);
152
153 setAllEnabled(true);
154 } else {
155 refreshBooks(type);
156 }
157 }
158 });
159 }
160 });
161 }
162 }
163 });
164 JMenu types = new JMenu("Type");
165 List<String> tt = Instance.getLibrary().getTypes();
166 tt.add(0, null);
167 for (final String type : tt) {
168 JMenuItem item = new JMenuItem(type == null ? "[all]" : type);
169 item.addActionListener(new ActionListener() {
170 public void actionPerformed(ActionEvent e) {
171 refreshBooks(type);
172 }
173 });
174 types.add(item);
175 }
176 JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X);
177 exit.addActionListener(new ActionListener() {
178 public void actionPerformed(ActionEvent e) {
179 LocalReaderFrame.this.dispatchEvent(new WindowEvent(
180 LocalReaderFrame.this, WindowEvent.WINDOW_CLOSING));
181 }
182 });
183
184 file.add(imprt);
185 file.add(types);
186 file.addSeparator();
187 file.add(exit);
188
189 bar.add(file);
190
191 return bar;
192 }
193
194 private void outOfUi(final Progress pg, final Runnable run) {
195 pgBar.setProgress(pg);
196
197 SwingUtilities.invokeLater(new Runnable() {
198 public void run() {
199 setAllEnabled(false);
200 pgBar.addActioListener(new ActionListener() {
201 public void actionPerformed(ActionEvent e) {
202 pgBar.setProgress(null);
203 setAllEnabled(true);
204 }
205 });
206 }
207 });
208
209 new Thread(new Runnable() {
210 public void run() {
211 run.run();
212 if (!pg.isDone()) {
213 pg.setProgress(pg.getMax());
214 }
215 }
216 }).start();
217 }
218
219 public void setAllEnabled(boolean enabled) {
220 for (LocalReaderBook book : books) {
221 book.setEnabled(enabled);
222 book.validate();
223 book.repaint();
224 }
225 bar.setEnabled(enabled);
226 bookPane.setEnabled(enabled);
227 bookPane.validate();
228 bookPane.repaint();
229 setEnabled(enabled);
230 validate();
231 repaint();
232 }
233 }