最古版。新版→https://osdn.jp/users/tacticsrealize/pf/ChlorophyllUploader/wiki/FrontPage
Revision | 1db25e03a61d9b3b54e115a811c2a1e5f4660b7b (tree) |
---|---|
Time | 2015-07-30 04:19:07 |
Author | MirrgieRiana |
Commiter | MirrgieRiana |
add: GroupBuilder, FrameHTML
@@ -0,0 +1,314 @@ | ||
1 | +package mirrg.swing.helium; | |
2 | + | |
3 | +import java.awt.Component; | |
4 | +import java.awt.Dimension; | |
5 | +import java.awt.event.KeyEvent; | |
6 | +import java.awt.event.KeyListener; | |
7 | +import java.beans.PropertyChangeListener; | |
8 | +import java.io.IOException; | |
9 | +import java.net.URL; | |
10 | +import java.util.LinkedList; | |
11 | + | |
12 | +import javax.swing.GroupLayout; | |
13 | +import javax.swing.GroupLayout.Alignment; | |
14 | +import javax.swing.JButton; | |
15 | +import javax.swing.JEditorPane; | |
16 | +import javax.swing.JLabel; | |
17 | +import javax.swing.JMenuItem; | |
18 | +import javax.swing.JPopupMenu; | |
19 | +import javax.swing.JScrollPane; | |
20 | +import javax.swing.JTextField; | |
21 | +import javax.swing.event.HyperlinkEvent.EventType; | |
22 | +import javax.swing.text.Document; | |
23 | +import javax.swing.text.html.HTMLDocument; | |
24 | + | |
25 | +import mirrg.struct.hydrogen.Struct1; | |
26 | +import mirrg.struct.hydrogen.Tuple; | |
27 | +import mirrg.swing.helium.logging.EnumTypeLog; | |
28 | +import mirrg.swing.helium.logging.HLog; | |
29 | + | |
30 | +public class FrameHTML extends FrameMirrg | |
31 | +{ | |
32 | + | |
33 | + /** | |
34 | + * 下に行くほど新しい。 | |
35 | + */ | |
36 | + private LinkedList<Tuple<URL, Integer>> historyLeft = new LinkedList<>(); | |
37 | + /** | |
38 | + * 下に行くほど新しい。 | |
39 | + */ | |
40 | + private LinkedList<Tuple<URL, Integer>> historyRight = new LinkedList<>(); | |
41 | + | |
42 | + private JButton button1; | |
43 | + private JButton button2; | |
44 | + private JTextField textField1; | |
45 | + private JEditorPane editorPane1; | |
46 | + private JScrollPane scrollPane1; | |
47 | + | |
48 | + public FrameHTML() | |
49 | + { | |
50 | + setTitle("HTMLビューワ"); | |
51 | + | |
52 | + { | |
53 | + | |
54 | + button1 = new JButton("戻る"); | |
55 | + button1.setToolTipText("右クリック:プルダウンメニューの表示"); | |
56 | + button1.addActionListener(e -> { | |
57 | + if (!historyLeft.isEmpty()) travelLeft(1); | |
58 | + }); | |
59 | + HSwing.hookPopup(button1, e -> { | |
60 | + | |
61 | + if (!historyLeft.isEmpty()) { | |
62 | + JPopupMenu popupMenu = new JPopupMenu(); | |
63 | + | |
64 | + for (int i = historyLeft.size() - 1; i >= 0; i--) { | |
65 | + Tuple<URL, Integer> entry = historyLeft.get(i); | |
66 | + JMenuItem menuItem = new JMenuItem( | |
67 | + entry.getY().toString() + ": " + entry.getX().toString()); | |
68 | + popupMenu.add(menuItem); | |
69 | + | |
70 | + int i2 = i + 1; | |
71 | + menuItem.addActionListener(e2 -> { | |
72 | + travelLeft(i2); | |
73 | + }); | |
74 | + } | |
75 | + | |
76 | + popupMenu.show((Component) e.getSource(), e.getX(), e.getY()); | |
77 | + | |
78 | + return true; | |
79 | + } | |
80 | + | |
81 | + return false; | |
82 | + }); | |
83 | + | |
84 | + button2 = new JButton("進む"); | |
85 | + button2.setToolTipText("右クリック:プルダウンメニューの表示"); | |
86 | + button2.addActionListener(e -> { | |
87 | + if (!historyRight.isEmpty()) travelRight(1); | |
88 | + }); | |
89 | + HSwing.hookPopup(button2, e -> { | |
90 | + | |
91 | + if (!historyRight.isEmpty()) { | |
92 | + JPopupMenu popupMenu = new JPopupMenu(); | |
93 | + | |
94 | + for (int i = 0; i < historyRight.size(); i++) { | |
95 | + Tuple<URL, Integer> entry = historyRight.get(i); | |
96 | + JMenuItem menuItem = new JMenuItem( | |
97 | + entry.getY().toString() + ": " + entry.getX().toString()); | |
98 | + popupMenu.add(menuItem); | |
99 | + | |
100 | + int i2 = i + 1; | |
101 | + menuItem.addActionListener(e2 -> { | |
102 | + travelRight(i2); | |
103 | + }); | |
104 | + } | |
105 | + | |
106 | + popupMenu.show((Component) e.getSource(), e.getX(), e.getY()); | |
107 | + | |
108 | + return true; | |
109 | + } | |
110 | + | |
111 | + return false; | |
112 | + }); | |
113 | + | |
114 | + textField1 = new JTextField(); | |
115 | + textField1.addActionListener(e -> { | |
116 | + navigate(textField1.getText()); | |
117 | + }); | |
118 | + | |
119 | + JButton button3 = new JButton("移動"); | |
120 | + button3.addActionListener(e -> { | |
121 | + navigate(textField1.getText()); | |
122 | + }); | |
123 | + | |
124 | + JButton button4 = new JButton("更新"); | |
125 | + button4.addActionListener(e -> { | |
126 | + refresh(); | |
127 | + }); | |
128 | + | |
129 | + editorPane1 = new JEditorPane(); | |
130 | + editorPane1.setEditable(false); | |
131 | + editorPane1.addHyperlinkListener(e -> { | |
132 | + if (e.getEventType() == EventType.ACTIVATED) { | |
133 | + navigate(e.getURL()); | |
134 | + } | |
135 | + }); | |
136 | + editorPane1.addKeyListener(new KeyListener() { | |
137 | + | |
138 | + @Override | |
139 | + public void keyTyped(KeyEvent e) | |
140 | + { | |
141 | + | |
142 | + } | |
143 | + | |
144 | + @Override | |
145 | + public void keyReleased(KeyEvent e) | |
146 | + { | |
147 | + | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + public void keyPressed(KeyEvent e) | |
152 | + { | |
153 | + if (e.getKeyCode() == KeyEvent.VK_F5) { | |
154 | + refresh(); | |
155 | + return; | |
156 | + } | |
157 | + if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { | |
158 | + if (!historyLeft.isEmpty()) travelLeft(1); | |
159 | + return; | |
160 | + } | |
161 | + } | |
162 | + | |
163 | + }); | |
164 | + | |
165 | + scrollPane1 = new JScrollPane(editorPane1); | |
166 | + scrollPane1.setPreferredSize(new Dimension(800, 800)); | |
167 | + | |
168 | + { | |
169 | + GroupLayout layout = new GroupLayout(getContentPane()); | |
170 | + setLayout(layout); | |
171 | + | |
172 | + layout.setAutoCreateGaps(true); | |
173 | + layout.setAutoCreateContainerGaps(false); | |
174 | + | |
175 | + GroupBuilder.group( | |
176 | + GroupBuilder.group( | |
177 | + button1, | |
178 | + button2, | |
179 | + new JLabel("アドレス:"), | |
180 | + textField1, | |
181 | + button3, | |
182 | + button4 | |
183 | + ).align(Alignment.CENTER), | |
184 | + scrollPane1 | |
185 | + ).apply(layout); | |
186 | + } | |
187 | + } | |
188 | + | |
189 | + historyChanged(); | |
190 | + | |
191 | + HLog.log(EnumTypeLog.FINE, "HTMLビューワを起動しました"); | |
192 | + | |
193 | + prepareFrame(); | |
194 | + } | |
195 | + | |
196 | + private void refresh() | |
197 | + { | |
198 | + Tuple<URL, Integer> now = getNow(); | |
199 | + | |
200 | + ((HTMLDocument) editorPane1.getDocument()).getDocumentProperties().remove( | |
201 | + Document.StreamDescriptionProperty); | |
202 | + | |
203 | + if (now != null) setPage(now); | |
204 | + } | |
205 | + | |
206 | + private Tuple<URL, Integer> getNow() | |
207 | + { | |
208 | + URL page = editorPane1.getPage(); | |
209 | + | |
210 | + return page == null | |
211 | + ? null | |
212 | + : new Tuple<>(page, scrollPane1.getVerticalScrollBar().getValue()); | |
213 | + } | |
214 | + | |
215 | + private void travelLeft(int times) | |
216 | + { | |
217 | + Tuple<URL, Integer> now = getNow(); | |
218 | + | |
219 | + // 履歴操作 | |
220 | + for (int i = 0; i < times; i++) { | |
221 | + historyRight.addFirst(now); | |
222 | + now = historyLeft.removeLast(); | |
223 | + } | |
224 | + | |
225 | + historyChanged(); | |
226 | + | |
227 | + setPage(now); | |
228 | + } | |
229 | + | |
230 | + private void travelRight(int times) | |
231 | + { | |
232 | + Tuple<URL, Integer> now = getNow(); | |
233 | + | |
234 | + // 履歴操作 | |
235 | + for (int i = 0; i < times; i++) { | |
236 | + historyLeft.addLast(now); | |
237 | + now = historyRight.removeFirst(); | |
238 | + } | |
239 | + | |
240 | + historyChanged(); | |
241 | + | |
242 | + setPage(now); | |
243 | + } | |
244 | + | |
245 | + private void setPage(Tuple<URL, Integer> url) | |
246 | + { | |
247 | + try { | |
248 | + editorPane1.setPage(url.getX()); | |
249 | + } catch (IOException e) { | |
250 | + HLog.processExceptionWarning(e); | |
251 | + return; | |
252 | + } | |
253 | + | |
254 | + textField1.setText(url.getX().toString()); | |
255 | + | |
256 | + // 表示位置調整 | |
257 | + Struct1<PropertyChangeListener> listener = new Struct1<>(); | |
258 | + listener.x = e -> { | |
259 | + editorPane1.removePropertyChangeListener("page", listener.x); | |
260 | + | |
261 | + scrollPane1.getVerticalScrollBar().setValue(url.getY()); | |
262 | + | |
263 | + }; | |
264 | + editorPane1.addPropertyChangeListener("page", listener.x); | |
265 | + | |
266 | + // 同じページに遷移した場合にイベントが発生しないので念のために変更しておく | |
267 | + // TODO イベントが残留するが次のイベントで死ぬのでとりあえず良しとする | |
268 | + scrollPane1.getVerticalScrollBar().setValue(url.getY()); | |
269 | + | |
270 | + } | |
271 | + | |
272 | + public void navigate(String url) | |
273 | + { | |
274 | + Tuple<URL, Integer> now = getNow(); | |
275 | + if (now != null) { | |
276 | + historyLeft.addLast(now); | |
277 | + historyChanged(); | |
278 | + } | |
279 | + | |
280 | + try { | |
281 | + editorPane1.setPage(url); | |
282 | + } catch (IOException e) { | |
283 | + HLog.processExceptionWarning(e); | |
284 | + return; | |
285 | + } | |
286 | + | |
287 | + textField1.setText(url); | |
288 | + } | |
289 | + | |
290 | + public void navigate(URL url) | |
291 | + { | |
292 | + Tuple<URL, Integer> now = getNow(); | |
293 | + if (now != null) { | |
294 | + historyLeft.addLast(now); | |
295 | + historyChanged(); | |
296 | + } | |
297 | + | |
298 | + try { | |
299 | + editorPane1.setPage(url); | |
300 | + } catch (IOException e) { | |
301 | + HLog.processExceptionWarning(e); | |
302 | + return; | |
303 | + } | |
304 | + | |
305 | + textField1.setText(url.toString()); | |
306 | + } | |
307 | + | |
308 | + private void historyChanged() | |
309 | + { | |
310 | + button1.setEnabled(!historyLeft.isEmpty()); | |
311 | + button2.setEnabled(!historyRight.isEmpty()); | |
312 | + } | |
313 | + | |
314 | +} |
@@ -0,0 +1,63 @@ | ||
1 | +package mirrg.swing.helium; | |
2 | + | |
3 | +import java.awt.Component; | |
4 | + | |
5 | +import javax.swing.GroupLayout; | |
6 | +import javax.swing.GroupLayout.Alignment; | |
7 | +import javax.swing.GroupLayout.Group; | |
8 | + | |
9 | +public class GroupBuilder | |
10 | +{ | |
11 | + | |
12 | + public static GroupBuilder group(Object... objects) | |
13 | + { | |
14 | + return new GroupBuilder(objects); | |
15 | + } | |
16 | + | |
17 | + private Object[] objects; | |
18 | + private Alignment alignment = null; | |
19 | + | |
20 | + public GroupBuilder(Object[] objects) | |
21 | + { | |
22 | + this.objects = objects; | |
23 | + } | |
24 | + | |
25 | + public Group build(GroupLayout groupLayout) | |
26 | + { | |
27 | + return build(groupLayout, true); | |
28 | + } | |
29 | + | |
30 | + public Group build(GroupLayout groupLayout, boolean isSequential) | |
31 | + { | |
32 | + Group group = isSequential | |
33 | + ? groupLayout.createSequentialGroup() | |
34 | + : alignment != null | |
35 | + ? groupLayout.createParallelGroup(alignment) | |
36 | + : groupLayout.createParallelGroup(); | |
37 | + | |
38 | + for (Object object : objects) { | |
39 | + if (object instanceof GroupBuilder) { | |
40 | + group.addGroup(((GroupBuilder) object).build(groupLayout, !isSequential)); | |
41 | + } else if (object instanceof Component) { | |
42 | + group.addComponent((Component) object); | |
43 | + } else { | |
44 | + throw new RuntimeException("unknown group build entry: " + object); | |
45 | + } | |
46 | + } | |
47 | + | |
48 | + return group; | |
49 | + } | |
50 | + | |
51 | + public void apply(GroupLayout layout) | |
52 | + { | |
53 | + layout.setHorizontalGroup(build(layout, false)); | |
54 | + layout.setVerticalGroup(build(layout)); | |
55 | + } | |
56 | + | |
57 | + public GroupBuilder align(Alignment alignment) | |
58 | + { | |
59 | + this.alignment = alignment; | |
60 | + return this; | |
61 | + } | |
62 | + | |
63 | +} |