1 | lib 1400047 lib 1400102 // jxbrowser icons & license |
2 | static L<S> _stickyLibs_1016163 = ll(#1400047, #1400102); |
3 | |
4 | import com.teamdev.jxbrowser.chromium.demo.resources.Resources; |
5 | import com.teamdev.jxbrowser.chromium.events.Callback; |
6 | import com.teamdev.jxbrowser.chromium.*; |
7 | import com.teamdev.jxbrowser.chromium.events.*; |
8 | import com.teamdev.jxbrowser.chromium.internal.Environment; |
9 | import com.teamdev.jxbrowser.chromium.swing.*; |
10 | |
11 | import java.beans.*; |
12 | |
13 | sclass TabbedPane extends JPanel { |
14 | private final List<Tab> tabs; |
15 | private final TabCaptions captions; |
16 | private final JComponent contentContainer; |
17 | bool hasNewTabButton; |
18 | BrowserContext context; |
19 | |
20 | *(BrowserContext *context) { |
21 | this.captions = new TabCaptions(); |
22 | this.tabs = new ArrayList<Tab>(); |
23 | this.contentContainer = new JPanel(new BorderLayout()); |
24 | |
25 | setLayout(new BorderLayout()); |
26 | add(captions, BorderLayout.NORTH); |
27 | add(contentContainer, BorderLayout.CENTER); |
28 | |
29 | insertNewTabButton(); |
30 | } |
31 | |
32 | void insertNewTabButton() { |
33 | if (hasNewTabButton) ret; |
34 | hasNewTabButton = true; |
35 | TabButton button = new TabButton(Resources.getIcon("new-tab.png"), "New tab"); |
36 | button.addActionListener(actionListener { |
37 | addAndSelectTab(TabFactory.createTab(context)); |
38 | }); |
39 | addTabButton(button); |
40 | } |
41 | |
42 | public void disposeAllTabs() { |
43 | for (Tab tab : getTabs()) { |
44 | disposeTab(tab); |
45 | } |
46 | } |
47 | |
48 | private void disposeTab(Tab tab) { |
49 | tab.getCaption().setSelected(false); |
50 | tab.getContent().dispose(); |
51 | removeTab(tab); |
52 | if (hasTabs()) { |
53 | Tab firstTab = getFirstTab(); |
54 | firstTab.getCaption().setSelected(true); |
55 | } else |
56 | disposeInternalFrame(this); |
57 | } |
58 | |
59 | private Tab findTab(TabCaption item) { |
60 | for (Tab tab : getTabs()) { |
61 | if (tab.getCaption().equals(item)) { |
62 | return tab; |
63 | } |
64 | } |
65 | return null; |
66 | } |
67 | |
68 | |
69 | void addAndSelectTab(Tab tab) { |
70 | addTab(tab); |
71 | selectTab(tab); |
72 | } |
73 | |
74 | public void addTab(final Tab tab) { |
75 | TabCaption caption = tab.getCaption(); |
76 | caption.addPropertyChangeListener("CloseButtonPressed", new TabCaptionCloseTabListener()); |
77 | caption.addPropertyChangeListener("TabSelected", new SelectTabListener()); |
78 | |
79 | TabContent content = tab.getContent(); |
80 | content.addPropertyChangeListener("TabClosed", new TabContentCloseTabListener()); |
81 | |
82 | captions.addTab(caption); |
83 | tabs.add(tab); |
84 | validate(); |
85 | repaint(); |
86 | } |
87 | |
88 | private boolean hasTabs() { |
89 | return !tabs.isEmpty(); |
90 | } |
91 | |
92 | private Tab getFirstTab() { |
93 | return tabs.get(0); |
94 | } |
95 | |
96 | private List<Tab> getTabs() { |
97 | return new ArrayList<Tab>(tabs); |
98 | } |
99 | |
100 | public void removeTab(Tab tab) { |
101 | TabCaption tabCaption = tab.getCaption(); |
102 | captions.removeTab(tabCaption); |
103 | tabs.remove(tab); |
104 | validate(); |
105 | repaint(); |
106 | } |
107 | |
108 | public void addTabButton(TabButton button) { |
109 | captions.addTabButton(button); |
110 | } |
111 | |
112 | public void selectTab(Tab tab) { |
113 | TabCaption tabCaption = tab.getCaption(); |
114 | TabCaption selectedTab = captions.getSelectedTab(); |
115 | if (selectedTab != null && !selectedTab.equals(tabCaption)) { |
116 | selectedTab.setSelected(false); |
117 | } |
118 | captions.setSelectedTab(tabCaption); |
119 | } |
120 | |
121 | private class TabCaptionCloseTabListener implements PropertyChangeListener { |
122 | public void propertyChange(PropertyChangeEvent evt) { |
123 | TabCaption caption = (TabCaption) evt.getSource(); |
124 | Tab tab = findTab(caption); |
125 | disposeTab(tab); |
126 | } |
127 | } |
128 | |
129 | private class SelectTabListener implements PropertyChangeListener { |
130 | public void propertyChange(PropertyChangeEvent evt) { |
131 | TabCaption caption = (TabCaption) evt.getSource(); |
132 | Tab tab = findTab(caption); |
133 | if (caption.isSelected()) { |
134 | selectTab(tab); |
135 | } |
136 | if (!caption.isSelected()) { |
137 | TabContent content = tab.getContent(); |
138 | contentContainer.remove(content); |
139 | contentContainer.validate(); |
140 | contentContainer.repaint(); |
141 | } else { |
142 | final TabContent content = tab.getContent(); |
143 | contentContainer.add(content, BorderLayout.CENTER); |
144 | contentContainer.validate(); |
145 | contentContainer.repaint(); |
146 | } |
147 | } |
148 | } |
149 | |
150 | private class TabContentCloseTabListener implements PropertyChangeListener { |
151 | public void propertyChange(PropertyChangeEvent evt) { |
152 | TabContent content = (TabContent) evt.getSource(); |
153 | Tab tab = findTab(content); |
154 | disposeTab(tab); |
155 | } |
156 | |
157 | private Tab findTab(TabContent content) { |
158 | for (Tab tab : getTabs()) { |
159 | if (tab.getContent().equals(content)) { |
160 | return tab; |
161 | } |
162 | } |
163 | return null; |
164 | } |
165 | } |
166 | } |
167 | |
168 | static class TabFactory { |
169 | |
170 | public static Tab createTab(BrowserContext context) { |
171 | return createTab(context, "about:blank"); |
172 | } |
173 | |
174 | public static Tab createTab(BrowserContext context, String url) { |
175 | Browser browser = new Browser(BrowserType.LIGHTWEIGHT, context); |
176 | print("Made browser " + browser); |
177 | BrowserView browserView = new BrowserView(browser); |
178 | TabContent tabContent = new TabContent(browserView); |
179 | |
180 | browser.setDownloadHandler(new DefaultDownloadHandler(browserView)); |
181 | browser.setDialogHandler(new DefaultDialogHandler(browserView)); |
182 | browser.setPopupHandler(new DefaultPopupHandler()); |
183 | |
184 | final TabCaption tabCaption = new TabCaption(); |
185 | tabCaption.setTitle("about:blank"); |
186 | |
187 | tabContent.addPropertyChangeListener("PageTitleChanged", new PropertyChangeListener() { |
188 | public void propertyChange(PropertyChangeEvent evt) { |
189 | tabCaption.setTitle((String) evt.getNewValue()); |
190 | } |
191 | }); |
192 | |
193 | browser.loadURL(url); |
194 | return new Tab(tabCaption, tabContent); |
195 | } |
196 | } |
197 | |
198 | sclass Tab { |
199 | |
200 | private final TabCaption caption; |
201 | private final TabContent content; |
202 | |
203 | public Tab(TabCaption caption, TabContent content) { |
204 | this.caption = caption; |
205 | this.content = content; |
206 | } |
207 | |
208 | public TabCaption getCaption() { |
209 | return caption; |
210 | } |
211 | |
212 | public TabContent getContent() { |
213 | return content; |
214 | } |
215 | } |
216 | |
217 | sclass TabButton extends JButton { |
218 | |
219 | public TabButton(Icon icon, String toolTipText) { |
220 | setIcon(icon); |
221 | setToolTipText(toolTipText); |
222 | setOpaque(false); |
223 | setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); |
224 | setContentAreaFilled(false); |
225 | setFocusable(false); |
226 | } |
227 | |
228 | } |
229 | |
230 | sclass TabCaption extends JPanel { |
231 | |
232 | private boolean selected; |
233 | private TabCaptionComponent component; |
234 | |
235 | public TabCaption() { |
236 | setLayout(new BorderLayout()); |
237 | setOpaque(false); |
238 | add(createComponent(), BorderLayout.CENTER); |
239 | add(Box.createHorizontalStrut(1), BorderLayout.EAST); |
240 | } |
241 | |
242 | private JComponent createComponent() { |
243 | component = new TabCaptionComponent(); |
244 | component.addPropertyChangeListener("CloseButtonPressed", new PropertyChangeListener() { |
245 | public void propertyChange(PropertyChangeEvent evt) { |
246 | firePropertyChange("CloseButtonPressed", evt.getOldValue(), evt.getNewValue()); |
247 | } |
248 | }); |
249 | component.addPropertyChangeListener("TabClicked", new PropertyChangeListener() { |
250 | public void propertyChange(PropertyChangeEvent evt) { |
251 | setSelected(true); |
252 | } |
253 | }); |
254 | return component; |
255 | } |
256 | |
257 | @Override |
258 | public Dimension getPreferredSize() { |
259 | return new Dimension(155, 26); |
260 | } |
261 | |
262 | @Override |
263 | public Dimension getMinimumSize() { |
264 | return new Dimension(50, 26); |
265 | } |
266 | |
267 | @Override |
268 | public Dimension getMaximumSize() { |
269 | return getPreferredSize(); |
270 | } |
271 | |
272 | public void setTitle(String title) { |
273 | component.setTitle(title); |
274 | } |
275 | |
276 | public boolean isSelected() { |
277 | return selected; |
278 | } |
279 | |
280 | public void setSelected(boolean selected) { |
281 | boolean oldValue = this.selected; |
282 | this.selected = selected; |
283 | component.setSelected(selected); |
284 | firePropertyChange("TabSelected", oldValue, selected); |
285 | } |
286 | |
287 | private static class TabCaptionComponent extends JPanel { |
288 | |
289 | private final Color defaultBackground; |
290 | private JLabel label; |
291 | |
292 | private TabCaptionComponent() { |
293 | defaultBackground = getBackground(); |
294 | setLayout(new BorderLayout()); |
295 | setOpaque(false); |
296 | add(createLabel(), BorderLayout.CENTER); |
297 | add(createCloseButton(), BorderLayout.EAST); |
298 | } |
299 | |
300 | private JComponent createLabel() { |
301 | label = new JLabel(); |
302 | label.setOpaque(false); |
303 | label.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); |
304 | label.addMouseListener(new MouseAdapter() { |
305 | @Override |
306 | public void mousePressed(MouseEvent e) { |
307 | if (e.getButton() == MouseEvent.BUTTON1) { |
308 | firePropertyChange("TabClicked", false, true); |
309 | } |
310 | if (e.getButton() == MouseEvent.BUTTON2) { |
311 | firePropertyChange("CloseButtonPressed", false, true); |
312 | } |
313 | } |
314 | }); |
315 | return label; |
316 | } |
317 | |
318 | private JComponent createCloseButton() { |
319 | JButton closeButton = new JButton(); |
320 | closeButton.setOpaque(false); |
321 | closeButton.setToolTipText("Close"); |
322 | closeButton.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); |
323 | closeButton.setPressedIcon(Resources.getIcon("close-pressed.png")); |
324 | closeButton.setIcon(Resources.getIcon("close.png")); |
325 | closeButton.setContentAreaFilled(false); |
326 | closeButton.setFocusable(false); |
327 | closeButton.addActionListener(new ActionListener() { |
328 | public void actionPerformed(ActionEvent e) { |
329 | firePropertyChange("CloseButtonPressed", false, true); |
330 | } |
331 | }); |
332 | return closeButton; |
333 | } |
334 | |
335 | public void setTitle(final String title) { |
336 | SwingUtilities.invokeLater(new Runnable() { |
337 | public void run() { |
338 | label.setText(title); |
339 | label.setToolTipText(title); |
340 | } |
341 | }); |
342 | } |
343 | |
344 | public void setSelected(boolean selected) { |
345 | setBackground(selected ? defaultBackground : new Color(150, 150, 150)); |
346 | repaint(); |
347 | } |
348 | |
349 | @Override |
350 | public void paint(Graphics g) { |
351 | Graphics2D g2d = (Graphics2D) g.create(); |
352 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
353 | RenderingHints.VALUE_ANTIALIAS_ON); |
354 | g2d.setPaint( |
355 | new GradientPaint(0, 0, Color.LIGHT_GRAY, 0, getHeight(), getBackground())); |
356 | g2d.fillRect(0, 0, getWidth(), getHeight()); |
357 | g2d.dispose(); |
358 | super.paint(g); |
359 | } |
360 | } |
361 | } |
362 | |
363 | sclass TabCaptions extends JPanel { |
364 | |
365 | private TabCaption selectedTab; |
366 | |
367 | private JPanel tabsPane; |
368 | private JPanel buttonsPane; |
369 | |
370 | public TabCaptions() { |
371 | createUI(); |
372 | } |
373 | |
374 | private void createUI() { |
375 | setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); |
376 | setBackground(Color.DARK_GRAY); |
377 | add(createItemsPane()); |
378 | add(createButtonsPane()); |
379 | add(Box.createHorizontalGlue()); |
380 | } |
381 | |
382 | private JComponent createItemsPane() { |
383 | tabsPane = new JPanel(); |
384 | tabsPane.setOpaque(false); |
385 | tabsPane.setLayout(new BoxLayout(tabsPane, BoxLayout.X_AXIS)); |
386 | return tabsPane; |
387 | } |
388 | |
389 | private JComponent createButtonsPane() { |
390 | buttonsPane = new JPanel(); |
391 | buttonsPane.setOpaque(false); |
392 | buttonsPane.setLayout(new BoxLayout(buttonsPane, BoxLayout.X_AXIS)); |
393 | return buttonsPane; |
394 | } |
395 | |
396 | public void addTab(TabCaption item) { |
397 | tabsPane.add(item); |
398 | } |
399 | |
400 | public void removeTab(TabCaption item) { |
401 | tabsPane.remove(item); |
402 | } |
403 | |
404 | public void addTabButton(TabButton button) { |
405 | buttonsPane.add(button); |
406 | } |
407 | |
408 | public TabCaption getSelectedTab() { |
409 | return selectedTab; |
410 | } |
411 | |
412 | public void setSelectedTab(TabCaption selectedTab) { |
413 | this.selectedTab = selectedTab; |
414 | this.selectedTab.setSelected(true); |
415 | } |
416 | } |
417 | |
418 | sclass TabContent extends JPanel { |
419 | |
420 | private final BrowserView browserView; |
421 | private final ToolBar toolBar; |
422 | private final JComponent jsConsole; |
423 | private final JComponent container; |
424 | private final JComponent browserContainer; |
425 | |
426 | public TabContent(final BrowserView browserView) { |
427 | this.browserView = browserView; |
428 | this.browserView.getBrowser().addLoadListener(new LoadAdapter() { |
429 | @Override |
430 | public void onFinishLoadingFrame(FinishLoadingEvent event) { |
431 | if (event.isMainFrame()) { |
432 | firePropertyChange("PageTitleChanged", null, |
433 | TabContent.this.browserView.getBrowser().getTitle()); |
434 | } |
435 | } |
436 | }); |
437 | |
438 | this.browserView.getBrowser().addTitleListener(new TitleListener() { |
439 | @Override |
440 | public void onTitleChange(TitleEvent event) { |
441 | firePropertyChange("PageTitleChanged", null, event.getTitle()); |
442 | } |
443 | }); |
444 | |
445 | browserContainer = createBrowserContainer(); |
446 | jsConsole = createConsole(); |
447 | toolBar = createToolBar(browserView); |
448 | |
449 | container = new JPanel(new BorderLayout()); |
450 | container.add(browserContainer, BorderLayout.CENTER); |
451 | |
452 | setLayout(new BorderLayout()); |
453 | add(toolBar, BorderLayout.NORTH); |
454 | add(container, BorderLayout.CENTER); |
455 | } |
456 | |
457 | private ToolBar createToolBar(BrowserView browserView) { |
458 | ToolBar toolBar = new ToolBar(browserView); |
459 | toolBar.addPropertyChangeListener("TabClosed", new PropertyChangeListener() { |
460 | public void propertyChange(PropertyChangeEvent evt) { |
461 | firePropertyChange("TabClosed", false, true); |
462 | } |
463 | }); |
464 | toolBar.addPropertyChangeListener("JSConsoleDisplayed", new PropertyChangeListener() { |
465 | public void propertyChange(PropertyChangeEvent evt) { |
466 | showConsole(); |
467 | } |
468 | }); |
469 | toolBar.addPropertyChangeListener("JSConsoleClosed", new PropertyChangeListener() { |
470 | public void propertyChange(PropertyChangeEvent evt) { |
471 | hideConsole(); |
472 | } |
473 | }); |
474 | return toolBar; |
475 | } |
476 | |
477 | private void hideConsole() { |
478 | showComponent(browserContainer); |
479 | } |
480 | |
481 | private void showComponent(JComponent component) { |
482 | container.removeAll(); |
483 | container.add(component, BorderLayout.CENTER); |
484 | validate(); |
485 | } |
486 | |
487 | private void showConsole() { |
488 | JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); |
489 | splitPane.add(browserContainer, JSplitPane.TOP); |
490 | splitPane.add(jsConsole, JSplitPane.BOTTOM); |
491 | splitPane.setResizeWeight(0.8); |
492 | splitPane.setBorder(BorderFactory.createEmptyBorder()); |
493 | showComponent(splitPane); |
494 | } |
495 | |
496 | private JComponent createConsole() { |
497 | JSConsole result = new JSConsole(browserView.getBrowser()); |
498 | result.addPropertyChangeListener("JSConsoleClosed", new PropertyChangeListener() { |
499 | public void propertyChange(PropertyChangeEvent evt) { |
500 | hideConsole(); |
501 | toolBar.didJSConsoleClose(); |
502 | } |
503 | }); |
504 | return result; |
505 | } |
506 | |
507 | private JComponent createBrowserContainer() { |
508 | JPanel container = new JPanel(new BorderLayout()); |
509 | container.add(browserView, BorderLayout.CENTER); |
510 | return container; |
511 | } |
512 | |
513 | public void dispose() { |
514 | Browser b = browserView.getBrowser(); |
515 | _print("Disposing browser " + b); |
516 | b.dispose(); |
517 | } |
518 | } |
519 | |
520 | sclass ToolBar extends JPanel { |
521 | private static final String RUN_JAVASCRIPT = "Run JavaScript..."; |
522 | private static final String CLOSE_JAVASCRIPT = "Close JavaScript Console"; |
523 | private static final String DEFAULT_URL = "about:blank"; |
524 | private final JTextField addressBar; |
525 | private final BrowserView browserView; |
526 | private JButton backwardButton; |
527 | private JButton forwardButton; |
528 | private JButton refreshButton; |
529 | private JButton stopButton; |
530 | private JMenuItem consoleMenuItem; |
531 | |
532 | public ToolBar(BrowserView browserView) { |
533 | this.browserView = browserView; |
534 | addressBar = createAddressBar(); |
535 | setLayout(new GridBagLayout()); |
536 | add(createActionsPane(), |
537 | new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, |
538 | GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); |
539 | add(addressBar, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, |
540 | GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(4, 0, 4, 5), 0, 0)); |
541 | add(createMenuButton(), new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, |
542 | GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 5), |
543 | 0, 0)); |
544 | } |
545 | |
546 | private static JButton createBackwardButton(final Browser browser) { |
547 | return createButton("Back", new AbstractAction() { |
548 | public void actionPerformed(ActionEvent e) { |
549 | browser.goBack(); |
550 | } |
551 | }); |
552 | } |
553 | |
554 | private static JButton createForwardButton(final Browser browser) { |
555 | return createButton("Forward", new AbstractAction() { |
556 | public void actionPerformed(ActionEvent e) { |
557 | browser.goForward(); |
558 | } |
559 | }); |
560 | } |
561 | |
562 | private static JButton createRefreshButton(final Browser browser) { |
563 | return createButton("Refresh", new AbstractAction() { |
564 | public void actionPerformed(ActionEvent e) { |
565 | browser.reload(); |
566 | } |
567 | }); |
568 | } |
569 | |
570 | private static JButton createStopButton(final Browser browser) { |
571 | return createButton("Stop", new AbstractAction() { |
572 | public void actionPerformed(ActionEvent e) { |
573 | browser.stop(); |
574 | } |
575 | }); |
576 | } |
577 | |
578 | private static JButton createButton(String caption, Action action) { |
579 | ActionButton button = new ActionButton(caption, action); |
580 | String imageName = caption.toLowerCase(); |
581 | button.setIcon(Resources.getIcon(imageName + ".png")); |
582 | button.setRolloverIcon(Resources.getIcon(imageName + "-selected.png")); |
583 | return button; |
584 | } |
585 | |
586 | private static JCheckBoxMenuItem createCheckBoxMenuItem(String title, boolean selected, |
587 | final CheckBoxMenuItemCallback action) { |
588 | final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(title, selected); |
589 | menuItem.addActionListener(new ActionListener() { |
590 | public void actionPerformed(ActionEvent e) { |
591 | action.call(menuItem.isSelected()); |
592 | } |
593 | }); |
594 | return menuItem; |
595 | } |
596 | |
597 | public void didJSConsoleClose() { |
598 | consoleMenuItem.setText(RUN_JAVASCRIPT); |
599 | } |
600 | |
601 | private JPanel createActionsPane() { |
602 | backwardButton = createBackwardButton(browserView.getBrowser()); |
603 | forwardButton = createForwardButton(browserView.getBrowser()); |
604 | refreshButton = createRefreshButton(browserView.getBrowser()); |
605 | stopButton = createStopButton(browserView.getBrowser()); |
606 | |
607 | JPanel actionsPanel = new JPanel(); |
608 | actionsPanel.add(backwardButton); |
609 | actionsPanel.add(forwardButton); |
610 | actionsPanel.add(refreshButton); |
611 | actionsPanel.add(stopButton); |
612 | return actionsPanel; |
613 | } |
614 | |
615 | private JTextField createAddressBar() { |
616 | final JTextField result = new JTextField(DEFAULT_URL); |
617 | result.addActionListener(new ActionListener() { |
618 | public void actionPerformed(ActionEvent e) { |
619 | browserView.getBrowser().loadURL(result.getText()); |
620 | } |
621 | }); |
622 | |
623 | browserView.getBrowser().addLoadListener(new LoadAdapter() { |
624 | @Override |
625 | public void onStartLoadingFrame(StartLoadingEvent event) { |
626 | if (event.isMainFrame()) { |
627 | SwingUtilities.invokeLater(new Runnable() { |
628 | public void run() { |
629 | refreshButton.setEnabled(false); |
630 | stopButton.setEnabled(true); |
631 | } |
632 | }); |
633 | } |
634 | } |
635 | |
636 | @Override |
637 | public void onProvisionalLoadingFrame(final ProvisionalLoadingEvent event) { |
638 | if (event.isMainFrame()) { |
639 | SwingUtilities.invokeLater(new Runnable() { |
640 | @Override |
641 | public void run() { |
642 | result.setText(event.getURL()); |
643 | result.setCaretPosition(result.getText().length()); |
644 | |
645 | Browser browser = event.getBrowser(); |
646 | forwardButton.setEnabled(browser.canGoForward()); |
647 | backwardButton.setEnabled(browser.canGoBack()); |
648 | } |
649 | }); |
650 | } |
651 | } |
652 | |
653 | @Override |
654 | public void onFinishLoadingFrame(final FinishLoadingEvent event) { |
655 | if (event.isMainFrame()) { |
656 | SwingUtilities.invokeLater(new Runnable() { |
657 | public void run() { |
658 | refreshButton.setEnabled(true); |
659 | stopButton.setEnabled(false); |
660 | } |
661 | }); |
662 | } |
663 | } |
664 | }); |
665 | return result; |
666 | } |
667 | |
668 | private JComponent createMenuButton() { |
669 | final JPopupMenu popupMenu = new JPopupMenu(); |
670 | popupMenu.add(createConsoleMenuItem()); |
671 | popupMenu.add(createGetHTMLMenuItem()); |
672 | popupMenu.add(createPopupsMenuItem()); |
673 | popupMenu.add(createUploadFileMenuItem()); |
674 | popupMenu.add(createDownloadFileMenuItem()); |
675 | popupMenu.add(createJavaScriptDialogsMenuItem()); |
676 | popupMenu.add(createPDFViewerMenuItem()); |
677 | popupMenu.add(createFlashMenuItem()); |
678 | popupMenu.add(createGoogleMapsMenuItem()); |
679 | popupMenu.add(createHTML5VideoMenuItem()); |
680 | popupMenu.add(createZoomInMenuItem()); |
681 | popupMenu.add(createZoomOutMenuItem()); |
682 | popupMenu.add(createActualSizeMenuItem()); |
683 | popupMenu.add(createSaveWebPageMenuItem()); |
684 | popupMenu.add(createClearCacheMenuItem()); |
685 | popupMenu.add(createPreferencesSubMenu()); |
686 | popupMenu.add(createExecuteCommandSubMenu()); |
687 | popupMenu.add(createPrintMenuItem()); |
688 | popupMenu.addSeparator(); |
689 | popupMenu.add(createMoreMenuItem()); |
690 | popupMenu.addSeparator(); |
691 | //popupMenu.add(createAboutMenuItem()); |
692 | |
693 | final ActionButton button = new ActionButton("Preferences", null); |
694 | button.setIcon(Resources.getIcon("gear.png")); |
695 | button.addMouseListener(new MouseAdapter() { |
696 | public void mousePressed(MouseEvent e) { |
697 | if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { |
698 | popupMenu.show(e.getComponent(), 0, button.getHeight()); |
699 | } else { |
700 | popupMenu.setVisible(false); |
701 | } |
702 | } |
703 | }); |
704 | return button; |
705 | } |
706 | |
707 | private Component createPrintMenuItem() { |
708 | JMenuItem menuItem = new JMenuItem("Print..."); |
709 | menuItem.addActionListener(new ActionListener() { |
710 | public void actionPerformed(ActionEvent e) { |
711 | browserView.getBrowser().print(); |
712 | } |
713 | }); |
714 | return menuItem; |
715 | } |
716 | |
717 | private Component createPreferencesSubMenu() { |
718 | JMenu menu = new JMenu("Preferences"); |
719 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
720 | menu.add(createCheckBoxMenuItem("JavaScript Enabled", preferences.isJavaScriptEnabled(), |
721 | new CheckBoxMenuItemCallback() { |
722 | public void call(boolean selected) { |
723 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
724 | preferences.setJavaScriptEnabled(selected); |
725 | browserView.getBrowser().setPreferences(preferences); |
726 | browserView.getBrowser().reloadIgnoringCache(); |
727 | } |
728 | })); |
729 | menu.add(createCheckBoxMenuItem("Images Enabled", preferences.isImagesEnabled(), |
730 | new CheckBoxMenuItemCallback() { |
731 | public void call(boolean selected) { |
732 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
733 | preferences.setImagesEnabled(selected); |
734 | browserView.getBrowser().setPreferences(preferences); |
735 | browserView.getBrowser().reloadIgnoringCache(); |
736 | } |
737 | })); |
738 | menu.add(createCheckBoxMenuItem("Plugins Enabled", preferences.isPluginsEnabled(), |
739 | new CheckBoxMenuItemCallback() { |
740 | public void call(boolean selected) { |
741 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
742 | preferences.setPluginsEnabled(selected); |
743 | browserView.getBrowser().setPreferences(preferences); |
744 | browserView.getBrowser().reloadIgnoringCache(); |
745 | } |
746 | })); |
747 | menu.add(createCheckBoxMenuItem("JavaScript Can Access Clipboard", |
748 | preferences.isJavaScriptCanAccessClipboard(), new CheckBoxMenuItemCallback() { |
749 | public void call(boolean selected) { |
750 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
751 | preferences.setJavaScriptCanAccessClipboard(selected); |
752 | browserView.getBrowser().setPreferences(preferences); |
753 | browserView.getBrowser().reloadIgnoringCache(); |
754 | } |
755 | })); |
756 | menu.add(createCheckBoxMenuItem("JavaScript Can Open Windows", |
757 | preferences.isJavaScriptCanOpenWindowsAutomatically(), |
758 | new CheckBoxMenuItemCallback() { |
759 | public void call(boolean selected) { |
760 | BrowserPreferences preferences = browserView.getBrowser().getPreferences(); |
761 | preferences.setJavaScriptCanOpenWindowsAutomatically(selected); |
762 | browserView.getBrowser().setPreferences(preferences); |
763 | browserView.getBrowser().reloadIgnoringCache(); |
764 | } |
765 | })); |
766 | return menu; |
767 | } |
768 | |
769 | private Component createClearCacheMenuItem() { |
770 | JMenuItem menuItem = new JMenuItem("Clear Cache"); |
771 | menuItem.addActionListener(new ActionListener() { |
772 | public void actionPerformed(ActionEvent e) { |
773 | browserView.getBrowser().getCacheStorage().clearCache(new Callback() { |
774 | public void invoke() { |
775 | JOptionPane.showMessageDialog(browserView, "Cache is cleared successfully.", |
776 | "Clear Cache", JOptionPane.INFORMATION_MESSAGE); |
777 | } |
778 | }); |
779 | } |
780 | }); |
781 | return menuItem; |
782 | } |
783 | |
784 | private Component createExecuteCommandSubMenu() { |
785 | final JMenu menu = new JMenu("Execute Command"); |
786 | menu.addMenuListener(new MenuListener() { |
787 | public void menuSelected(MenuEvent e) { |
788 | Component[] menuItems = menu.getMenuComponents(); |
789 | for (Component menuItem : menuItems) { |
790 | menuItem.setEnabled(browserView.getBrowser() |
791 | .isCommandEnabled(((CommandMenuItem) menuItem).getCommand())); |
792 | } |
793 | } |
794 | |
795 | public void menuDeselected(MenuEvent e) { |
796 | |
797 | } |
798 | |
799 | public void menuCanceled(MenuEvent e) { |
800 | |
801 | } |
802 | }); |
803 | |
804 | menu.add(createExecuteCommandSubMenuItem("Cut", EditorCommand.CUT)); |
805 | menu.add(createExecuteCommandSubMenuItem("Copy", EditorCommand.COPY)); |
806 | menu.add(createExecuteCommandSubMenuItem("Paste", EditorCommand.PASTE)); |
807 | menu.add(createExecuteCommandSubMenuItem("Select All", EditorCommand.SELECT_ALL)); |
808 | menu.add(createExecuteCommandSubMenuItem("Unselect", EditorCommand.UNSELECT)); |
809 | menu.add(createExecuteCommandSubMenuItem("Undo", EditorCommand.UNDO)); |
810 | menu.add(createExecuteCommandSubMenuItem("Redo", EditorCommand.REDO)); |
811 | menu.add(createExecuteCommandSubMenuItem("Insert Text...", "Insert Text", |
812 | EditorCommand.INSERT_TEXT)); |
813 | menu.add(createExecuteCommandSubMenuItem("Find Text...", "Find Text", |
814 | EditorCommand.FIND_STRING)); |
815 | return menu; |
816 | } |
817 | |
818 | private Component createExecuteCommandSubMenuItem(final String commandName, |
819 | final EditorCommand command) { |
820 | final CommandMenuItem menuItem = new CommandMenuItem(commandName, command); |
821 | menuItem.addActionListener(new ActionListener() { |
822 | public void actionPerformed(ActionEvent e) { |
823 | browserView.getBrowser().executeCommand(command); |
824 | } |
825 | }); |
826 | return menuItem; |
827 | } |
828 | |
829 | private Component createExecuteCommandSubMenuItem(final String commandName, |
830 | final String dialogTitle, final EditorCommand command) { |
831 | final CommandMenuItem menuItem = new CommandMenuItem(commandName, command); |
832 | menuItem.addActionListener(new ActionListener() { |
833 | public void actionPerformed(ActionEvent e) { |
834 | String value = JOptionPane |
835 | .showInputDialog(browserView, "Command value:", dialogTitle, |
836 | JOptionPane.PLAIN_MESSAGE); |
837 | browserView.getBrowser().executeCommand(command, value); |
838 | } |
839 | }); |
840 | return menuItem; |
841 | } |
842 | |
843 | private Component createMoreMenuItem() { |
844 | JMenuItem menuItem = new JMenuItem("More Features..."); |
845 | menuItem.addActionListener(new ActionListener() { |
846 | public void actionPerformed(ActionEvent e) { |
847 | browserView.getBrowser().loadURL( |
848 | "https://jxbrowser.support.teamdev.com/support/solutions/9000049010"); |
849 | } |
850 | }); |
851 | return menuItem; |
852 | } |
853 | |
854 | private Component createSaveWebPageMenuItem() { |
855 | JMenuItem menuItem = new JMenuItem("Save Web Page..."); |
856 | menuItem.addActionListener(new ActionListener() { |
857 | public void actionPerformed(ActionEvent e) { |
858 | JFileChooser fileChooser = new JFileChooser(); |
859 | fileChooser.setSelectedFile(new File("my-web-page.html")); |
860 | int result = fileChooser.showSaveDialog(browserView); |
861 | if (result == JFileChooser.APPROVE_OPTION) { |
862 | File selectedFile = fileChooser.getSelectedFile(); |
863 | String dirPath = new File(selectedFile.getParent(), "resources") |
864 | .getAbsolutePath(); |
865 | browserView.getBrowser().saveWebPage(selectedFile.getAbsolutePath(), dirPath, |
866 | SavePageType.COMPLETE_HTML); |
867 | } |
868 | } |
869 | }); |
870 | return menuItem; |
871 | } |
872 | |
873 | private Component createActualSizeMenuItem() { |
874 | JMenuItem menuItem = new JMenuItem("Actual Size"); |
875 | menuItem.addActionListener(new ActionListener() { |
876 | public void actionPerformed(ActionEvent e) { |
877 | browserView.getBrowser().zoomReset(); |
878 | } |
879 | }); |
880 | return menuItem; |
881 | } |
882 | |
883 | private Component createZoomOutMenuItem() { |
884 | JMenuItem menuItem = new JMenuItem("Zoom Out"); |
885 | menuItem.addActionListener(new ActionListener() { |
886 | public void actionPerformed(ActionEvent e) { |
887 | browserView.getBrowser().zoomOut(); |
888 | } |
889 | }); |
890 | return menuItem; |
891 | } |
892 | |
893 | private Component createZoomInMenuItem() { |
894 | JMenuItem menuItem = new JMenuItem("Zoom In"); |
895 | menuItem.addActionListener(new ActionListener() { |
896 | public void actionPerformed(ActionEvent e) { |
897 | browserView.getBrowser().zoomIn(); |
898 | } |
899 | }); |
900 | return menuItem; |
901 | } |
902 | |
903 | private Component createHTML5VideoMenuItem() { |
904 | JMenuItem menuItem = new JMenuItem("HTML5 Video"); |
905 | menuItem.addActionListener(new ActionListener() { |
906 | public void actionPerformed(ActionEvent e) { |
907 | browserView.getBrowser() |
908 | .loadURL("http://www.w3.org/2010/05/video/mediaevents.html"); |
909 | } |
910 | }); |
911 | return menuItem; |
912 | } |
913 | |
914 | private Component createGoogleMapsMenuItem() { |
915 | JMenuItem menuItem = new JMenuItem("Google Maps"); |
916 | menuItem.addActionListener(new ActionListener() { |
917 | public void actionPerformed(ActionEvent e) { |
918 | browserView.getBrowser().loadURL("https://maps.google.com/"); |
919 | } |
920 | }); |
921 | return menuItem; |
922 | } |
923 | |
924 | private Component createJavaScriptDialogsMenuItem() { |
925 | JMenuItem menuItem = new JMenuItem("JavaScript Dialogs"); |
926 | menuItem.addActionListener(new ActionListener() { |
927 | public void actionPerformed(ActionEvent e) { |
928 | browserView.getBrowser().loadURL("http://www.javascripter.net/faq/alert.htm"); |
929 | } |
930 | }); |
931 | return menuItem; |
932 | } |
933 | |
934 | private Component createDownloadFileMenuItem() { |
935 | JMenuItem menuItem = new JMenuItem("Download File"); |
936 | menuItem.addActionListener(new ActionListener() { |
937 | public void actionPerformed(ActionEvent e) { |
938 | browserView.getBrowser().loadURL( |
939 | "https://s3.amazonaws.com/cloud.teamdev.com/downloads/demo/jxbrowserdemo.jnlp"); |
940 | } |
941 | }); |
942 | return menuItem; |
943 | } |
944 | |
945 | private Component createGetHTMLMenuItem() { |
946 | JMenuItem menuItem = new JMenuItem("Get HTML"); |
947 | menuItem.addActionListener(new ActionListener() { |
948 | public void actionPerformed(ActionEvent e) { |
949 | String html = browserView.getBrowser().getHTML(); |
950 | Window window = SwingUtilities.getWindowAncestor(browserView); |
951 | JDialog dialog = new JDialog(window); |
952 | dialog.setModal(true); |
953 | dialog.setContentPane(new JScrollPane(new JTextArea(html))); |
954 | dialog.setSize(700, 500); |
955 | dialog.setLocationRelativeTo(null); |
956 | dialog.setVisible(true); |
957 | |
958 | } |
959 | }); |
960 | return menuItem; |
961 | } |
962 | |
963 | private JMenuItem createConsoleMenuItem() { |
964 | consoleMenuItem = new JMenuItem(RUN_JAVASCRIPT); |
965 | consoleMenuItem.addActionListener(new ActionListener() { |
966 | public void actionPerformed(ActionEvent e) { |
967 | if (RUN_JAVASCRIPT.equals(consoleMenuItem.getText())) { |
968 | consoleMenuItem.setText(CLOSE_JAVASCRIPT); |
969 | firePropertyChange("JSConsoleDisplayed", false, true); |
970 | } else { |
971 | consoleMenuItem.setText(RUN_JAVASCRIPT); |
972 | firePropertyChange("JSConsoleClosed", false, true); |
973 | } |
974 | } |
975 | }); |
976 | return consoleMenuItem; |
977 | } |
978 | |
979 | private JMenuItem createUploadFileMenuItem() { |
980 | JMenuItem menuItem = new JMenuItem("Upload File"); |
981 | menuItem.addActionListener(new ActionListener() { |
982 | public void actionPerformed(ActionEvent e) { |
983 | browserView.getBrowser() |
984 | .loadURL("http://www.cs.tut.fi/~jkorpela/forms/file.html#example"); |
985 | } |
986 | }); |
987 | return menuItem; |
988 | } |
989 | |
990 | private JMenuItem createPopupsMenuItem() { |
991 | JMenuItem menuItem = new JMenuItem("Popup Windows"); |
992 | menuItem.addActionListener(new ActionListener() { |
993 | public void actionPerformed(ActionEvent e) { |
994 | browserView.getBrowser().loadURL("http://www.popuptest.com"); |
995 | } |
996 | }); |
997 | return menuItem; |
998 | } |
999 | |
1000 | private JMenuItem createPDFViewerMenuItem() { |
1001 | JMenuItem menuItem = new JMenuItem("PDF Viewer"); |
1002 | menuItem.addActionListener(new ActionListener() { |
1003 | public void actionPerformed(ActionEvent e) { |
1004 | browserView.getBrowser().loadURL("http://www.orimi.com/pdf-test.pdf"); |
1005 | } |
1006 | }); |
1007 | return menuItem; |
1008 | } |
1009 | |
1010 | private JMenuItem createFlashMenuItem() { |
1011 | JMenuItem menuItem = new JMenuItem("Adobe Flash"); |
1012 | menuItem.addActionListener(new ActionListener() { |
1013 | public void actionPerformed(ActionEvent e) { |
1014 | browserView.getBrowser().loadURL("http://helpx.adobe.com/flash-player.html"); |
1015 | } |
1016 | }); |
1017 | return menuItem; |
1018 | } |
1019 | |
1020 | /*private JMenuItem createAboutMenuItem() { |
1021 | JMenuItem menuItem = new JMenuItem("About JxBrowser Demo"); |
1022 | menuItem.addActionListener(new ActionListener() { |
1023 | public void actionPerformed(ActionEvent e) { |
1024 | Frame parentFrame = (Frame) SwingUtilities.getWindowAncestor(ToolBar.this); |
1025 | AboutDialog aboutDialog = new AboutDialog(parentFrame); |
1026 | aboutDialog.setVisible(true); |
1027 | } |
1028 | }); |
1029 | return menuItem; |
1030 | }*/ |
1031 | |
1032 | private boolean isFocusRequired() { |
1033 | String url = addressBar.getText(); |
1034 | return url.isEmpty() || url.equals(DEFAULT_URL); |
1035 | } |
1036 | |
1037 | @Override |
1038 | public void addNotify() { |
1039 | super.addNotify(); |
1040 | SwingUtilities.invokeLater(new Runnable() { |
1041 | public void run() { |
1042 | if (isFocusRequired()) { |
1043 | addressBar.requestFocus(); |
1044 | addressBar.selectAll(); |
1045 | } |
1046 | } |
1047 | }); |
1048 | } |
1049 | |
1050 | private interface CheckBoxMenuItemCallback { |
1051 | void call(boolean selected); |
1052 | } |
1053 | |
1054 | private static class ActionButton extends JButton { |
1055 | private ActionButton(String hint, Action action) { |
1056 | super(action); |
1057 | setContentAreaFilled(false); |
1058 | setBorder(BorderFactory.createEmptyBorder()); |
1059 | setBorderPainted(false); |
1060 | setRolloverEnabled(true); |
1061 | setToolTipText(hint); |
1062 | setText(null); |
1063 | setFocusable(false); |
1064 | setDefaultCapable(false); |
1065 | } |
1066 | } |
1067 | } |
1068 | |
1069 | sclass CommandMenuItem extends JMenuItem { |
1070 | |
1071 | private final EditorCommand command; |
1072 | |
1073 | public CommandMenuItem(String commandName, EditorCommand command) { |
1074 | super(commandName); |
1075 | this.command = command; |
1076 | } |
1077 | |
1078 | public EditorCommand getCommand() { |
1079 | return command; |
1080 | } |
1081 | } |
1082 | |
1083 | sclass JSConsole extends JPanel { |
1084 | |
1085 | private static final String NEW_LINE = "\n"; |
1086 | private static final String QUERY_LINE_START = ">> "; |
1087 | private final Browser browser; |
1088 | private final ExecutorService executor; |
1089 | private JTextArea console; |
1090 | |
1091 | public JSConsole(Browser browser) { |
1092 | this.browser = browser; |
1093 | this.executor = Executors.newCachedThreadPool(); |
1094 | setLayout(new BorderLayout()); |
1095 | add(createTitle(), BorderLayout.NORTH); |
1096 | add(createConsoleOutput(), BorderLayout.CENTER); |
1097 | add(createConsoleInput(), BorderLayout.SOUTH); |
1098 | } |
1099 | |
1100 | private static JComponent createTitleLabel() { |
1101 | return new JLabel("JavaScript Console"); |
1102 | } |
1103 | |
1104 | private JComponent createConsoleInput() { |
1105 | JPanel result = new JPanel(new BorderLayout()); |
1106 | result.setBackground(Color.WHITE); |
1107 | |
1108 | JLabel label = new JLabel(QUERY_LINE_START); |
1109 | label.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 0)); |
1110 | |
1111 | final JTextField consoleInput = new JTextField(); |
1112 | consoleInput.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4)); |
1113 | consoleInput.addActionListener(new ActionListener() { |
1114 | public void actionPerformed(ActionEvent e) { |
1115 | executor.submit(new Runnable() { |
1116 | public void run() { |
1117 | final String script = consoleInput.getText(); |
1118 | JSValue jsValue = browser.executeJavaScriptAndReturnValue(script); |
1119 | final String executionResult = jsValue.toString(); |
1120 | SwingUtilities.invokeLater(new Runnable() { |
1121 | public void run() { |
1122 | updateConsoleOutput(script, executionResult); |
1123 | consoleInput.setText(""); |
1124 | } |
1125 | }); |
1126 | } |
1127 | }); |
1128 | } |
1129 | }); |
1130 | result.add(label, BorderLayout.WEST); |
1131 | result.add(consoleInput, BorderLayout.CENTER); |
1132 | return result; |
1133 | } |
1134 | |
1135 | private JComponent createConsoleOutput() { |
1136 | console = new JTextArea(); |
1137 | console.setFont(new Font("Consolas", Font.PLAIN, 12)); |
1138 | console.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); |
1139 | console.setEditable(false); |
1140 | console.setWrapStyleWord(true); |
1141 | console.setLineWrap(true); |
1142 | console.setText(""); |
1143 | JScrollPane scrollPane = new JScrollPane(console); |
1144 | scrollPane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.GRAY)); |
1145 | return scrollPane; |
1146 | } |
1147 | |
1148 | private JComponent createTitle() { |
1149 | JPanel panel = new JPanel(new BorderLayout()); |
1150 | // panel.setBackground(new Color(182, 191, 207)); |
1151 | panel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); |
1152 | panel.add(createTitleLabel(), BorderLayout.WEST); |
1153 | panel.add(createCloseButton(), BorderLayout.EAST); |
1154 | return panel; |
1155 | } |
1156 | |
1157 | private JComponent createCloseButton() { |
1158 | JButton closeButton = new JButton(); |
1159 | closeButton.setOpaque(false); |
1160 | closeButton.setToolTipText("Close JavaScript Console"); |
1161 | closeButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); |
1162 | closeButton.setPressedIcon(Resources.getIcon("close-pressed.png")); |
1163 | closeButton.setIcon(Resources.getIcon("close.png")); |
1164 | closeButton.setContentAreaFilled(false); |
1165 | closeButton.setFocusable(false); |
1166 | closeButton.addActionListener(new ActionListener() { |
1167 | public void actionPerformed(ActionEvent e) { |
1168 | firePropertyChange("JSConsoleClosed", false, true); |
1169 | } |
1170 | }); |
1171 | return closeButton; |
1172 | } |
1173 | |
1174 | private void updateConsoleOutput(String script, String executionResult) { |
1175 | displayScript(script); |
1176 | displayExecutionResult(executionResult); |
1177 | console.setCaretPosition(console.getText().length()); |
1178 | } |
1179 | |
1180 | private void displayExecutionResult(String result) { |
1181 | console.append(result); |
1182 | console.append(NEW_LINE); |
1183 | } |
1184 | |
1185 | private void displayScript(String script) { |
1186 | console.append(QUERY_LINE_START); |
1187 | console.append(script); |
1188 | console.append(NEW_LINE); |
1189 | } |
1190 | } |
download show line numbers debug dex old transpilations
Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1016163 |
Snippet name: | Tabbed JxBrowser [Include] |
Eternal ID of this version: | #1016163/12 |
Text MD5: | f0be8ae90b5a7abad9e31b90981d48b0 |
Author: | stefan |
Category: | javax / gui |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2018-07-05 11:14:13 |
Source code size: | 44312 bytes / 1190 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 426 / 767 |
Version history: | 11 change(s) |
Referenced in: | [show references] |