1.1 --- a/group/src/org/netbeans/modules/group/GroupShadow.java Wed Jun 25 08:46:04 2003 +0000
1.2 +++ b/group/src/org/netbeans/modules/group/GroupShadow.java Fri Jun 27 14:40:54 2003 +0000
1.3 @@ -26,8 +26,12 @@
1.4 import java.io.OutputStreamWriter;
1.5 import java.text.MessageFormat;
1.6 import java.util.*;
1.7 +import java.util.HashSet;
1.8 +import java.util.Set;
1.9 +import java.util.regex.Pattern;
1.10 import javax.swing.event.ChangeListener;
1.11
1.12 +import org.openide.ErrorManager;
1.13 import org.openide.cookies.CompilerCookie;
1.14 import org.openide.filesystems.*;
1.15 import org.openide.loaders.*;
1.16 @@ -43,20 +47,41 @@
1.17 import org.openide.util.Lookup;
1.18
1.19
1.20 -/** Group shadow.
1.21 - * <code>DataObject</code> representing a group of DataDbjects on a filesystem.
1.22 - * It also defines rules for templating of group members:
1.23 - * <p>property templateALL if true then the group is result
1.24 - * otherwise bunch of group members
1.25 - * <p>property templatePattern defines MessageFormat where
1.26 - * <p> {0} member name
1.27 - * <p> {1} name entered by user (during template instantiation)
1.28 - * <p> {2} posfix got from {0} by using part following last "__"
1.29 - * e.g. for "hello__World" is postfix "World"
1.30 - * for "helloWorld" is postfix ""
1.31 - * <p> {3} backward substitution result (i.e. __somethingBetween__ => {1} )
1.32 +/**
1.33 + * Group shadow - <code>DataObject</code> representing a group of
1.34 + * <code>DataObject</code>s on a filesystem.
1.35 + * It also defines rules for templating of group members:
1.36 + * <ul>
1.37 + * <li>property Template All - if <code>true</code> the group is result,
1.38 + * otherwise bunch of group members
1.39 + * </li>
1.40 + * <li>property Template Pattern - defines <code>MessageFormat</code> where:
1.41 + * <blockquote>
1.42 + * <table>
1.43 + * <tr><td><code>{0}</code></td>
1.44 + * <td>is a member name</td></tr>
1.45 + * <tr><td><code>{1}</code></td>
1.46 + * <td>is a name entered by user
1.47 + * (during template instantiation)</td></tr>
1.48 + * <tr><td valign="baseline"><code>{2}</code></td>
1.49 + * <td>is a posfix got from <code>{0}</code> by using part
1.50 + * following the last "__"<br />
1.51 + * Examples:<br />
1.52 + * - postfix of "hello__World"
1.53 + * is "World"<br />
1.54 + * - postfix of "helloWorld"
1.55 + * is "" (an empty string)</td></tr>
1.56 + * <tr><td><code>{3}</code></td>
1.57 + * <td>backward substitution result
1.58 + * (i.e. __somethingBetween__ => <code>{1}</code>)
1.59 + * </td></tr>
1.60 + * </table>
1.61 + * </blockquote>
1.62 + * </li>
1.63 + * </ul>
1.64 *
1.65 * @author Martin Ryzl
1.66 + * @author Marian Petras
1.67 * @see org.openide.loaders.DataObject
1.68 */
1.69 public class GroupShadow extends DataObject {
1.70 @@ -217,36 +242,52 @@
1.71 }
1.72 }
1.73
1.74 - /** Reads whole file to the List.
1.75 - * @param fo file object to be read
1.76 - * @return List of String */
1.77 + /**
1.78 + * Reads names of <code>FileObject</code>s contained in this group.
1.79 + *
1.80 + * @param fo <code>FileObject</code> containing names of contained
1.81 + * <code>FileObject</code>s (this object's primary file)
1.82 + * @return names of <code>FileObject</code>s,
1.83 + * each <code>FileObject</code>'s name is relative to the
1.84 + * filesystem the <code>FileObject</code> pertains to
1.85 + * @exception java.io.IOException if an error occured during reading
1.86 + * this group's primary file
1.87 + */
1.88 public static List readLinks(FileObject fo) throws IOException {
1.89 - String line;
1.90 List list = new ArrayList();
1.91 BufferedReader br = null;
1.92 try {
1.93 br = new BufferedReader(new InputStreamReader(fo.getInputStream()));
1.94 -
1.95 + String line;
1.96 while ((line = br.readLine()) != null) {
1.97 list.add(line);
1.98 }
1.99 - } catch (IOException ex) {
1.100 - throw ex;
1.101 } finally {
1.102 - if (br != null) br.close();
1.103 + if (br != null) {
1.104 + try {
1.105 + br.close();
1.106 + } catch (IOException ex) {
1.107 + /* give up */
1.108 + }
1.109 + }
1.110 }
1.111 -
1.112 return list;
1.113 }
1.114
1.115 - /** Reads whole file to the List.
1.116 - * @return List of String's */
1.117 + /**
1.118 + * Reads whole file to the List.
1.119 + *
1.120 + * @return List of String's
1.121 + */
1.122 public List readLinks() throws IOException {
1.123 return readLinks(getPrimaryFile());
1.124 }
1.125
1.126 - /** Writes List as new content of file.
1.127 - * @param list List of String's */
1.128 + /**
1.129 + * Writes List as new content of file.
1.130 + *
1.131 + * @param list List of String's
1.132 + */
1.133 public static void writeLinks(List list, FileObject fo) throws IOException {
1.134 String line;
1.135 Iterator iterator = list.iterator();
1.136 @@ -271,72 +312,83 @@
1.137 }
1.138 }
1.139
1.140 - /** Writes List as new content of file.
1.141 - * @param list List of String */
1.142 + /**
1.143 + * Writes List as new content of file.
1.144 + *
1.145 + * @param list List of String
1.146 + */
1.147 protected void writeLinks(List list) throws IOException {
1.148 writeLinks(list, getPrimaryFile());
1.149 }
1.150
1.151 - /** Get link name.
1.152 + /**
1.153 + * Get link name.
1.154 + *
1.155 * @param fo file object
1.156 - * @return file name */
1.157 + * @return file name
1.158 + */
1.159 public static String getLinkName(FileObject fo) {
1.160 return fo.getPackageNameExt('/', '.');
1.161 }
1.162
1.163 - /** Get FileObject for given filename.
1.164 - * @param filename filename
1.165 - * @return FileObject */
1.166 - private static FileObject findFileObject(String filename) {
1.167 -
1.168 - return org.openide.filesystems.Repository.getDefault()
1.169 - .findResource(filename);
1.170 + /**
1.171 + * Finds a <code>DataObject</code> for a given file name.
1.172 + * Lookup for a file having the specified file name is performed
1.173 + * in all mounted filesystems, using method
1.174 + * {@link org.openide.filesystems.Repository#findResource(String)}.
1.175 + *
1.176 + * @param filename name of the file, relative to the filesystem it
1.177 + * pertains to
1.178 + * @return the found <code>DataObject</code>, or <code>null</code>
1.179 + * if a file having the specified name was not found
1.180 + * @exception if a file having the specified name was found but
1.181 + * there is no <code>DataObject</code> created for it
1.182 + */
1.183 + private static DataObject getDataObjectByName(String filename)
1.184 + throws DataObjectNotFoundException {
1.185 + FileObject file = Repository.getDefault().findResource(filename);
1.186 + return (file != null) ? DataObject.find(file) : null;
1.187 }
1.188
1.189 - /** Get DataObject for given filename.
1.190 - * @param filename filename
1.191 - * @return DataObject
1.192 + /**
1.193 + * Returns <code>DataObject</code>s contained in this group.
1.194 + * Reads contents of this group's primary file (names of nested
1.195 + * <code>DataObject</code>s' primary files) and asks for the corresponding
1.196 + * <code>DataObject</code>s. In case of broken links (names of non-existing
1.197 + * files), names of the files are returned instead of
1.198 + * <code>DataObject</code>s. Files that exist but there is no
1.199 + * <code>DataObject</code> for them, are silently ignored.
1.200 + *
1.201 + * @return array containing <code>DataObject</code>s
1.202 + * and names of broken links
1.203 */
1.204 - private static DataObject getDataObjectByName(String filename) throws DataObjectNotFoundException {
1.205 -
1.206 - FileObject tempfo = findFileObject(filename);
1.207 - return (tempfo != null) ? DataObject.find(tempfo): null;
1.208 - }
1.209 -
1.210 - /** Reads filenames from shadow and creates an array of DataObjects for them.
1.211 - * @return array that can contain DataObjects or Strings with names of invalid
1.212 - * links */
1.213 public Object[] getLinks() {
1.214 - FileObject pf = getPrimaryFile(); //, parent = pf.getParent(), tempfo;
1.215 - DataObject obj;
1.216 - String line;
1.217 - HashSet set = new HashSet();
1.218 - List linearray;
1.219 -
1.220 + List filenames;
1.221 try {
1.222 - linearray = readLinks(pf);
1.223 - Iterator it = linearray.iterator();
1.224 - while (it.hasNext()) {
1.225 - line = (String)it.next();
1.226 - try {
1.227 - if ((obj = getDataObjectByName(line)) != null) {
1.228 - set.add(obj);
1.229 - }
1.230 - else set.add(new String(line));
1.231 - } catch (DataObjectNotFoundException ex) {
1.232 - // can be thrown when the link is not recognized by any data loader
1.233 - // in this case I can't help so ignore it
1.234 - }
1.235 + filenames = readLinks(getPrimaryFile());
1.236 + } catch (IOException ex) {
1.237 + ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, ex);
1.238 + return new Object[0];
1.239 + }
1.240 +
1.241 + Set set = new HashSet();
1.242 + for (Iterator it = filenames.iterator(); it.hasNext(); ) {
1.243 + String filename = (String) it.next();
1.244 + try {
1.245 + DataObject obj = getDataObjectByName(filename);
1.246 + set.add(obj != null ? (Object) obj
1.247 + : (Object) new String(filename));
1.248 + } catch (DataObjectNotFoundException ex) {
1.249 + // can be thrown when the link is not recognized by any data loader
1.250 + // in this case I can't help so ignore it
1.251 }
1.252 - } catch (IOException ex) {
1.253 - // it can be ignored
1.254 }
1.255 -
1.256 - // the array can contain DataObjects and Strings !
1.257 return set.toArray();
1.258 }
1.259
1.260 - /** Replace the oldprefix by a newprefix in name.
1.261 + /**
1.262 + * Replace the oldprefix by a newprefix in name.
1.263 + *
1.264 * @param name name
1.265 * @param oldprefix old prefix
1.266 * @param newprefix new prefix
1.267 @@ -349,141 +401,129 @@
1.268 return name;
1.269 }
1.270
1.271 - /** Replaces all occurences of __.*__ by a given text
1.272 - * @param name name with __.*__ substrings
1.273 - * @param pattern replacement
1.274 - * @return a string with __.*__ replaced
1.275 + /**
1.276 + * Replaces name according to naming pattern defined by property
1.277 + * {@link #PROP_TEMPLATE_PATTERN}, or falls to {@link #replaceName0()}
1.278 + * if value of the property is <code>null</code>.
1.279 */
1.280 - private String replaceName0(String name, String pattern) {
1.281 - StringBuffer sb = new StringBuffer(256);
1.282 - int i = 0, j, k;
1.283 + private String replaceName(String name, String replacement) {
1.284 + String fmt = getTemplatePattern();
1.285 +
1.286 + if (!isUsePattern() || fmt == null) {
1.287 + return name.replaceAll("__.*?__", replacement); //NOI18N
1.288 + }
1.289
1.290 - while ((j = name.indexOf("__", i)) != -1) { // NOI18N
1.291 + /* filter out all characters before "__" */
1.292 + int i = name.lastIndexOf("__"); //NOI18N
1.293 + String postfix = (i > 0) ? name.substring(i + 2) : ""; //NOI18N
1.294
1.295 - // first occurence found
1.296 - k = name.indexOf("__", j + 2); // NOI18N
1.297 - if (k != -1) {
1.298 - // second occurence found, copy start part and pattern
1.299 - sb.append(name.substring(i, j));
1.300 - sb.append(pattern);
1.301 - i = k + 2;
1.302 - } else {
1.303 - break;
1.304 - }
1.305 - }
1.306 - // copy the rest
1.307 - sb.append(name.substring(i, name.length ()));
1.308 - return sb.toString();
1.309 + String subst = string3(name, replacement);
1.310 + return MessageFormat.format(
1.311 + fmt,
1.312 + new String[] {name, replacement, postfix, subst});
1.313 }
1.314
1.315 - /** Replaces name according to namming pattern defined by templatePattern
1.316 - * property or fails to replaceName0() if the property is <code>null</code>. */
1.317 - private String replaceName(String name, String pattern) {
1.318 - String fmt = getTemplatePattern();
1.319 -
1.320 - if(!isUsePattern() || fmt==null){
1.321 - return replaceName0(name,pattern);
1.322 + /**
1.323 + * Substitution wrapper for special cases.
1.324 + *
1.325 + * @returns String representing new name after substitution
1.326 + */
1.327 + private String string3(String name, String replacement) {
1.328 +
1.329 + String patch;
1.330 + if (name.startsWith("__")) { //NOI18N
1.331 + patch = name;
1.332 + } else {
1.333 + patch = "__" + name; //NOI18N
1.334 }
1.335
1.336 - // filter out all characters before "__" // NOI18N
1.337 - String postfix = ""; // NOI18N
1.338 - try{
1.339 - int i = name.lastIndexOf("__"); // NOI18N
1.340 - if(i>0){
1.341 - postfix = name.substring(i+2);
1.342 - }
1.343 - }catch(IndexOutOfBoundsException ex){
1.344 - //use default value
1.345 - }
1.346 -
1.347 - String subst = string3(name,pattern);
1.348 - return MessageFormat.format(fmt,new String[]{name,pattern,postfix,subst});
1.349 - }
1.350 -
1.351 - /** Backward substitution in name by x.
1.352 - * SE: it calls recursively itself until whole substituion done
1.353 - * x must not contain substitution pattern !!! */
1.354 - private String substitute(String name, String x){
1.355 - StringBuffer sb = new StringBuffer(name);
1.356 - int j = name.length();
1.357 - int i = name.lastIndexOf("__",j); // NOI18N
1.358 - j = i-1;
1.359 - if(i>=0){
1.360 - i = name.lastIndexOf("__",j); // NOI18N
1.361 - if(i>=0){
1.362 - sb.delete(i,j+3);
1.363 - sb.insert(i,x);
1.364 - return substitute(sb.toString(),x);
1.365 - }
1.366 - }
1.367 - return name;
1.368 - }
1.369 -
1.370 - /** Substitution wrapper for special cases.
1.371 - * @returns String representing new name after substitution */
1.372 - private String string3(String name, String pattern) {
1.373 -
1.374 - String patch;
1.375 - if(name.startsWith("__")){ // NOI18N
1.376 - patch = name;
1.377 - } else {
1.378 - patch = "__" + name; // NOI18N
1.379 - }
1.380 -
1.381 - String s3 = substitute(patch,pattern);
1.382 - if (s3.startsWith("__")){ // NOI18N
1.383 + String s3 = substitute(patch, replacement);
1.384 +
1.385 + if (s3.startsWith("__")) { //NOI18N
1.386 s3 = s3.substring(2);
1.387 }
1.388 return s3;
1.389 }
1.390
1.391 + /**
1.392 + * Global backward substitution of substrings matching pattern
1.393 + * "<code>__.*?__</code>". The name is searched for the rightmost
1.394 + * occurence of a substring matching the pattern. If it is found,
1.395 + * the substring is replaced with a specified replacement and the same
1.396 + * process is performed on the result of the substitution, until no matching
1.397 + * substring is found.
1.398 + *
1.399 + * @param name string to process with a substitution
1.400 + * @param replacement string to put in place of matching substrings
1.401 + * of the name
1.402 + * @return result of the substitutions
1.403 + */
1.404 + private String substitute(String name, String replacement) {
1.405 + int last;
1.406 + int lastButOne;
1.407 + StringBuffer sb = new StringBuffer(name);
1.408 + while ((last = sb.lastIndexOf("__")) >= 0 //NOI18N
1.409 + && (lastButOne = sb.lastIndexOf("__", last - 2)) >= 0) { //NOI18N
1.410 + sb.replace(lastButOne, last + 2, replacement);
1.411 + }
1.412 + return sb.toString();
1.413 + }
1.414 +
1.415 /** Implementation of handleCreateFromTemplate for GroupShadow.
1.416 * All members of this group are called to create new objects. */
1.417 protected DataObject handleCreateFromTemplate(DataFolder df, String name) throws IOException {
1.418 List createdObjs = createGroupFromTemplate(df, name, true);
1.419 - return createdObjs != null && createdObjs.size() > 0 ?
1.420 - (DataObject)createdObjs.get(0) : this;
1.421 + return createdObjs != null && createdObjs.size() > 0
1.422 + ? (DataObject) createdObjs.get(0)
1.423 + : this;
1.424 }
1.425
1.426 - /** Creates new objects from all members of this group.
1.427 - * @returns List of created objects. */
1.428 - private List createGroupFromTemplate(DataFolder df,
1.429 - String name,
1.430 - boolean root) throws IOException {
1.431 - if (gsprocessed == null) gsprocessed = this;
1.432 - else return null;
1.433 + /**
1.434 + * Creates new objects from all members of this group.
1.435 + *
1.436 + * @returns list of created objects
1.437 + */
1.438 + private List createGroupFromTemplate(DataFolder folder,
1.439 + String name,
1.440 + boolean root) throws IOException {
1.441 + if (gsprocessed == null) {
1.442 + gsprocessed = this;
1.443 + } else {
1.444 + return null;
1.445 + }
1.446
1.447 - if (name == null) // name is not specified
1.448 - name = FileUtil.findFreeFileName(df.getPrimaryFile(),
1.449 - getPrimaryFile().getName(), GS_EXTENSION);
1.450 -
1.451 + if (name == null) {// name is not specified
1.452 + name = FileUtil.findFreeFileName(folder.getPrimaryFile(),
1.453 + getPrimaryFile().getName(),
1.454 + GS_EXTENSION);
1.455 + }
1.456 Object[] objs = getLinks();
1.457 - ArrayList createdObjs = new ArrayList(objs.length+1);
1.458 + ArrayList createdObjs = new ArrayList(objs.length + 1);
1.459 ArrayList linksList = new ArrayList(objs.length);
1.460
1.461 try {
1.462 - for (int i=0; i < objs.length; i++) {
1.463 + for (int i = 0; i < objs.length; i++) {
1.464 if (objs[i] instanceof DataObject) {
1.465 - DataObject original = (DataObject)objs[i];
1.466 + DataObject original = (DataObject) objs[i];
1.467
1.468 if (original instanceof GroupShadow) {
1.469 - GroupShadow gs = (GroupShadow)original;
1.470 - List items = gs.createGroupFromTemplate(df, name, false);
1.471 + GroupShadow gs = (GroupShadow) original;
1.472 + List items = gs.createGroupFromTemplate(folder, name, false);
1.473 if (items != null) {
1.474 - for (int j=0, n=items.size(); j < n; j++) {
1.475 - DataObject obj = (DataObject)items.get(j);
1.476 + for (int j = 0, n = items.size(); j < n; j++) {
1.477 + DataObject obj = (DataObject) items.get(j);
1.478 createdObjs.add(obj);
1.479 linksList.add(getLinkName(obj.getPrimaryFile()));
1.480 - if (j == 0 && obj instanceof GroupShadow
1.481 - && gs.getTemplateAll())
1.482 + if (j == 0
1.483 + && obj instanceof GroupShadow
1.484 + && gs.getTemplateAll())
1.485 break;
1.486 }
1.487 // createdObjs.addAll(items);
1.488 }
1.489 - }
1.490 - else {
1.491 + } else {
1.492 String repName = replaceName(original.getName(), name);
1.493 - DataObject newObj = original.createFromTemplate(df, repName);
1.494 + DataObject newObj = original.createFromTemplate(folder, repName);
1.495 createdObjs.add(newObj);
1.496 linksList.add(getLinkName(newObj.getPrimaryFile()));
1.497 }
1.498 @@ -492,11 +532,12 @@
1.499
1.500 if (objs.length == 0 || getTemplateAll()) { // create also the group
1.501 String repName = root ? name : replaceName(getName(), name);
1.502 - FileObject fo = df.getPrimaryFile().createData(repName, GS_EXTENSION);
1.503 + FileObject fo = folder.getPrimaryFile().createData(repName, GS_EXTENSION);
1.504 writeLinks(linksList, fo);
1.505 - GroupShadow gs = (GroupShadow)DataObject.find(fo);
1.506 - if (gs == null)
1.507 + GroupShadow gs = (GroupShadow) DataObject.find(fo);
1.508 + if (gs == null) {
1.509 gs = new GroupShadow(fo, getLoader());
1.510 + }
1.511 createdObjs.add(0, gs);
1.512 }
1.513 }
1.514 @@ -514,7 +555,9 @@
1.515 return createdObjs;
1.516 }
1.517
1.518 - /** Setter for showLinks property.
1.519 + /**
1.520 + * Setter for showLinks property.
1.521 + *
1.522 * @param show if true also show real packages and names of targets */
1.523 public void setShowLinks(boolean show) {
1.524 showLinks = show;
1.525 @@ -525,8 +568,11 @@
1.526 return showLinks;
1.527 }
1.528
1.529 - /** Setter for template pattern.
1.530 - * @exception IOException if error occured */
1.531 + /**
1.532 + * Setter for template pattern.
1.533 + *
1.534 + * @exception IOException if error occured
1.535 + */
1.536 public void setTemplatePattern(String templatePattern) throws IOException{
1.537 final FileObject fo = getPrimaryFile();
1.538 String old = getTemplatePattern();
1.539 @@ -542,21 +588,15 @@
1.540 /** Getter for template pattern. */
1.541 public String getTemplatePattern(){
1.542 Object value = getPrimaryFile().getAttribute(GroupShadow.PROP_TEMPLATE_PATTERN);
1.543 - if(value != null && value instanceof String)
1.544 - return (String)value;
1.545 - else
1.546 - // Default pattern.
1.547 - return "{1}";
1.548 + return (value instanceof String) ? (String) value
1.549 + : "{1}"; //NOI18N
1.550 }
1.551
1.552
1.553 /** Getter for use pattern property. */
1.554 public boolean isUsePattern() {
1.555 - Object value = getPrimaryFile().getAttribute(GroupShadow.PROP_USE_PATTERN);
1.556 - if(value != null && value instanceof Boolean)
1.557 - return ((Boolean)value).booleanValue();
1.558 -
1.559 - return false;
1.560 + Object o = getPrimaryFile().getAttribute(GroupShadow.PROP_USE_PATTERN);
1.561 + return Boolean.TRUE.equals(o);
1.562 }
1.563
1.564
1.565 @@ -565,19 +605,19 @@
1.566 FileObject fileObject = getPrimaryFile();
1.567 boolean oldValue = isUsePattern();
1.568
1.569 - if(usePattern == oldValue)
1.570 + if (usePattern == oldValue) {
1.571 return;
1.572 + }
1.573 + fileObject.setAttribute(PROP_USE_PATTERN, Boolean.valueOf(usePattern));
1.574
1.575 - fileObject.setAttribute(PROP_USE_PATTERN, usePattern ? Boolean.TRUE : Boolean.FALSE);
1.576 -
1.577 - firePropertyChange(PROP_USE_PATTERN, oldValue ? Boolean.TRUE : Boolean.FALSE, usePattern ? Boolean.TRUE : Boolean.FALSE);
1.578 + firePropertyChange(PROP_USE_PATTERN, Boolean.valueOf(oldValue),
1.579 + Boolean.valueOf(usePattern));
1.580 }
1.581
1.582 /** Getter for template all. */
1.583 public boolean getTemplateAll() {
1.584 Object o = getPrimaryFile().getAttribute(GroupShadow.PROP_TEMPLATE_ALL);
1.585 - if (o instanceof Boolean) return ((Boolean) o).booleanValue();
1.586 - else return false;
1.587 + return Boolean.TRUE.equals(o);
1.588 }
1.589
1.590
1.591 @@ -589,7 +629,8 @@
1.592 fo.setAttribute(PROP_TEMPLATE_ALL, (templateAll ? Boolean.TRUE : null));
1.593
1.594 if (oldtempl != templateAll) {
1.595 - firePropertyChange(PROP_TEMPLATE_ALL, oldtempl ? Boolean.TRUE : Boolean.FALSE, templateAll ? Boolean.TRUE : Boolean.FALSE);
1.596 + firePropertyChange(PROP_TEMPLATE_ALL, Boolean.valueOf(oldtempl),
1.597 + Boolean.valueOf(templateAll));
1.598 }
1.599 }
1.600