Revision 1243

View differences:

org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/test/resources/log4j.xml
1
<?xml version="1.0" encoding="UTF-8" ?>
2
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
3

  
4
<!-- 
5
Log4J configuration file for unit tests execution.
6
 -->
7
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
8

  
9
	<!-- Appender configuration to show logging messages through the console -->
10
	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
11
		<layout class="org.apache.log4j.PatternLayout">
12
			<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c{2}.%M()]\n  %m%n" />
13
		</layout>
14
	</appender>
15

  
16
	<!-- 
17
	Activate logging messages of DEBUG level of higher only for the
18
	DefaultExampleManager class.
19
	You can put full classes names or packages instead, to configure
20
	logging for all the classes and subpackages of the package.
21
	-->
22
	<category name="org.gvsig.scripting.impl.DefaultExampleManager">
23
		<priority value="DEBUG" />
24
	</category>
25

  
26
	<!-- 
27
	By default, show only logging messages of INFO level or higher, 
28
	through the previously configured CONSOLE appender. 
29
	-->
30
	<root>
31
		<priority value="INFO" />
32
		<appender-ref ref="CONSOLE" />
33
	</root>
34
</log4j:configuration>
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/test/resources/README.txt
1
#set( $symbol_pound = '#' )
2
#set( $symbol_dollar = '$' )
3
#set( $symbol_escape = '\' )
4
Put into this folder the resources needed by your test classes.
5

  
6
This folder is added to the Tests classpath, so you can load any resources 
7
through the ClassLoader.
8

  
9
By default, in this folder you can find an example of log4j configuration,
10
prepared to log messages through the console, so logging works when you
11
run your tests classes.
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/test/java/README.txt
1
#set( $symbol_pound = '#' )
2
#set( $symbol_dollar = '$' )
3
#set( $symbol_escape = '\' )
4
For each class you are going to test, create one Test class with the same
5
name as the class to test, ending with Test.
6

  
7
For example, the unit tests of the "ExampleLibrary" class are performed
8
by the "ExampleLibraryTest" class.
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/main/java/thinletcommons/ThinletTester.java
1
// jEdit settings:
2
// :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1:
3

  
4
package thinletcommons;
5

  
6

  
7
import java.io.BufferedInputStream;
8
import java.io.FileInputStream;
9
import java.io.InputStream;
10
import java.lang.reflect.InvocationTargetException;
11
import java.lang.reflect.Method;
12

  
13
import thinlet.FrameLauncher;
14
import thinlet.Thinlet;
15

  
16

  
17
public class ThinletTester
18
{
19

  
20
    private static String file = null;
21
    private static String thinletClassname = "thinlet.Thinlet";
22
    private static String handlerClassname = null;
23

  
24

  
25
    public static void main(String[] args) throws Throwable
26
    {
27
        getArgs(args);
28
        run();
29
    }
30

  
31

  
32
    private static void getArgs(String[] args)
33
    {
34
        if(args.length < 1 || args.length > 5)
35
            usage();
36

  
37
        for(int i = 0; i < args.length; ++i)
38
        {
39
            if(args[i].equals("--help"))
40
                usage();
41
            else if(args[i].equals("--thinlet"))
42
            {
43
                if(i == args.length - 1)
44
                    usage();
45
                else
46
                    thinletClassname = args[++i];
47
            }
48
            else if(args[i].equals("--handler"))
49
            {
50
                if(i == args.length - 1)
51
                    usage();
52
                else
53
                    handlerClassname = args[++i];
54
            }
55
            else if(file == null)
56
                file = args[i];
57
            else
58
                usage();
59
        }
60

  
61
        if(file == null)
62
            usage();
63
    }
64

  
65

  
66
    private static void usage()
67
    {
68
        System.out.println("ThinletTester, version 1.0");
69
        System.out.println();
70
        System.out.println("Usage: java [-cp <classpath>] thinletcommons.ThinletTester [--thinlet <classname>]");
71
        System.out.println("         [--handler <classname>] thinletfile.xml");
72
        System.out.println();
73
        System.out.println("  --thinlet  Thinlet classname, e.g. thinlet.Thinlet");
74
        System.out.println("  --handler  Handler classname, e.g. foo.bar.MyHandler");
75
        System.out.println();
76
        System.out.println("  The classpath must include both the Thinlet class and the handler class (if");
77
        System.out.println("  given on the commandline) as well as thinlet.jar.");
78
        System.out.println("  The specified Thinlet class and Handler class must have a default");
79
        System.out.println("  constructor.");
80
        System.out.println();
81
        System.exit(1);
82
    }
83

  
84

  
85
    private static void run() throws Throwable
86
    {
87
        // create Thinlet instance
88
        Class thinletClass = Class.forName(thinletClassname);
89
        Object thinlet = thinletClass.newInstance();
90

  
91
        if(!Thinlet.class.isInstance(thinlet))
92
        {
93
            System.err.println("error: " + thinletClassname + " is not a Thinlet class.");
94
            System.exit(2);
95
        }
96

  
97
        System.out.println("using thinlet class: " + thinletClass.getName());
98

  
99
        // create Handler instance
100
        Object handler = thinlet;
101
        if(handlerClassname != null)
102
        {
103
            Class handlerClass = Class.forName(handlerClassname);
104
            handler = handlerClass.newInstance();
105
            System.out.println("using handler class: " + handlerClass.getName());
106
        }
107

  
108
        InputStream is = getInputStream(file);
109
        System.out.println("parsing file " + file + " ...");
110

  
111
        // "Object result = thinlet.parse(is, handler);"
112
        Method parseMethod = thinletClass.getMethod("parse", new Class[] { InputStream.class, Object.class });
113
        Object result;
114
        try
115
        {
116
            result = parseMethod.invoke(thinlet, new Object[] { is, handler });
117
        }
118
        catch(InvocationTargetException e)
119
        {
120
            throw e.getTargetException();
121
        }
122

  
123
        // "thinlet.add(result);"
124
        Method addMethod = thinletClass.getMethod("add", new Class[] { Object.class });
125
        try
126
        {
127
            addMethod.invoke(thinlet, new Object[] { result });
128
        }
129
        catch(InvocationTargetException e)
130
        {
131
            throw e.getTargetException();
132
        }
133

  
134
        System.out.println("showing frame...");
135

  
136
        /*FrameLauncher frame = new FrameLauncher("ThinletTester", null, (Thinlet)thinlet, 400, 400, false);
137
        frame.pack();
138
        frame.setVisible(true);
139
*/
140
        System.out.println("done.");
141
    }
142

  
143

  
144
    private static InputStream getInputStream(String filename) throws Exception
145
    {
146
        return new BufferedInputStream(new FileInputStream(filename));
147
    }
148

  
149
}
150

  
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/main/java/thinletcommons/DirChooser.java
1
// jEdit settings:
2
// :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1:
3

  
4
package thinletcommons;
5

  
6

  
7
import java.awt.Dialog;
8
import java.awt.Frame;
9
import java.awt.Image;
10
import java.awt.image.BufferedImage;
11
import java.io.File;
12
import java.text.Collator;
13
import java.util.Arrays;
14
import java.util.Comparator;
15
import java.util.Stack;
16
import java.util.logging.Level;
17
import java.util.logging.Logger;
18

  
19
import javax.swing.Icon;
20
import javax.swing.ImageIcon;
21
import javax.swing.filechooser.FileSystemView;
22

  
23
import thinlet.Thinlet;
24

  
25

  
26
/**
27
 * A Thinlet directory chooser dialog.
28
 *
29
 * <p>
30
 * The dialog is modal and blocks the calling frame/dialog. It is therefore
31
 * displayed in a separate window.
32
 *
33
 * <p>
34
 * <b>TODO:</b>
35
 * <ul>
36
 *   <li>Button "Create directory"</li>
37
 * </ul>
38
 *
39
 * <p>
40
 * <b>Implementation note:</b> This implementation uses
41
 * <code>javax.swing.filechooser.FileSystemView</code>, because it provides
42
 * directory information that looks more "native". This introduces a dependency
43
 * on Swing, but since ThinG requires JDK 1.4, Swing should be there anyway.
44
 * Only a minimal set of Swing classes is loaded while using
45
 * <code>javax.swing.filechooser.FileSystemView</code>; alas, the loading
46
 * of <code>javax.swing.UIManager</code> and <code>javax.swing.LookAndFeel</code>
47
 * can <i>not</i> be avoided, although no Swing beans are actually used.
48
 *
49
 * @author Dirk Moebius
50
 */
