Index: DefaultScriptingFolder.java
===================================================================
--- DefaultScriptingFolder.java	(revision 1065)
+++ DefaultScriptingFolder.java	(revision 1066)
@@ -6,6 +6,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -18,6 +19,7 @@
 import org.gvsig.scripting.ScriptingManager;
 import org.gvsig.scripting.ScriptingUnit;
 import org.gvsig.tools.exception.BaseException;
+import static org.gvsig.tools.util.FileTools.relativizeFile;
 import org.gvsig.tools.visitor.Visitor;
 import org.ini4j.Ini;
 import org.slf4j.Logger;
@@ -28,7 +30,9 @@
     private static final Logger logger = LoggerFactory.getLogger(DefaultScriptingFolder.class);
     protected File folder;
     private File infFile;
-
+    private File linkTarget;
+    private String[] iconNames = new String[]{"scripting-icon-folder", "scripting-icon-folder-open"};
+    
     protected DefaultScriptingFolder(ScriptingManager manager) {
         super(null, ScriptingManager.UNIT_FOLDER, manager, null);
     }
@@ -36,29 +40,21 @@
     public DefaultScriptingFolder(ScriptingFolder parent, ScriptingManager manager, File folder) {
         super(parent, ScriptingManager.UNIT_FOLDER, manager, null);
         this.folder = new File(FilenameUtils.normalizeNoEndSeparator(folder.getAbsolutePath(),true));
-        this.infFile = null;
-        if( folder.isFile() ) {
-            if( !folder.getName().toLowerCase().endsWith(".inf") ) {
-                throw new IllegalArgumentException("folder argument can be a folder.");
-            }
-            if( !folder.exists() ) {
-                throw new IllegalArgumentException("Can't access to folder inf file ("+folder.getAbsolutePath()+").");
-            }
-            this.loadInf(folder);
-        } else {
-            this.setId(folder.getName());
-            File f = new File(folder.getParentFile(),this.getId() + ".inf");
-            if (f.isFile()) {
-                this.loadInf(f);
-            }
+        this.infFile = null;        
+        if( folder.isFile() && !FilenameUtils.isExtension(folder.getName(), "inf") ) {
+            throw new IllegalArgumentException("folder argument can be a folder.");
         }
+        this.load(parent, folder.getName());
    }
     
     @Override
     public void create(ScriptingFolder folder, String id) {
         File f = new File(folder.getFile(), id);
-        f.mkdir();
-        this.load(folder, id);    }
+        this.load(folder, id);
+        if( !this.isLink() ) {
+            f.mkdir();
+        }
+    }
 
     @Override
     public void create(ScriptingFolder folder, String id, String language) {
@@ -67,13 +63,19 @@
     
     @Override
     public File getFile() {
-        return this.folder;
+        if( this.linkTarget==null ) {
+            return this.folder;
+        }
+        return this.linkTarget;
     }
 
     @Override
     public List<File> getFiles() {
         List<File> l = new ArrayList<>();
-        l.add(this.getFile());
+        l.add(this.folder);
+        if( this.infFile!=null ) {
+            l.add(this.infFile);
+        }
         return l;
     }
 
@@ -83,21 +85,16 @@
         if( parent != null ) {
             return parent;
         }
-        File f = this.infFile;
-        if( f==null ) {
-            // Is a link
-            f = this.folder;
-        } 
+        File f = this.folder;
+        if( this.isLink() ) {
+            f = this.infFile.getParentFile();
+        }
         if( FileUtils.isSameFile(this.manager.getRootUserFolder(), f) ) {
             return null;
         }
         if( FileUtils.isRootFile(f) ) {
             return null;
         }
-//        if( !DefaultScriptingManager.isSubfolder(this.manager.getRootUserFolder(), f) ) {
-//            return null;
-//        }        
-
         return manager.getFolder(f.getParentFile());
     }
 
@@ -158,10 +155,21 @@
         return unit;
     }
 
