CSS change, some fallbacks programs for Desktop
[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 // TODO: allow custom programs, with
103 // Desktop/xdg-open fallback
104 try {
105 Desktop.getDesktop().browse(target.toURI());
106 } catch (UnsupportedOperationException e) {
107 String browsers[] = new String[] {
108 "xdg-open", "epiphany",
109 "konqueror", "firefox", "chrome",
110 "google-chrome", "mozilla" };
111
112 Runtime runtime = Runtime.getRuntime();
113 for (String browser : browsers) {
114 try {
115 runtime.exec(new String[] {
116 browser,
117 target.getAbsolutePath() });
118 runtime = null;
119 break;
120 } catch (IOException ioe) {
121 // continue, try next browser
122 }
123 }
124
125 if (runtime != null) {
126 throw new IOException(
127 "Cannot find a working GUI browser...");
128 }
129 }
130 } catch (IOException e) {
131 Instance.syserr(e);
132 }
133 }
134 });
135 }
136 });
137
138 bookPane.add(book);
139 }
140
141 bookPane.validate();
142 bookPane.repaint();
143 }
144
145 private JMenuBar createMenu() {
146 bar = new JMenuBar();
147
148 JMenu file = new JMenu("File");
149
150 JMenuItem imprt = new JMenuItem("Import", KeyEvent.VK_I);
151 imprt.addActionListener(new ActionListener() {
152 public void actionPerformed(ActionEvent e) {
153 final String url = JOptionPane.showInputDialog(
154 LocalReaderFrame.this, "url of the story to import?",
155 "Importing from URL", JOptionPane.QUESTION_MESSAGE);
156 if (url != null && !url.isEmpty()) {
157 final Progress pg = new Progress("Importing " + url);
158 outOfUi(pg, new Runnable() {
159 public void run() {
160 Exception ex = null;
161 try {
162 Instance.getLibrary().imprt(
163 BasicReader.getUrl(url), pg);
164 } catch (IOException e) {
165 ex = e;
166 }
167
168 final Exception e = ex;
169
170 final boolean ok = (e == null);
171 SwingUtilities.invokeLater(new Runnable() {
172 public void run() {
173 if (!ok) {
174 JOptionPane.showMessageDialog(
175 LocalReaderFrame.this,
176 "Cannot import: " + url,
177 e.getMessage(),
178 JOptionPane.ERROR_MESSAGE);
179
180 setAllEnabled(true);
181 } else {
182 refreshBooks(type);
183 }
184 }
185 });
186 }
187 });
188 }
189 }
190 });
191 JMenu types = new JMenu("Type");
192 List<String> tt = Instance.getLibrary().getTypes();
193 tt.add(0, null);
194 for (final String type : tt) {
195 JMenuItem item = new JMenuItem(type == null ? "[all]" : type);
196 item.addActionListener(new ActionListener() {
197 public void actionPerformed(ActionEvent e) {
198 refreshBooks(type);
199 }
200 });
201 types.add(item);
202 }
203 JMenuItem exit = new JMenuItem("Exit", KeyEvent.VK_X);
204 exit.addActionListener(new ActionListener() {
205 public void actionPerformed(ActionEvent e) {
206 LocalReaderFrame.this.dispatchEvent(new WindowEvent(
207 LocalReaderFrame.this, WindowEvent.WINDOW_CLOSING));
208 }
209 });
210
211 file.add(imprt);
212 file.add(types);
213 file.addSeparator();
214 file.add(exit);
215
216 bar.add(file);
217
218 return bar;
219 }
220
221 private void outOfUi(final Progress pg, final Runnable run) {
222 pgBar.setProgress(pg);
223
224 SwingUtilities.invokeLater(new Runnable() {
225 public void run() {
226 setAllEnabled(false);
227 pgBar.addActioListener(new ActionListener() {
228 public void actionPerformed(ActionEvent e) {
229 pgBar.setProgress(null);
230 setAllEnabled(true);
231 }
232 });
233 }
234 });
235
236 new Thread(new Runnable() {
237 public void run() {
238 run.run();
239 if (!pg.isDone()) {
240 pg.setProgress(pg.getMax());
241 }
242 }
243 }).start();
244 }
245
246 public void setAllEnabled(boolean enabled) {
247 for (LocalReaderBook book : books) {
248 book.setEnabled(enabled);
249 book.validate();
250 book.repaint();
251 }
252 bar.setEnabled(enabled);
253 bookPane.setEnabled(enabled);
254 bookPane.validate();
255 bookPane.repaint();
256 setEnabled(enabled);
257 validate();
258 repaint();
259 }
260 }