51
public class DirChooser
52
{
53
    //{{{ logging
54
    private static final Logger log = Logger.getLogger("thinletcommons");
55
    private static final boolean debug() { return log.isLoggable(Level.FINE); }
56
    //}}}
57

  
58

  
59
    private ThinletDialog dialog;
60
    private Thinlet thinlet;
61
    private File selectedDir;
62
    private File expandDir;
63
    private boolean isInitialized = false;
64
    private FileSystemView fsv = FileSystemView.getFileSystemView();
65

  
66

  
67
    public DirChooser(Frame owner, String title)
68
    {
69
        this.dialog = new ThinletDialog(owner, title);
70
        init();
71
    }
72

  
73

  
74
    public DirChooser(Dialog owner, String title)
75
    {
76
        this.dialog = new ThinletDialog(owner, title);
77
        init();
78
    }
79

  
80

  
81
    private void init()
82
    {
83
        thinlet = new AntiAliasedThinlet();
84

  
85
        try
86
        {
87
            Object panel = thinlet.parse("/thinletcommons/dirchooser.xml", this);
88
            thinlet.add(panel);
89
        }
90
        catch(Exception e)
91
        {
92
            log.log(Level.SEVERE, "Error parsing dirchooser.xml", e);
93
        }
94

  
95
        dialog.setContent(thinlet);
96
    }
97

  
98

  
99
    /**
100
     * Show the modal dialog.
101
     * This halts the application until the user dismisses the dialog.
102
     */
103
    public void show()
104
    {
105
        selectedDir = null;
106
        if(expandDir != null)
107
        {
108
            expandTreeTo(expandDir);
109
            expandDir = null;
110
        }
111
        dialog.pack();
112
        dialog.setLocationRelativeTo(dialog.getOwner());
113
        dialog.setVisible(true);
114
    }
115

  
116

  
117
    public void setSelectedDirectory(File dir)
118
    {
119
        this.expandDir = dir;
120
    }
121

  
122

  
123
    public File getSelectedDirectory()
124
    {
125
        return selectedDir;
126
    }
127

  
128

  
129
    //{{{ callbacks for dirchooser.xml
130
    /** Thinlet callback. */
131
    public void init(Object tree)
132
    {
133
        if(debug()) log.fine("in init()");
134
        if(!isInitialized)
135
        {
136
            addFiles(fsv.getRoots(), tree);
137
            isInitialized = true;
138
        }
139
    }
140

  
141

  
142
    /** Thinlet callback. */
143
    public void ok(Object tree)
144
    {
145
        Object node = thinlet.getSelectedItem(tree);
146
        if(node != null)
147
            selectedDir = (File) thinlet.getProperty(node, "file");
148
        close();
149
    }
150

  
151

  
152
    /** Thinlet callback. */
153
    public void close()
154
    {
155
        dialog.setVisible(false);
156
    }
157

  
158

  
159
    /** Thinlet callback. */
160
    public void nodeExpanded(Object tree, Object node)
161
    {
162
        File file = (File) thinlet.getProperty(node, "file");
163
        // remove all existing nodes below the selected node (including
164
        // dummy placeholder nodes)
165
        thinlet.removeAll(node);
166
        // re-add subdirectory nodes below current node
167
        File[] files = fsv.getFiles(file, false);
168
        addFiles(files, node);
169
    }
170
    //}}}
171

  
172

  
173
    //{{{ private methods
174
    private void addFiles(File[] files, Object parent)
175
    {
176
        sort(files);
177

  
178
        for(int i = 0; i < files.length; ++i)
179
        {
180
            File file = files[i];
181
            if(fsv.isTraversable(file).booleanValue())
182
            {
183
                // it's  directory; create a node for it
184
                Object node = createNode(file);
185
                thinlet.setBoolean(node, "expanded", false);
186
                thinlet.add(parent, node);
187

  
188
                // create a placeholder node for the (possible) children of
189
                // the directory
190
                Object placeholder = Thinlet.create("node");
191
                thinlet.setBoolean(placeholder, "expanded", false);
192
                thinlet.setString(placeholder, "text", "#Placeholder#");
193
                thinlet.add(node, placeholder);
194
                //thinlet.putProperty(node, "hasDummyChild", Boolean.TRUE);
195
            }
196
        }
197
    }
198

  
199

  
200
    private Object createNode(File file)
201
    {
202
        Object node = Thinlet.create("node");
203
        thinlet.setString(node, "text", fsv.getSystemDisplayName(file));
204

  
205
        Icon icon = fsv.getSystemIcon(file);
206
        if(icon != null)
207
            thinlet.setIcon(node, "icon", convertIconToImage(thinlet, icon));
208

  
209
        thinlet.putProperty(node, "file", file);
210
        return node;
211
    }
212

  
213

  
214
    private void sort(File[] files)
215
    {
216
        if(files.length == 0)
217
            return;
218

  
219
        // don't sort if first file is a special (non-disc) file
220
        File firstFile = files[0];
221
        if(fsv.isComputerNode(firstFile) || fsv.isDrive(firstFile)
222
            || fsv.isFileSystemRoot(firstFile) || fsv.isFloppyDrive(firstFile)
223
            || fsv.isRoot(firstFile))
224
            return;
225

  
226
        Arrays.sort(files, new Comparator()
227
        {
228
            private  Collator collator = Collator.getInstance();
229

  
230
            public int compare(Object obj1, Object obj2)
231
            {
232
                return collator.compare(
233
                    fsv.getSystemDisplayName((File)obj1),
234
                    fsv.getSystemDisplayName((File)obj2)
235
                );
236
            }
237

  
238
            public boolean equals(Object other)
239
            {
240
                // unused
241
                return false;
242
            }
243
        });
244
    }
245

  
246

  
247
    private void expandTreeTo(File file)
248
    {
249
        Stack stack = new Stack();
250
        stack.push(file);
251
        File root = null;
252
        File parent = file;
253

  
254
        // find root, fill stack
255
        do
256
        {
257
            parent = fsv.getParentDirectory(parent);
258
            if(parent != null)
259
            {
260
                stack.push(parent);
261
                root = parent;
262
            }
263
        } while(parent != null);
264

  
265
        if(root == null)
266
        {
267
            log.warning("cannot expand to directory '" + file + "' because parent not found!");
268
            return;
269
        }
270

  
271
        Object tree = thinlet.find("tree");
272
        _expandTreeTo(tree, stack);
273
    }
274

  
275

  
276
    private void _expandTreeTo(Object node, Stack stack)
277
    {
278
        File currentDir = (File) stack.pop();
279
        Object[] nodes = thinlet.getItems(node);
280
        boolean found = false;
281

  
282
        for(int i = 0; i < nodes.length; ++i)
283
        {
284
            Object subnode = nodes[i];
285

  
286
            File file = (File) thinlet.getProperty(subnode, "file");
287
            if(!found && file.equals(currentDir))
288
            {
289
                thinlet.removeAll(subnode);
290
                File[] subfiles = fsv.getFiles(file, false);
291
                addFiles(subfiles, subnode);
292
                if(stack.empty())
293
                    thinlet.setBoolean(subnode, "selected", true);
294
                else
295
                {
296
                    thinlet.setBoolean(subnode, "expanded", true);
297
                    _expandTreeTo(subnode, stack);
298
                    found = true;
299
                }
300
            }
301
        }
302
    }
303

  
304

  
305
    private static Image convertIconToImage(Thinlet thinlet, Icon icon)
306
    {
307
        BufferedImage image = new BufferedImage(icon.getIconWidth(),
308
            icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
309
        icon.paintIcon(thinlet, image.getGraphics(), 0, 0);
310
        return image;
311
    }
312
    //}}}
313

  
314
}
315

  
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/main/java/thinletcommons/ColorChooser.java
1
// jEdit settings:
2
// :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1:
3

  
4
package thinletcommons;
5

  
6

  
7
import java.awt.Color;
8
import java.awt.Dialog;
9
import java.awt.Frame;
10
import java.util.logging.Level;
11
import java.util.logging.Logger;
12

  
13
import thinlet.Thinlet;
14

  
15

  
16
/**
17
 * A Thinlet color chooser dialog.
18
 *
19
 * <p>
20
 * The dialog is modal and blocks the calling frame/dialog. It is therefore
21
 * displayed in a separate window.
22
 *
23
 * @author Dirk Moebius
24
 */
25
public class ColorChooser
26
{
27
    //{{{ logging
28
    private static final Logger log = Logger.getLogger("thinletcommons");
29
    private static final boolean debug() { return log.isLoggable(Level.FINE); }
30
    //}}}
31

  
32

  
33
    private ThinletDialog dialog;
34
    private Thinlet thinlet;
35
    private Color selectedColor;
36

  
37
    // components
38
    private Object sl_red, sl_green, sl_blue;
39
    private Object sb_red, sb_green, sb_blue;
40
    private Object tf_hue, tf_saturation, tf_brightness;
41
    private Object pb_hue, pb_saturation, pb_brightness;
42
    private Object rgb_label;
43

  
44

  
45
    public ColorChooser(Frame owner, String title)
46
    {
47
        this.dialog = new ThinletDialog(owner, title);
48
        init();
49
    }
50

  
51

  
52
    public ColorChooser(Dialog owner, String title)
53
    {
54
        this.dialog = new ThinletDialog(owner, title);
55
        init();
56
    }
57

  
58

  
59
    private void init()
60
    {
61
        thinlet = new AntiAliasedThinlet();
62

  
63
        try
64
        {
65
            Object panel = thinlet.parse("/thinletcommons/colorchooser.xml", this);
66
            thinlet.add(panel);
67
        }
68
        catch(Exception e)
69
        {
70
            log.log(Level.SEVERE, "Error parsing colorchooser.xml", e);
71
        }
72

  
73
        dialog.setContent(thinlet);
74
    }
75

  
76

  
77
    /**
78
     * Show the modal dialog.
79
     * This halts the application until the user dismisses the dialog.
80
     */
81
    public void show()
82
    {
83
        if(debug()) log.fine("in show");
84
        dialog.pack();
85
        dialog.setResizable(false);
86
        dialog.setLocationRelativeTo(dialog.getOwner());
87
        dialog.setVisible(true);
88
    }
89

  
90

  
91
    public void setSelectedColor(Color color)
92
    {
93
        int red = 0, green = 0, blue = 0;
94
        if(color != null)
95
        {
96
            red = color.getRed();
97
            green = color.getGreen();
98
            blue = color.getBlue();
99
            thinlet.setInteger(sl_red, "value", red);
100
            thinlet.setInteger(sl_green, "value", green);
101
            thinlet.setInteger(sl_blue, "value", blue);
102
            thinlet.setString(sb_red, "text", String.valueOf(red));
103
            thinlet.setString(sb_green, "text", String.valueOf(green));
104
            thinlet.setString(sb_blue, "text", String.valueOf(blue));
105
            hsbChanged();
106
        }
107
    }
108

  
109

  
110
    public Color getSelectedColor()
111
    {
112
        return selectedColor;
113
    }
114

  
115

  
116
    //{{{ callbacks for colorchooser.xml
117
    /** Thinlet callback. */
118
    public void init(Object sl_red, Object sl_green, Object sl_blue,
119
        Object sb_red, Object sb_green, Object sb_blue,
120
        Object tf_hue, Object tf_saturation, Object tf_brightness,
121
        Object pb_hue, Object pb_saturation, Object pb_brightness,
122
        Object rgb_label)
123
    {
124
        if(debug()) log.fine("in init");
125
        this.sl_red = sl_red;
126
        this.sl_green = sl_green;
127
        this.sl_blue = sl_blue;
128
        this.sb_red = sb_red;
129
        this.sb_green = sb_green;
130
        this.sb_blue = sb_blue;
131
        this.tf_hue = tf_hue;
132
        this.tf_saturation = tf_saturation;
133
        this.tf_brightness = tf_brightness;
134
        this.pb_hue = pb_hue;
135
        this.pb_saturation = pb_saturation;
136
        this.pb_brightness = pb_brightness;
137
        this.rgb_label = rgb_label;
138
    }
139

  
140

  
141
    /** Thinlet callback. */
142
    public void sliderChanged(int value, Object spinbox)
143
    {
144
        thinlet.setString(spinbox, "text", String.valueOf(value));
145
        hsbChanged();
146
    }
147

  
148

  
149
    /** Thinlet callback. */
150
    public void spinboxChanged(String text, Object slider)
151
    {
152
        try
153
        {
154
            int value = Integer.parseInt(text);
155
            if(value >= 0 && value <= 255)
156
            {
157
                thinlet.setInteger(slider, "value", value);
158
                hsbChanged();
159
            }
160
        }
161
        catch (NumberFormatException ignore)
162
        {
163
        }
164
    }
165

  
166

  
167
    /** Thinlet callback. */
168
    public void ok()
169
    {
170
        int red = thinlet.getInteger(sl_red, "value");
171
        int green = thinlet.getInteger(sl_green, "value");
172
        int blue = thinlet.getInteger(sl_blue, "value");
173
        this.selectedColor = new Color(red, green, blue);
174
        dialog.setVisible(false);
175
    }
176

  
177

  
178
    /** Thinlet callback. */
179
    public void close()
180
    {
181
        dialog.setVisible(false);
182
    }
183
    //}}}
184

  
185

  
186
    //{{{ private methods
187
    private void hsbChanged()
188
    {
189
        int red = thinlet.getInteger(sl_red, "value");
190
        int green = thinlet.getInteger(sl_green, "value");
191
        int blue = thinlet.getInteger(sl_blue, "value");
192

  
193
        float[] hsb = Color.RGBtoHSB(red, green, blue, null);
194

  
195
        thinlet.setColor(rgb_label, "background", new Color(red, green, blue));
196
        thinlet.setString(tf_hue, "text", String.valueOf(hsb[0]));
197
        thinlet.setString(tf_saturation, "text", String.valueOf(hsb[1]));
198
        thinlet.setString(tf_brightness, "text", String.valueOf(hsb[2]));
199

  
200
        thinlet.setInteger(pb_hue, "value", (int) (100f * hsb[0]));
201
        thinlet.setInteger(pb_saturation, "value", (int) (100f * hsb[1]));
202
        thinlet.setInteger(pb_brightness, "value", (int) (100f * hsb[2]));
203
    }
204
    //}}}
205

  
206
}
207

  
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/main/java/thinletcommons/FileChooser.java
1
// jEdit settings:
2
// :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1:
3

  
4
package thinletcommons;
5

  
6

  
7
import java.awt.Dialog;
8
import java.awt.Frame;
9
import java.awt.Image;
10
import java.awt.image.BufferedImage;
11
import java.io.File;
12
import java.text.Collator;
13
import java.text.DateFormat;
14
import java.text.DecimalFormat;
15
import java.util.Arrays;
16
import java.util.Comparator;
17
import java.util.Date;
18
import java.util.logging.Level;
19
import java.util.logging.Logger;
20

  
21
import javax.swing.Icon;
22
import javax.swing.ImageIcon;
23
import javax.swing.filechooser.FileSystemView;
24

  
25
import thinlet.Thinlet;
26

  
27

  
28
/**
29
 * A Thinlet file chooser dialog.
30
 *
31
 * <p>
32
 * The dialog is modal and blocks the calling frame/dialog. It is therefore
33
 * displayed in a separate window.
34
 *
35
 * <p>
36
 * <b>TODO:</b>
37
 * <ul>
38
 *   <li>For mode OPEN: multiple selection</li>
39
 *   <li>Button "Create directory"</li>
40
 * </ul>
41
 *
42
 * <p>
43
 * <b>Implementation note:</b> This implementation uses
44
 * <code>javax.swing.filechooser.FileSystemView</code>, because it provides
45
 * directory information that looks more "native". This introduces a dependency
46
 * on Swing, but since ThinG requires JDK 1.4, Swing should be there anyway.
47
 * Only a minimal set of Swing classes is loaded while using
48
 * <code>javax.swing.filechooser.FileSystemView</code>; alas, the loading
49
 * of <code>javax.swing.UIManager</code> and <code>javax.swing.LookAndFeel</code>
50
 * can <i>not</i> be avoided, although no Swing beans are actually used.
51
 *
52
 * @author Dirk Moebius
53
 */
54
public class FileChooser
55
{
56
    //{{{ logging
57
    private static final Logger log = Logger.getLogger("thinletcommons");
58
    private static final boolean debug() { return log.isLoggable(Level.FINE); }
59
    //}}}
60

  
61

  
62
    public static final int MODE_OPEN = 0;
63
    public static final int MODE_SAVE = 1;
64

  
65
    private static final FileSystemView fsv = FileSystemView.getFileSystemView();
66
    private static final DecimalFormat decimalFormat = new DecimalFormat("#,##0.0");
67
    private static final DecimalFormat integerFormat = new DecimalFormat("###,###,###,###,###,###,###,###,###,###");
68
    private static final DateFormat dateFormat = DateFormat.getInstance();
69

  
70
    private ThinletDialog dialog;
71
    private Thinlet thinlet;
72
    private File selectedFile;
73
    private File showFile;
74
    private File currentDir;
75
    private int mode;
76
    private boolean showHiddenFiles = false;
77
    private int sortColumn = 0;
78
    private boolean sortAscending = true;
79
    private FileFilter[] filters;
80
    private FileFilter selectedFilter;
81

  
82
    // components
83
    private Object cbPath, bUp, bShowHidden, tbFilelist, tFilename, bOk, cbFilter;
84

  
85

  
86
    public FileChooser(Frame owner, String title, int mode)
87
    {
88
        this.dialog = new ThinletDialog(owner, title);
89
        this.mode = mode;
90
        init();
91
    }
92

  
93

  
94
    public FileChooser(Dialog owner, String title, int mode)
95
    {
96
        this.dialog = new ThinletDialog(owner, title);
97
        this.mode = mode;
98
        init();
99
    }
100

  
101

  
102
    private void init()
103
    {
104
        thinlet = new AntiAliasedThinlet();
105

  
106
        try
107
        {
108
            Object panel = thinlet.parse("/thinletcommons/filechooser.xml", this);
109
            thinlet.add(panel);
110
        }
111
        catch(Exception e)
112
        {
113
            log.log(Level.SEVERE, "Error parsing filechooser.xml", e);
114
        }
115

  
116
        tbFilelist = thinlet.find("tbFilelist");
117
        cbPath = thinlet.find("cbPath");
118
        bUp = thinlet.find("bUp");
119
        bShowHidden = thinlet.find("bShowHidden");
120
        bOk = thinlet.find("bOk");
121
        tFilename = thinlet.find("tFilename");
122
        cbFilter = thinlet.find("cbFilter");
123

  
124
        dialog.setContent(thinlet);
125
    }
126

  
127

  
128
    /**
129
     * Show the modal dialog.
130
     * This halts the application until the user dismisses the dialog.
131
     */
132
    public void show()
133
    {
134
        selectedFile = null;
135

  
136
        setupFileFilters();
137

  
138
        if(showFile == null || !showFile.exists())
139
            showFile = fsv.getHomeDirectory();
140
        addFiles(showFile);
141
        showFile = null;
142

  
143
        thinlet.setString(thinlet.find("bOk"), "text", mode == MODE_OPEN ? "Open" : "Save");
144
        thinlet.setBoolean(thinlet.find("bShowHidden"), "selected", showHiddenFiles);
145
        thinlet.requestFocus(thinlet.find("tbFilelist"));
146

  
147
        dialog.pack();
148
        dialog.setLocationRelativeTo(dialog.getOwner());
149
        dialog.setVisible(true);
150
    }
151

  
152

  
153
    public void setSelectedFile(File file)
154
    {
155
        this.showFile = file;
156
    }
157

  
158

  
159
    public File getSelectedFile()
160
    {
161
        return selectedFile;
162
    }
163

  
164

  
165
    public void setShowHiddenFiles(boolean showHiddenFiles)
166
    {
167
        this.showHiddenFiles = showHiddenFiles;
168
    }
169

  
170

  
171
    public boolean getShowHiddenFiles()
172
    {
173
        return showHiddenFiles;
174
    }
175

  
176

  
177
    /**
178
     * Set the list of choosable file filters.
179
     * <p>
180
     * This replaces the default filter "All files", so care must be taken to
181
     * include an all file filter in the list, if you don't want the "All files"
182
     * filter to be removed.
183
     * <p>
184
     * To restore the "All files" filter and remove all custom filter, call
185
     * this method with argument <code>null</code>.
186
     *
187
     * @param filters  the list of choosable file filters, or <code>null</code>.
188
     */
189
    public void setFileFilters(FileFilter[] filters)
190
    {
191
        this.filters = filters;
192
    }
193

  
194

  
195
    public FileFilter getSelectedFileFilter()
196
    {
197
        return selectedFilter;
198
    }
199

  
200

  
201
    //{{{ callbacks for filechooser.xml
202
    /** Thinlet callback. */
203
    public void ok()
204
    {
205
        String filename = thinlet.getString(tFilename, "text");
206
        if(filename == null || filename.trim().length() == 0)
207
            new MessageDialog(dialog, "No selection", "Please select a file.").show();
208
        else
209
        {
210
            File file = new File(currentDir, filename);
211
            if(fsv.isTraversable(file).booleanValue())
212
                addFiles(file);
213
            else
214
            {
215
                selectedFile = file;
216
                close();
217
            }
218
        }
219
    }
220

  
221

  
222
    /** Thinlet callback. */
223
    public void close()
224
    {
225
        dialog.setVisible(false);
226
    }
227

  
228

  
229
    /** Thinlet callback. */
230
    public void goUp()
231
    {
232
        if(currentDir != null)
233
        {
234
            File parent = fsv.getParentDirectory(currentDir);
235
            if(parent != null)
236
                addFiles(parent);
237
        }
238
    }
239

  
240

  
241
    /** Thinlet callback. */
242
    public void goHome()
243
    {
244
        // Workaround: FileSystemView.getHomeDirectory() returns wrong directory
245
        // on Windows; using system property "user.home" instead:
246
        //File home = fsv.getHomeDirectory();
247
        File home = new File(System.getProperty("user.home"));
248
        addFiles(home);
249
    }
250

  
251

  
252
    /** Thinlet callback. */
253
    public void toggleShowHiddenFiles(boolean showHidden)
254
    {
255
        this.showHiddenFiles = showHidden;
256
        addFiles(currentDir);
257
    }
258

  
259

  
260
    /** Thinlet callback. */
261
    public void tableRowDoubleClicked()
262
    {
263
        File file = getSelectedTableRowFile();
264
        if(file != null && fsv.isTraversable(file).booleanValue())
265
            addFiles(file);
266
        else
267
        {
268
            selectedFile = file;
269
            close();
270
        }
271
    }
272

  
273

  
274
    /** Thinlet callback. */
275
    public void tableRowSelected()
276
    {
277
        thinlet.setString(tFilename, "text", getSelectedTableRowFilename());
278
    }
279

  
280

  
281
    /** Thinlet callback. */
282
    public void tableHeaderChanged(Object colName, Object colType, Object colSize, Object colMod)
283
    {
284
        final Object[] column = { colName, colType, colSize, colMod };
285
        for(int i = 0; i < column.length; ++i)
286
        {
287
            String sort = thinlet.getChoice(column[i], "sort");
288
            if(!sort.equals("none"))
289
            {
290
                this.sortColumn = i;
291
                this.sortAscending = sort.equals("ascent");
292
                break;
293
            }
294
        }
295
        addFiles(currentDir);
296
    }
297

  
298

  
299
    /** Thinlet callback. */
300
    public void cbPathChanged()
301
    {
302
        Object item = thinlet.getSelectedItem(cbPath);
303
        if(item != null)
304
        {
305
            File dir = (File) thinlet.getProperty(item, "file");
306
            addFiles(dir);
307
        }
308
    }
309

  
310

  
311
    /** Thinlet callback. */
312
    public void cbFilterChanged(int index)
313
    {
314
        if(filters != null)
315
        {
316
            selectedFilter = filters[index];
317
            addFiles(currentDir);
318
        }
319
    }
320
    //}}}
321

  
322

  
323
    //{{{ private methods
324
    private void addFiles(File file)
325
    {
326
        currentDir = file;
327
        if(fsv.isTraversable(file).booleanValue())
328
            thinlet.setString(tFilename, "text", "");
329
        else
330
        {
331
            thinlet.setString(tFilename, "text", fsv.getSystemDisplayName(file));
332
            currentDir = fsv.getParentDirectory(file);
333
        }
334

  
335
        // fill table
336
        File[] files = fsv.getFiles(currentDir, false);
337
        sort(files, sortColumn, sortAscending);
338
        thinlet.removeAll(tbFilelist);
339
        for(int i = 0; i < files.length; ++i)
340
            if(acceptFile(files[i]))
341
                thinlet.add(tbFilelist, createTableRow(files[i]));
342

  
343
        // fill path combobox
344
        thinlet.removeAll(cbPath);
345
        File dir = currentDir;
346
        while(dir != null)
347
        {
348
            Object item = Thinlet.create("choice");
349
            thinlet.setString(item, "text", fsv.getSystemDisplayName(dir));
350
            thinlet.putProperty(item, "file", dir);
351
            setFileIcon(item, dir);
352
            thinlet.add(cbPath, item, 0);
353
            dir = fsv.getParentDirectory(dir);
354
        }
355
        thinlet.setInteger(cbPath, "selected", thinlet.getCount(cbPath) - 1);
356

  
357
        // configure "Up" button
358
        thinlet.setBoolean(bUp, "enabled", fsv.getParentDirectory(currentDir) != null);
359
    }
360

  
361

  
362
    private boolean acceptFile(File file)
363
    {
364
        // don't show hidden files
365
        if(!showHiddenFiles && fsv.isHiddenFile(file)) return false;
366
        // always show directories
367
        if(fsv.isTraversable(file).booleanValue()) return true;
368
        // "All files" filter accepts all
369
        if(selectedFilter == null) return true;
370
        // Use selected file filter
371
        return selectedFilter.accept(file);
372
    }
373

  
374

  
375
    private void setupFileFilters()
376
    {
377
        thinlet.removeAll(cbFilter);
378
        if(filters == null)
379
        {
380
            addFileFilter("All files (*.*)");
381
            selectedFilter = null;
382
        }
383
        else
384
        {
385
            for(int i = 0; i < filters.length; ++i)
386
                addFileFilter(filters[i].getDescription());
387
            selectedFilter = filters[0];
388
        }
389
        thinlet.setInteger(cbFilter, "selected", 0);
390
    }
391

  
392

  
393
    private void addFileFilter(String description)
394
    {
395
        Object choice = Thinlet.create("choice");
396
        thinlet.setString(choice, "text", description);
397
        thinlet.add(cbFilter, choice);
398
    }
399

  
400

  
401
    private Object createTableRow(File file)
402
    {
403
        Object row = Thinlet.create("row");
404
        Object cellName = Thinlet.create("cell");
405
        Object cellType = Thinlet.create("cell");
406
        Object cellSize = Thinlet.create("cell");
407
        Object cellMod = Thinlet.create("cell");
408
        thinlet.add(row, cellName);
409
        thinlet.add(row, cellType);
410
        thinlet.add(row, cellSize);
411
        thinlet.add(row, cellMod);
412
        thinlet.setString(cellName, "text", fsv.getSystemDisplayName(file));
413
        thinlet.setString(cellType, "text", formatTypeString(file));
414
        thinlet.setString(cellMod, "text", formatDateString(file.lastModified()));
415
        thinlet.setString(cellSize, "text", fsv.isTraversable(file).booleanValue() ? "" : formatByteString(file.length()));
416
        thinlet.setChoice(cellSize, "alignment", "right");
417
        setFileIcon(cellName, file);
418
        thinlet.putProperty(row, "file", file);
419
        return row;
420
    }
421

  
422

  
423
    private static void sort(File[] files, int sortColumn, boolean sortAscending)
424
    {
425
        if(files.length == 0)
426
            return;
427

  
428
        // don't sort if first file is a special (non-disc) file
429
        File firstFile = files[0];
430
        if(fsv.isComputerNode(firstFile) || fsv.isDrive(firstFile)
431
            || fsv.isFileSystemRoot(firstFile) || fsv.isFloppyDrive(firstFile)
432
            || fsv.isRoot(firstFile))
433
            return;
434

  
435
        Arrays.sort(files, new FileComparator(sortColumn, sortAscending));
436
    }
437

  
438

  
439
    private File getSelectedTableRowFile()
440
    {
441
        Object row = thinlet.getSelectedItem(tbFilelist);
442
        if(row != null)
443
            return (File) thinlet.getProperty(row, "file");
444
        else
445
            return null;
446
    }
447

  
448

  
449
    private String getSelectedTableRowFilename()
450
    {
451
        File file = getSelectedTableRowFile();
452
        if(file != null)
453
            return fsv.getSystemDisplayName(file);
454
        else
455
            return "";
456
    }
457

  
458

  
459
    private void setFileIcon(Object component, File file)
460
    {
461
        Icon icon = fsv.getSystemIcon(file);
462
        if(icon != null)
463
            thinlet.setIcon(component, "icon", convertIconToImage(thinlet, icon));
464
    }
465

  
466

  
467
    private static String formatTypeString(File file)
468
    {
469
        String desc = fsv.getSystemTypeDescription(file);
470
        if(desc == null || desc.length() == 0)
471
        {
472
            if(fsv.isComputerNode(file))
473
                desc = "Computer";
474
            else if(fsv.isDrive(file))
475
                desc = "Disk";
476
            else if(fsv.isFloppyDrive(file))
477
                desc = "Floppy";
478
            else if(fsv.isTraversable(file).booleanValue())
479
                desc = "Directory";
480
            else
481
                desc = "Unknown";
482
        }
483
        return desc;
484
    }
485

  
486

  
487
    private static String formatByteString(long size)
488
    {
489
        double d = size;
490
        int magnitude = 0;
491
        for(; d >= 1024.0; ++magnitude)
492
            d = d / 1024.0;
493
        switch(magnitude)
494
        {
495
            case 1: return decimalFormat.format(d) + " KB";
496
            case 2: return decimalFormat.format(d) + " MB";
497
            case 3: return decimalFormat.format(d) + " GB";
498
            case 4: return decimalFormat.format(d) + " TB";
499
            default: return integerFormat.format(size);
500
        }
501
    }
502

  
503

  
504
    private static String formatDateString(long date)
505
    {
506
        return dateFormat.format(new Date(date));
507
    }
508

  
509

  
510
    private static Image convertIconToImage(Thinlet thinlet, Icon icon)
511
    {
512
        BufferedImage image = new BufferedImage(icon.getIconWidth(),
513
            icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
514
        icon.paintIcon(thinlet, image.getGraphics(), 0, 0);
515
        return image;
516
    }
517
    //}}}
518

  
519

  
520
    //{{{ inner class FileComparator
521
    /** A comparator for files and directories. */
522
    private static class FileComparator implements Comparator
523
    {
524
        private Collator collator = Collator.getInstance();
525
        private int sortColumn;
526
        private boolean sortAscending;
527

  
528
        public FileComparator(int sortColumn, boolean sortAscending)
529
        {
530
            this.sortColumn = sortColumn;
531
            this.sortAscending = sortAscending;
532
        }
533

  
534
        /**
535
         * Compares the two objects assuming they are files (or
536
         * directories). Directories are always sorted before files.
537
         */
538
        public int compare(Object obj1, Object obj2)
539
        {
540
            File f1 = (File) obj1;
541
            File f2 = (File) obj2;
542
            boolean f1Traversable = fsv.isTraversable(f1).booleanValue();
543
            boolean f2Traversable = fsv.isTraversable(f2).booleanValue();
544

  
545
            if(f1Traversable && !f2Traversable)
546
                return sortAscending ? Integer.MIN_VALUE : Integer.MAX_VALUE;
547
            else if(!f1Traversable && f2Traversable)
548
                return sortAscending ? Integer.MAX_VALUE : Integer.MIN_VALUE;
549
            else
550
            {
551
                int retval = 0;
552
                switch(sortColumn)
553
                {
554
                    case 0: // Column "Name"
555
                        retval = collator.compare(
556
                            fsv.getSystemDisplayName(f1),
557
                            fsv.getSystemDisplayName(f2));
558
                        break;
559
                    case 1: // Column "Type"
560
                        retval = collator.compare(
561
                            fsv.getSystemTypeDescription(f1),
562
                            fsv.getSystemTypeDescription(f2));
563
                        break;
564
                    case 2: // Column "Size"
565
                        retval = f1.length() > f2.length() ? 1
566
                            : f1.length() < f2.length() ? -1 : 0;
567
                        break;
568
                    case 3: // Column "Last Modified"
569
                        retval = f1.lastModified() > f2.lastModified() ? 1
570
                            : f1.lastModified() < f2.lastModified() ? -1 : 0;
571
                        break;
572
                    default:
573
                        throw new IllegalArgumentException("unexpected column: " + sortColumn);
574
                }
575

  
576
                if(retval == 0 && sortColumn != 0)
577
                    retval = collator.compare(
578
                        fsv.getSystemDisplayName(f1),
579
                        fsv.getSystemDisplayName(f2));
580

  
581
                return sortAscending ? retval : (-1 * retval);
582
            }
583
        }
584

  
585
        /** not used; returns false. */
586
        public boolean equals(Object other)
587
        {
588
            return false;
589
        }
590
    }
591
    //}}}
592

  
593

  
594
    /**
595
     * Test method.
596
     */
597
    public static void main(String[] args)
598
    {
599
        FileChooser chooser = new FileChooser(new Frame(), "Choose File...", FileChooser.MODE_OPEN);
600
        if(args.length > 0)
601
            chooser.setSelectedFile(new File(args[0]));
602
        chooser.setFileFilters(new FileFilter[]
603
        {
604
            new ExtensionFileFilter("xml", "XML files (*.xml)"),
605
            new ExtensionFileFilter("java", "Java source code (*.java)"),
606
            new FileFilter()
607
            {
608
                public boolean accept(File file) { return true; }
609
                public String getDescription() { return "All files (*.*)"; }
610
            }
611
        });
612
        chooser.show();
613
        System.out.println("File selected: " + chooser.getSelectedFile());
614
        System.exit(0);
615
    }
616

  
617
}
618

  
org.gvsig.scripting/tags/org.gvsig.scripting-2.3.94/org.gvsig.scripting.thing/src/main/java/thinletcommons/MessageDialog.java
1
// jEdit settings:
2
// :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1:
3

  
4
package thinletcommons;
5

  
6

  
7
import java.awt.BorderLayout;
8
import java.awt.Dialog;
9
import java.awt.Dimension;
10
import java.awt.EventQueue;
11
import java.awt.Frame;
12
import java.awt.Image;
13
import java.util.logging.Level;
14
import java.util.logging.Logger;
15

  
16
import thinlet.Thinlet;
17

  
18
import utils.AWTUtils;
19

  
20

  
21
/**
22
 * A Thinlet message dialog with configurable OK/CANCEL/YES/NO-Buttons.
23
 *
24
 * <p>
25
 * The dialog is modal and blocks the calling frame/dialog. It is therefore
26
 * displayed in a separate window.
27
 *
28
 * <p>
29
 * <b>TODO:</b>
30
 * <ul>
31
 *   <li>make message type configurable (ERROR/WARN/INFO)</li>
32
 * </ul>
33
 *
34
 * @author Dirk Moebius
35
 */
36
public class MessageDialog
37
{
38
    //{{{ logging
39
    private static final Logger log = Logger.getLogger("thinletcommons");
40
    private static final boolean debug() { return log.isLoggable(Level.FINE); }
41
    //}}}
42

  
43

  
44
    public static final int MODE_OK = 0;
45
    public static final int MODE_OK_CANCEL = 1;
46
    public static final int MODE_YES_NO = 2;
47
    public static final int MODE_YES_NO_CANCEL = 3;
48

  
49
    public static final int ACTION_OK = 0;
50
    public static final int ACTION_CANCEL = 1;
51
    public static final int ACTION_YES = 2;
52
    public static final int ACTION_NO = 3;
53

  
54

  
55
    private Thinlet thinlet;
56
    private ThinletDialog dialog;
57
    private String msg;
58
    private Image icon;
59
    private int mode;
60
    private int returnValue;
61

  
62

  
63
    /**
64
     * Show a simple message dialog with an "Ok" button.
65
     */
66
    public MessageDialog(Dialog owner, String title, String msg)
67
    {
68
        this.dialog = new ThinletDialog(owner, title);
69
        init(msg, null, MODE_OK);
70
    }
71

  
72

  
73
    /**
74
     * Show a simple message dialog with an "Ok" button and a custom icon.
75
     */
76
    public MessageDialog(Dialog owner, String title, Image icon, String msg)
77
    {
78
        this.dialog = new ThinletDialog(owner, title);
79
        init(msg, icon, MODE_OK);
80
    }
81

  
82

  
83
    /**
84
     * Show a simple message dialog with an "Ok" button.
85
     */
86
    public MessageDialog(Frame owner, String title, String msg)
87
    {
88
        this.dialog = new ThinletDialog(owner, title);
89
        init(msg, null, MODE_OK);
90
    }
91

  
92

  
93
    /**
94
     * Show a simple message dialog with an "Ok" button and a custom icon.
95
     */
96
    public MessageDialog(Frame owner, String title, Image icon, String msg)
97
    {
98
        this.dialog = new ThinletDialog(owner, title);
99
        init(msg, icon, MODE_OK);
100
    }
101

  
102

  
103
    public MessageDialog(Dialog owner, String title, String msg, int mode)
104
    {
105
        this.dialog = new ThinletDialog(owner, title);
106
        init(msg, null, mode);
107
    }
108

  
109

  
110
    public MessageDialog(Dialog owner, String title, Image icon, String msg, int mode)
111
    {
112
        this.dialog = new ThinletDialog(owner, title);
113
        init(msg, icon, mode);
114
    }
115

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff