1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  *   Licensed to the Apache Software Foundation (ASF) under one or more
11  *   contributor license agreements. See the NOTICE file distributed
12  *   with this work for additional information regarding copyright
13  *   ownership. The ASF licenses this file to you under the Apache
14  *   License, Version 2.0 (the "License"); you may not use this file
15  *   except in compliance with the License. You may obtain a copy of
16  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 
19 package org.libreoffice.example.java_scripts;
20 
21 import javax.swing.*;
22 import javax.swing.tree.*;
23 import javax.swing.table.*;
24 import javax.swing.event.*;
25 import javax.swing.border.*;
26 import java.awt.*;
27 import java.awt.event.*;
28 import java.util.*;
29 import java.beans.*;
30 
31 import com.sun.star.uno.UnoRuntime;
32 import com.sun.star.uno.Exception;
33 import com.sun.star.uno.Any;
34 import com.sun.star.uno.AnyConverter;
35 import com.sun.star.uno.Type;
36 import com.sun.star.uno.XComponentContext;
37 
38 import com.sun.star.lang.XMultiComponentFactory;
39 import com.sun.star.lang.XComponent;
40 import com.sun.star.frame.XModel;
41 import com.sun.star.frame.FrameSearchFlag;
42 import com.sun.star.frame.XDispatchProvider;
43 import com.sun.star.frame.XDispatchHelper;
44 import com.sun.star.frame.XDispatch;
45 import com.sun.star.util.XURLTransformer;
46 import com.sun.star.beans.*;
47 import com.sun.star.script.XInvocation;
48 
49 import com.sun.star.lib.uno.helper.PropertySet;
50 
51 import com.sun.star.script.browse.XBrowseNode;
52 import com.sun.star.script.browse.BrowseNodeTypes;
53 import com.sun.star.script.browse.XBrowseNodeFactory;
54 import com.sun.star.script.browse.BrowseNodeFactoryViewTypes;
55 import com.sun.star.script.provider.XScriptContext;
56 import com.sun.star.script.provider.XScript;
57 import com.sun.star.script.provider.XScriptProvider;
58 
59 public class ScriptSelector {
60 
61     private static final int BIG_GAP = 10;
62     private static final int MED_GAP = 5;
63 
64     private ScriptSelectorPanel selectorPanel;
65 
ScriptSelector()66     public ScriptSelector() {
67     }
68 
showOrganizer(final XScriptContext ctxt)69     public void showOrganizer(final XScriptContext ctxt) {
70         try {
71             XBrowseNode root = getRootNode(ctxt);
72 
73             final XScriptProvider msp =
74                 (XScriptProvider)UnoRuntime.queryInterface(
75                     XScriptProvider.class, root);
76 
77             final JFrame client = new JFrame("Script");
78 
79             selectorPanel = new ScriptSelectorPanel(root);
80 
81             final JButton runButton, closeButton, createButton,
82                   editButton, deleteButton;
83 
84             runButton = new JButton("Run");
85             runButton.setEnabled(false);
86 
87             closeButton = new JButton("Close");
88 
89             editButton = new JButton("Edit");
90             editButton.setEnabled(false);
91 
92             JPanel northButtons =
93                 new JPanel(new GridLayout(2, 1, MED_GAP, MED_GAP));
94 
95             northButtons.add(runButton);
96             northButtons.add(closeButton);
97 
98             createButton = new JButton("Create");
99             createButton.setEnabled(false);
100 
101             deleteButton = new JButton("Delete");
102             deleteButton.setEnabled(false);
103 
104             JPanel southButtons =
105                 new JPanel(new GridLayout(3, 1, MED_GAP, MED_GAP));
106 
107             southButtons.add(editButton);
108             southButtons.add(createButton);
109             southButtons.add(deleteButton);
110 
111             selectorPanel.tree.addTreeSelectionListener(
112             new TreeSelectionListener() {
113                 public void valueChanged(TreeSelectionEvent e) {
114                     XBrowseNode xbn = selectorPanel.getSelection();
115                     XPropertySet props = (XPropertySet)
116                                          UnoRuntime.queryInterface(XPropertySet.class, xbn);
117 
118                     checkEnabled(props, "Creatable", createButton);
119                     checkEnabled(props, "Deletable", deleteButton);
120                     checkEnabled(props, "Editable", editButton);
121 
122                     if (xbn != null &&
123                         xbn.getType() == BrowseNodeTypes.SCRIPT) {
124                         runButton.setEnabled(true);
125                     } else {
126                         runButton.setEnabled(false);
127                     }
128                 }
129             }
130             );
131 
132             ActionListener listener = new ActionListener() {
133                 public void actionPerformed(ActionEvent event) {
134                     if (event.getSource() == runButton) {
135                         String uri = selectorPanel.textField.getText();
136 
137                         try {
138                             XScript script = msp.getScript(uri);
139 
140                             Object[][] out = new Object[1][0];
141                             out[0] = new Object[0];
142 
143                             short[][] num = new short[1][0];
144                             num[0] = new short[0];
145 
146                             script.invoke(new Object[0], num, out);
147                         } catch (Exception e) {
148                             e.printStackTrace();
149                         }
150                     } else if (event.getSource() == closeButton) {
151                         client.dispose();
152                     } else if (event.getSource() == editButton) {
153                         DefaultMutableTreeNode node =
154                             (DefaultMutableTreeNode)
155                             selectorPanel.tree.getLastSelectedPathComponent();
156 
157                         if (node == null) return;
158 
159                         showEditor(ctxt, node);
160                     } else if (event.getSource() == createButton) {
161                         DefaultMutableTreeNode node =
162                             (DefaultMutableTreeNode)
163                             selectorPanel.tree.getLastSelectedPathComponent();
164 
165                         if (node == null) return;
166 
167                         doCreate(ctxt, node);
168                     } else if (event.getSource() == deleteButton) {
169                         DefaultMutableTreeNode node =
170                             (DefaultMutableTreeNode)
171                             selectorPanel.tree.getLastSelectedPathComponent();
172 
173                         if (node == null) return;
174 
175                         doDelete(ctxt, node);
176                     }
177                 }
178             };
179 
180             runButton.addActionListener(listener);
181             closeButton.addActionListener(listener);
182             createButton.addActionListener(listener);
183             editButton.addActionListener(listener);
184             deleteButton.addActionListener(listener);
185 
186             JPanel buttonPanel = new JPanel(new BorderLayout());
187             buttonPanel.add(northButtons, BorderLayout.NORTH);
188             buttonPanel.add(southButtons, BorderLayout.SOUTH);
189 
190             JPanel mainPanel = new JPanel(new BorderLayout(MED_GAP, MED_GAP));
191             mainPanel.setBorder(
192                 new EmptyBorder(BIG_GAP, BIG_GAP, BIG_GAP, BIG_GAP));
193             mainPanel.add(selectorPanel, BorderLayout.CENTER);
194             mainPanel.add(buttonPanel, BorderLayout.EAST);
195 
196             client.getContentPane().add(mainPanel);
197             client.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
198             client.setSize(500, 350);
199 
200             // set the x and y locations so that the frame is in the
201             // centre of the screen
202             Dimension d = client.getToolkit().getScreenSize();
203 
204             int x = (int)((d.getWidth() - client.getWidth()) / 2);
205             int y = (int)((d.getHeight() - client.getHeight()) / 2);
206 
207             client.setLocation(x, y);
208 
209             client.show();
210         } catch (com.sun.star.uno.RuntimeException rue) {
211             rue.printStackTrace();
212         } catch (java.lang.Exception e) {
213             e.printStackTrace();
214         }
215     }
216 
showOrganizer(final XScriptContext ctxt, final com.sun.star.awt.MouseEvent e)217     public void showOrganizer(final XScriptContext ctxt,
218                               final com.sun.star.awt.MouseEvent e) {
219         showOrganizer(ctxt);
220     }
221 
showOrganizer(final XScriptContext ctxt, final com.sun.star.awt.ActionEvent e)222     public void showOrganizer(final XScriptContext ctxt,
223                               final com.sun.star.awt.ActionEvent e) {
224         showOrganizer(ctxt);
225     }
226 
doDelete( XScriptContext ctxt, DefaultMutableTreeNode node)227     private void doDelete(
228         XScriptContext ctxt, DefaultMutableTreeNode node) {
229         Object obj = node.getUserObject();
230         XInvocation inv =
231             (XInvocation)UnoRuntime.queryInterface(
232                 XInvocation.class, obj);
233         Object[] args = new Object[] { ctxt };
234 
235         try {
236             Object result = inv.invoke("Deletable", args,
237                                        new short[1][0], new Object[1][0]);
238 
239             if (result != null && AnyConverter.toBoolean(result) == true) {
240                 selectorPanel.removeNode(node);
241             }
242         } catch (Exception e) {
243             e.printStackTrace();
244         }
245     }
246 
doCreate( XScriptContext ctxt, DefaultMutableTreeNode node)247     private void doCreate(
248         XScriptContext ctxt, DefaultMutableTreeNode node) {
249         Object obj = node.getUserObject();
250         XInvocation inv =
251             (XInvocation)UnoRuntime.queryInterface(
252                 XInvocation.class, obj);
253         Object[] args = new Object[] { ctxt };
254 
255         try {
256             Object result = inv.invoke("Creatable", args,
257                                        new short[1][0], new Object[1][0]);
258 
259             if (result != null) {
260                 XBrowseNode xbn = (XBrowseNode)
261                                   AnyConverter.toObject(new Type(XBrowseNode.class), result);
262                 selectorPanel.addNode(node, xbn);
263             }
264         } catch (Exception e) {
265             e.printStackTrace();
266         }
267     }
268 
showEditor( XScriptContext ctxt, DefaultMutableTreeNode node)269     private void showEditor(
270         XScriptContext ctxt, DefaultMutableTreeNode node) {
271         Object obj = node.getUserObject();
272         XInvocation inv =
273             (XInvocation)UnoRuntime.queryInterface(
274                 XInvocation.class, obj);
275         Object[] args = new Object[] { ctxt };
276 
277         try {
278             inv.invoke("Editable", args,
279                        new short[1][0], new Object[1][0]);
280         } catch (Exception e) {
281             e.printStackTrace();
282         }
283     }
284 
checkEnabled(XPropertySet props, String name, JButton button)285     private void checkEnabled(XPropertySet props, String name,
286                               JButton button) {
287         boolean enable = false;
288 
289         try {
290             if (props != null) {
291                 Object o = props.getPropertyValue(name);
292                 enable = AnyConverter.toBoolean(
293                              props.getPropertyValue(name));
294             }
295         } catch (com.sun.star.lang.IllegalArgumentException iae) {
296             // leave enable set to false
297         } catch (com.sun.star.beans.UnknownPropertyException upe) {
298             // leave enable set to false
299         } catch (com.sun.star.lang.WrappedTargetException wte) {
300             // leave enable set to false
301         }
302 
303         button.setEnabled(enable);
304     }
305 
getRootNode(XScriptContext ctxt)306     private XBrowseNode getRootNode(XScriptContext ctxt) {
307 
308         XBrowseNode result = null;
309 
310 
311         XComponentContext xcc = ctxt.getComponentContext();
312         XMultiComponentFactory xmcf = xcc.getServiceManager();
313         XBrowseNodeFactory xBrowseFac = (XBrowseNodeFactory)
314                                         UnoRuntime.queryInterface(XBrowseNodeFactory.class, xcc.getValueByName(
315                                                 "/singletons/com.sun.star.script.browse.theBrowseNodeFactory"));
316 
317 
318         result = (XBrowseNode)UnoRuntime.queryInterface(
319                      XBrowseNode.class, xBrowseFac.createView(
320                          BrowseNodeFactoryViewTypes.MACROORGANIZER));
321         return result;
322     }
323 }
324 
325 class ScriptSelectorPanel extends JPanel {
326 
327     private XBrowseNode myrootnode = null;
328     public JTextField textField;
329     public JTree tree;
330     public DefaultTreeModel treeModel;
331 
ScriptSelectorPanel(XBrowseNode root)332     public ScriptSelectorPanel(XBrowseNode root) {
333         this.myrootnode = root;
334         initUI();
335     }
336 
getSelection()337     public XBrowseNode getSelection() {
338         DefaultMutableTreeNode node = (DefaultMutableTreeNode)
339                                       tree.getLastSelectedPathComponent();
340 
341         if (node == null) {
342             return null;
343         }
344 
345         return (XBrowseNode)node.getUserObject();
346     }
347 
initUI()348     private void initUI() {
349         setLayout(new BorderLayout());
350 
351         DefaultMutableTreeNode top =
352         new DefaultMutableTreeNode(myrootnode) {
353             public String toString() {
354                 return ((XBrowseNode)getUserObject()).getName();
355             }
356         };
357         initNodes(myrootnode, top);
358         treeModel = new DefaultTreeModel(top);
359         tree = new JTree(treeModel);
360 
361         tree.setCellRenderer(new ScriptTreeRenderer());
362 
363         tree.getSelectionModel().setSelectionMode
364         (TreeSelectionModel.SINGLE_TREE_SELECTION);
365 
366         tree.addTreeSelectionListener(new TreeSelectionListener() {
367             public void valueChanged(TreeSelectionEvent e) {
368                 XBrowseNode xbn = getSelection();
369                 XPropertySet props = (XPropertySet)UnoRuntime.queryInterface(
370                                          XPropertySet.class, xbn);
371 
372                 if (xbn == null) {
373                     textField.setText("");
374                     return;
375                 }
376 
377                 String str = xbn.getName();
378 
379                 if (xbn.getType() == BrowseNodeTypes.SCRIPT && props != null) {
380                     try {
381                         str = AnyConverter.toString(
382                                   props.getPropertyValue("URI"));
383                     } catch (Exception ignore) {
384                         // default will be used
385                     }
386                 }
387 
388                 textField.setText(str);
389             }
390         });
391 
392         JScrollPane scroller = new JScrollPane(tree);
393         add(scroller, BorderLayout.CENTER);
394 
395         textField = new JTextField();
396         add(textField, BorderLayout.SOUTH);
397     }
398 
removeNode(DefaultMutableTreeNode node)399     public void removeNode(DefaultMutableTreeNode node) {
400         MutableTreeNode parent = (MutableTreeNode)(node.getParent());
401 
402         if (parent != null) {
403             treeModel.removeNodeFromParent(node);
404         }
405     }
406 
addNode(DefaultMutableTreeNode parent, XBrowseNode xbn)407     public void addNode(DefaultMutableTreeNode parent, XBrowseNode xbn) {
408         DefaultMutableTreeNode newNode =
409         new DefaultMutableTreeNode(xbn) {
410             public String toString() {
411                 return ((XBrowseNode)getUserObject()).getName();
412             }
413         };
414 
415         treeModel.insertNodeInto(newNode, parent, parent.getChildCount());
416         tree.scrollPathToVisible(new TreePath(newNode.getPath()));
417     }
418 
initNodes(XBrowseNode parent, DefaultMutableTreeNode top)419     private void initNodes(XBrowseNode parent, DefaultMutableTreeNode top) {
420         if (parent == null || parent.hasChildNodes() == false) {
421             return;
422         }
423 
424         XBrowseNode[] children = parent.getChildNodes();
425 
426         try {
427             if (children != null) {
428                 for (int i = 0; i < children.length; i++) {
429                     if (children[i] == null) {
430                         continue;
431                     }
432 
433                     DefaultMutableTreeNode newNode =
434                     new DefaultMutableTreeNode(children[i]) {
435                         public String toString() {
436                             return ((XBrowseNode)getUserObject()).getName();
437                         }
438                     };
439                     top.add(newNode);
440                     initNodes(children[i], newNode);
441                 }
442             }
443         } catch (java.lang.Exception e) {
444             e.printStackTrace();
445         }
446     }
447 }
448 
449 class ScriptTreeRenderer extends DefaultTreeCellRenderer {
450 
451     private ImageIcon sofficeIcon;
452     private ImageIcon scriptIcon;
453     private ImageIcon containerIcon;
454 
ScriptTreeRenderer()455     public ScriptTreeRenderer() {
456         sofficeIcon = new ImageIcon(getClass().getResource("soffice.gif"));
457         scriptIcon = new ImageIcon(getClass().getResource("script.gif"));
458         containerIcon = new ImageIcon(getClass().getResource("container.gif"));
459     }
460 
getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)461     public Component getTreeCellRendererComponent(
462         JTree tree,
463         Object value,
464         boolean sel,
465         boolean expanded,
466         boolean leaf,
467         int row,
468         boolean hasFocus) {
469 
470         super.getTreeCellRendererComponent(
471             tree, value, sel,
472             expanded, leaf, row,
473             hasFocus);
474 
475         DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
476         XBrowseNode xbn = (XBrowseNode)node.getUserObject();
477 
478         if (xbn.getType() == BrowseNodeTypes.SCRIPT) {
479             setIcon(scriptIcon);
480         } else if (xbn.getType() == BrowseNodeTypes.CONTAINER) {
481             setIcon(containerIcon);
482         } else if (xbn.getType() == BrowseNodeTypes.ROOT) {
483             setIcon(sofficeIcon);
484         }
485 
486         return this;
487     }
488 }
489