+    private boolean containsAny(Set<File> files, Collection<File> other) {
+        for (File file : other) {
+            if( files.contains(file) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
     @Override
     public List<ScriptingUnit> getUnits() {
         List<ScriptingUnit> ol = new ArrayList<>();
-        File[] files = this.folder.listFiles(new FilenameFilter() {
+        //
+        // Buscamos los directorios y ficheros ".inf".
+        File[] files = this.getFile().listFiles(new FilenameFilter() {
             @Override
             public boolean accept(File arg0, String arg1) {
                 File f = new File(arg0, arg1);
@@ -171,35 +179,32 @@
                 if (f.isDirectory()) {
                     return true;
                 }
+                if( "#folder.inf".equals(f.getName()) ) {
+                    return false;
+                }
                 String ext = FilenameUtils.getExtension(f.getName());
                 return "inf".equalsIgnoreCase(ext);
             }
         });
         Set<File> filesAdded = new HashSet<>();
         if (files != null) {
-//            Arrays.sort(files, new Comparator<File>() {
-//                @Override
-//                public int compare(File f1, File f2) {
-//                    if (f1.isDirectory() && !f2.isDirectory()) {
-//                        return -1;
-//                    } else if (!f1.isDirectory() && f2.isDirectory()) {
-//                        return 1;
-//                    } else {
-//                        return f1.getName().toLowerCase().compareTo(f2.getName().toLowerCase());
-//                    }
-//                }
-//            });
             for (File f : files) {
                 try {
                     ScriptingUnit unit = this.getUnit(f);
-                    filesAdded.addAll(unit.getFiles());
-                    ol.add(unit);
+                    if( !containsAny(filesAdded, unit.getFiles()) ) {
+                        filesAdded.addAll(unit.getFiles());
+                        ol.add(unit);
+                    }
                 } catch (Exception ex) {
                     logger.warn("Can't create unit from file '" + f.getAbsolutePath() + "'.",ex);
                 }
             }
         }
-        files = this.folder.listFiles(new FilenameFilter() {
+        
+        
+        // Ahora buscamos los ficheros de tipo ExternalFile, no son 
+        // directorios, no tienen ".inf".
+        files = this.getFile().listFiles(new FilenameFilter() {
             @Override
             public boolean accept(File arg0, String arg1) {
                 File f = new File(arg0, arg1);
@@ -207,8 +212,11 @@
                     return false;
                 }
                 if (f.isDirectory()) {
-                    return true;
+                    return false;
                 }
+                if( "#folder.inf".equals(f.getName()) ) {
+                    return false;
+                }
                 return true;
             }
         });
@@ -249,7 +257,7 @@
     @Override
     public List<ScriptingFolder> getUnitFolders() {
         List<ScriptingFolder> ol = new ArrayList<>();
-        File[] files = this.folder.listFiles(new FilenameFilter() {
+        File[] files = this.getFile().listFiles(new FilenameFilter() {
             @Override
             public boolean accept(File arg0, String arg1) {
                 File f = new File(arg0, arg1);
@@ -301,51 +309,110 @@
     }
 
     @Override
+    public File getFileResource(String extension) {
+        if( this.isLink() ) {
+            return new File(
+                    this.infFile.getParentFile(), 
+                    FilenameUtils.getBaseName(this.infFile.getName()) + extension
+                ).getAbsoluteFile();
+        }
+        return new File(
+                this.getFile().getParentFile(), 
+                this.getFile().getName() + extension
+            ).getAbsoluteFile();
+    }
+    
+
+    @Override
+    public void save() {
+        File f = this.infFile;
+        if( f==null ) {
+            f = new File(folder,"#folder.inf");
+        }
+        try {        
+            Ini prefs = new Ini();
+            prefs.setFile(f);
+            if( this.linkTarget!=null ) {
+                prefs.put(
+                        ScriptingManager.UNIT_FOLDER, 
+                        "path", 
+                        relativizeFile(this.infFile.getParentFile(), this.linkTarget)
+                );
+            }
+            if( this.iconNames!=null ) {
+                prefs.put(ScriptingManager.UNIT_FOLDER, "iconName", this.iconNames[0]);
+                prefs.put(ScriptingManager.UNIT_FOLDER, "iconNameOpen", this.iconNames[1]);
+            }
+            this.save(prefs);
+        } catch (Throwable e) {
+            String msg = "Can't save 'inf' file '" + f.getAbsolutePath() + "'.";
+            logger.warn(msg, e);
+            throw new RuntimeException(msg, e);
+        }
+    }
+    
+    @Override
     public void load(ScriptingFolder parent, String id) {
-        File f = new File(parent.getFile(), id+".inf");
-        if (f.isFile()) {
-            this.loadInf(f);
-        } else {
-            this.setParent(parent);
-            this.setId(id);
+        this.infFile = null;
+        this.linkTarget = null;
+        this.iconNames = new String[]{"scripting-icon-folder", "scripting-icon-folder-open"};
+        this.setId(id);
+        this.setParent(parent);
+
+        File fileInf = getFileResource(".inf");
+        if (!fileInf.isFile()) {
+            fileInf = new File(this.folder, "#folder.inf");
+            if (!fileInf.isFile()) {
+                return;
+            }
         }
-    }
-        
-    private void loadInf(File f) {   
         Ini prefs;
         try {
-            prefs = new Ini(f);
+            prefs = new Ini(fileInf);
             loadInf(prefs);
-            String spath = getInfString(
-                    prefs, 
-                    ScriptingManager.UNIT_FOLDER, 
+            String iconName = getInfString(
+                    prefs,
+                    ScriptingManager.UNIT_FOLDER,
+                    "iconName",
+                    null
+            );
+            String iconNameOpen = getInfString(
+                    prefs,
+                    ScriptingManager.UNIT_FOLDER,
+                    "iconNameOpen",
+                    null
+            );
+            if( iconName!=null ) {
+                this.iconNames = new String[] {
+                    iconName,
+                    iconNameOpen==null? iconName:iconNameOpen
+                };
+            }
+            String targetPath = getInfString(
+                    prefs,
+                    ScriptingManager.UNIT_FOLDER,
                     "path",
                     null
             );
-            if( StringUtils.isEmpty(spath) ) {
-                this.folder = FileUtils.removeExtension(f);
-                this.infFile = null;
-            } else {
-                File path = new File(spath);
-                if( path.isAbsolute() ) {
-                    this.folder = path;
+            if( !StringUtils.isEmpty(targetPath) ) {
+                File target = new File(targetPath);
+                if (target.isAbsolute()) {
+                    this.linkTarget = target;
                 } else {
-                    this.folder = new File(FilenameUtils.concat(f.getParent(), spath));
+                    this.linkTarget = new File(FilenameUtils.concat(fileInf.getParent(), targetPath));
                 }
-                this.infFile = FileUtils.getAbsoluteFile(f);
-                this.manager.addLink(this.infFile, this.folder);
+                this.manager.addLink(this.infFile, this.linkTarget);
             }
-            this.folder = FileUtils.getAbsoluteFile(this.folder);
-            this.setId(FileUtils.getBaseName(f));
-            this.setParent(manager.getFolder(f.getParentFile()));
+            this.infFile = FileUtils.getAbsoluteFile(fileInf);
         } catch (Exception e) {
-            logger.warn("Can't load 'inf' file '" + f.getAbsolutePath() + "'.", e);
+            logger.warn("Can't load 'inf' file '" + fileInf.getAbsolutePath() + "'.", e);
         }
+
     }
 
     @Override
     public String[] getIconNames() {
-        return new String[]{"folder", "folder-drag-accept"};
+        return this.iconNames;
     }
 
     @Override
@@ -432,7 +499,7 @@
     
     @Override
     public boolean isLink() {
-        return this.infFile!=null;
+        return this.linkTarget!=null;
     }
     
     @Override
@@ -451,18 +518,29 @@
     }
 
     @Override
-    public void save() {
-        File f = this.infFile;
-        if( f==null ) {
-            f = new File(folder.getParentFile(),this.getId() + ".inf");
+    public String getRawInf() {
+        if( this.infFile == null ) {
+            return null;
         }
-        try {        
-            Ini prefs = new Ini(f);
-            this.save(prefs);
-        } catch (Throwable e) {
-            String msg = "Can't save 'inf' file '" + f.getAbsolutePath() + "'.";
-            logger.warn(msg, e);
-            throw new RuntimeException(msg, e);
+        try {
+            String rawInf = org.apache.commons.io.FileUtils.readFileToString(infFile);
+            return rawInf;
+        } catch (IOException ex) {
+            // TODO: 
         }
+        return null;
     }
+    
+    @Override
+    public void setRawInf(String rawInf) {
+        if( this.infFile == null ) {
+            this.infFile = new File(folder,"#folder.inf");
+        }
+        try {
+            org.apache.commons.io.FileUtils.write(infFile, rawInf);
+            this.reload();
+        } catch (IOException ex) {
+            // TODO: 
+        }
+    }
 }
