Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for java.awt.datatransfer.SystemFlavorMap

 1:  /* SystemFlavorMap.java -- Maps between native flavor names and MIME types.
 2:  Copyright (C) 2001, 2004 Free Software Foundation, Inc.
 3: 
 4: This file is part of GNU Classpath.
 5: 
 6: GNU Classpath is free software; you can redistribute it and/or modify
 7: it under the terms of the GNU General Public License as published by
 8: the Free Software Foundation; either version 2, or (at your option)
 9: any later version.
 10: 
 11: GNU Classpath is distributed in the hope that it will be useful, but
 12: WITHOUT ANY WARRANTY; without even the implied warranty of
 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 14: General Public License for more details.
 15: 
 16: You should have received a copy of the GNU General Public License
 17: along with GNU Classpath; see the file COPYING. If not, write to the
 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 19: 02110-1301 USA.
 20: 
 21: Linking this library statically or dynamically with other modules is
 22: making a combined work based on this library. Thus, the terms and
 23: conditions of the GNU General Public License cover the whole
 24: combination.
 25: 
 26: As a special exception, the copyright holders of this library give you
 27: permission to link this library with independent modules to produce an
 28: executable, regardless of the license terms of these independent
 29: modules, and to copy and distribute the resulting executable under
 30: terms of your choice, provided that you also meet, for each linked
 31: independent module, the terms and conditions of the license of that
 32: module. An independent module is a module which is not derived from
 33: or based on this library. If you modify this library, you may extend
 34: this exception to your version of the library, but you are not
 35: obligated to do so. If you do not wish to do so, delete this
 36: exception statement from your version. */
 37: 
 38: 
 39:  package java.awt.datatransfer;
 40: 
 41:  import java.awt.Toolkit;
 42:  import java.io.File;
 43:  import java.io.FileInputStream;
 44:  import java.io.IOException;
 45:  import java.io.InputStream;
 46:  import java.net.URL;
 47:  import java.security.AccessController;
 48:  import java.security.PrivilegedAction;
 49:  import java.util.ArrayList;
 50:  import java.util.Collection;
 51:  import java.util.Enumeration;
 52:  import java.util.HashMap;
 53:  import java.util.List;
 54:  import java.util.Map;
 55:  import java.util.Properties;
 56:  import java.util.WeakHashMap;
 57: 
 58:  /**
 59:  * This class maps between native platform type names and DataFlavors.
 60:  *
 61:  * XXX - The current implementation does no mapping at all.
 62:  *
 63:  * @author Mark Wielaard (mark@klomp.org)
 64:  *
 65:  * @since 1.2
 66:  */
 67:  public final class SystemFlavorMap implements FlavorMap, FlavorTable
 68: {
 69:  /**
 70:  * The map which maps the thread's <code>ClassLoaders</code> to 
 71:  * <code>SystemFlavorMaps</code>.
 72:  */
 73:  private static final Map systemFlavorMaps = new WeakHashMap();
 74:  
 75:  /**
 76:  * Constant which is used to prefix encode Java MIME types.
 77:  */
 78:  private static final String GNU_JAVA_MIME_PREFIX = "gnu.java:";
 79:  
 80:  /**
 81:  * This map maps native <code>String</code>s to lists of 
 82:  * <code>DataFlavor</code>s
 83:  */
 84:  private HashMap<String,List<DataFlavor>> nativeToFlavorMap =
 85:  new HashMap<String,List<DataFlavor>>();
 86:  
 87:  /**
 88:  * This map maps <code>DataFlavor</code>s to lists of native 
 89:  * <code>String</code>s
 90:  */
 91:  private HashMap<DataFlavor, List<String>> flavorToNativeMap =
 92:  new HashMap<DataFlavor, List<String>>();
 93:  
 94:  /**
 95:  * Private constructor.
 96:  */
 97:  private SystemFlavorMap ()
 98:  {
 99:  AccessController.doPrivileged
 100:  (new PrivilegedAction<Object>()
 101:  {
 102:  public Object run()
 103:  {
 104:  try
 105:  {
 106:  // Load installed flavormap.properties first.
 107:  String sep = File.separator;
 108:  File propsFile =
 109:  new File(System.getProperty("gnu.classpath.home.url")
 110:  + sep + "accessibility.properties");
 111:  InputStream in = new FileInputStream(propsFile);
 112:  Properties props = new Properties();
 113:  props.load(in);
 114:  in.close();
 115: 
 116:  String augmented = Toolkit.getProperty("AWT.DnD.flavorMapFileURL",
 117:  null);
 118:  if (augmented != null)
 119:  {
 120:  URL url = new URL(augmented);
 121:  in = url.openStream();
 122:  props.load(in);
 123:  }
 124:  setupMapping(props);
 125:  }
 126:  catch (IOException ex)
 127:  {
 128:  // Can't do anything about it.
 129:  }
 130:  return null;
 131:  }
 132:  });
 133:  }
 134: 
 135:  /**
 136:  * Sets up the mapping from native to mime types and vice versa as specified
 137:  * in the flavormap.properties file.
 138:  *
 139:  * This is package private to avoid an accessor method.
 140:  *
 141:  * @param props the properties file
 142:  */
 143:  void setupMapping(Properties props)
 144:  {
 145:  Enumeration propNames = props.propertyNames();
 146:  while (propNames.hasMoreElements())
 147:  {
 148:  try
 149:  {
 150:  String nat = (String) propNames.nextElement();
 151:  String mime = (String) props.getProperty(nat);
 152:  // Check valid mime type.
 153:  MimeType type = new MimeType(mime);
 154:  DataFlavor flav = new DataFlavor(mime);
 155:  
 156:  List<DataFlavor> flavs = nativeToFlavorMap.get(nat);
 157:  if (flavs == null)
 158:  {
 159:  flavs = new ArrayList<DataFlavor>();
 160:  nativeToFlavorMap.put(nat, flavs);
 161:  }
 162:  List<String> nats = flavorToNativeMap.get(flav);
 163:  if (nats == null)
 164:  {
 165:  nats = new ArrayList<String>();
 166:  flavorToNativeMap.put(flav, nats);
 167:  }
 168:  flavs.add(flav);
 169:  nats.add(nat);
 170:  }
 171:  catch (ClassNotFoundException ex)
 172:  {
 173:  // Skip.
 174:  }
 175:  catch (MimeTypeParseException ex)
 176:  {
 177:  // Skip.
 178:  }
 179:  }
 180:  }
 181: 
 182:  /**
 183:  * Maps the specified <code>DataFlavor</code> objects to the native
 184:  * data type name. The returned <code>Map</code> has keys that are
 185:  * the data flavors and values that are strings. The returned map
 186:  * may be modified. This can be useful for implementing nested mappings.
 187:  *
 188:  * @param flavors An array of data flavors to map
 189:  * or null for all data flavors.
 190:  *
 191:  * @return A <code>Map</code> of native data types to data flavors.
 192:  */
 193:  public Map<DataFlavor, String> getNativesForFlavors (DataFlavor[] flavors)
 194:  {
 195:  return new HashMap<DataFlavor, String>();
 196:  }
 197: 
 198:  /**
 199:  * Maps the specified native type names to <code>DataFlavor</code>'s.
 200:  * The returned <code>Map</code> has keys that are strings and values
 201:  * that are <code>DataFlavor</code>'s. The returned map may be
 202:  * modified. This can be useful for implementing nested mappings.
 203:  *
 204:  * @param natives An array of native types to map
 205:  * or null for all native types.
 206:  *
 207:  * @return A <code>Map</code> of data flavors to native type names.
 208:  */
 209:  public Map<String, DataFlavor> getFlavorsForNatives (String[] natives)
 210:  { 
 211:  return new HashMap<String, DataFlavor>();
 212:  }
 213: 
 214:  /**
 215:  * Returns the (System)FlavorMap for the current thread's
 216:  * ClassLoader.
 217:  */
 218:  public static FlavorMap getDefaultFlavorMap ()
 219:  {
 220:  ClassLoader classLoader = Thread.currentThread()
 221:  .getContextClassLoader();
 222:  
 223:  //if ContextClassLoader not set, use system default 
 224:  if (classLoader == null)
 225:  {
 226:  classLoader = ClassLoader.getSystemClassLoader();
 227:  }
 228:  
 229:  synchronized(systemFlavorMaps)
 230:  {
 231:  FlavorMap map = (FlavorMap) 
 232:  systemFlavorMaps.get(classLoader);
 233:  if (map == null) 
 234:  {
 235:  map = new SystemFlavorMap();
 236:  systemFlavorMaps.put(classLoader, map);
 237:  }
 238:  return map;
 239:  }
 240:  }
 241: 
 242:  /**
 243:  * Encodes a MIME type for use as a <code>String</code> native. The format
 244:  * of an encoded representation of a MIME type is implementation-dependent.
 245:  * The only restrictions are:
 246:  * <ul>
 247:  * <li>The encoded representation is <code>null</code> if and only if the
 248:  * MIME type <code>String</code> is <code>null</code>.</li>
 249:  * <li>The encoded representations for two non-<code>null</code> MIME type
 250:  * <code>String</code>s are equal if and only if these <code>String</code>s
 251:  * are equal according to <code>String.equals(Object)</code>.</li>
 252:  * </ul>
 253:  * <p>
 254:  * The present implementation of this method returns the specified MIME
 255:  * type <code>String</code> prefixed with <code>gnu.java:</code>.
 256:  *
 257:  * @param mime the MIME type to encode
 258:  * @return the encoded <code>String</code>, or <code>null</code> if
 259:  * mimeType is <code>null</code>
 260:  */
 261:  public static String encodeJavaMIMEType (String mime)
 262:  {
 263:  if (mime != null)
 264:  return GNU_JAVA_MIME_PREFIX + mime;
 265:  else
 266:  return null;
 267:  }
 268: 
 269:  /**
 270:  * Encodes a <code>DataFlavor</code> for use as a <code>String</code>
 271:  * native. The format of an encoded <code>DataFlavor</code> is 
 272:  * implementation-dependent. The only restrictions are:
 273:  * <ul>
 274:  * <li>The encoded representation is <code>null</code> if and only if the
 275:  * specified <code>DataFlavor</code> is <code>null</code> or its MIME type
 276:  * <code>String</code> is <code>null</code>.</li>
 277:  * <li>The encoded representations for two non-<code>null</code>
 278:  * <code>DataFlavor</code>s with non-<code>null</code> MIME type
 279:  * <code>String</code>s are equal if and only if the MIME type
 280:  * <code>String</code>s of these <code>DataFlavor</code>s are equal
 281:  * according to <code>String.equals(Object)</code>.</li>
 282:  * </ul>
 283:  * <p>
 284:  * The present implementation of this method returns the MIME type
 285:  * <code>String</code> of the specified <code>DataFlavor</code> prefixed
 286:  * with <code>gnu.java:</code>.
 287:  *
 288:  * @param df the <code>DataFlavor</code> to encode
 289:  * @return the encoded <code>String</code>, or <code>null</code> if
 290:  * flav is <code>null</code> or has a <code>null</code> MIME type
 291:  */
 292:  public static String encodeDataFlavor (DataFlavor df)
 293:  {
 294:  if (df != null)
 295:  {
 296:  return encodeJavaMIMEType(df.getMimeType());
 297:  }
 298:  else
 299:  return null;
 300:  }
 301: 
 302:  /**
 303:  * Returns true if the native type name can be represented as
 304:  * a java mime type. Returns <code>false</code> if parameter is
 305:  * <code>null</code>.
 306:  */
 307:  public static boolean isJavaMIMEType (String name)
 308:  {
 309:  return (name != null && name.startsWith(GNU_JAVA_MIME_PREFIX));
 310:  }
 311: 
 312:  /**
 313:  * Decodes a <code>String</code> native for use as a Java MIME type.
 314:  *
 315:  * @param name the <code>String</code> to decode
 316:  * @return the decoded Java MIME type, or <code>null</code> if nat 
 317:  * is not an encoded <code>String</code> native
 318:  */
 319:  public static String decodeJavaMIMEType (String name)
 320:  {
 321:  if (isJavaMIMEType(name))
 322:  {
 323:  return name.substring(GNU_JAVA_MIME_PREFIX.length());
 324:  }
 325:  else 
 326:  return null;
 327:  }
 328: 
 329:  /**
 330:  * Returns the data flavor given the native type name
 331:  * or null when no such data flavor exists.
 332:  */
 333:  public static DataFlavor decodeDataFlavor (String name)
 334:  throws ClassNotFoundException
 335:  {
 336:  String javaMIMEType = decodeJavaMIMEType (name);
 337:  
 338:  if (javaMIMEType != null)
 339:  return new DataFlavor (javaMIMEType);
 340:  else
 341:  return null;
 342:  }
 343: 
 344:  /** 
 345:  * Returns a List of <code>DataFlavors</code> to which the specified 
 346:  * <code>String</code> native can be translated by the data transfer 
 347:  * subsystem. The <code>List</code> will be sorted from best 
 348:  * <code>DataFlavor</code> to worst. That is, the first <code>DataFlavor 
 349:  * </code> will best reflect data in the specified native to a Java 
 350:  * application. 
 351:  * <p>
 352:  * If the specified native is previously unknown to the data transfer 
 353:  * subsystem, and that native has been properly encoded, then invoking 
 354:  * this method will establish a mapping in both directions between the 
 355:  * specified native and a DataFlavor whose MIME type is a decoded 
 356:  * version of the native.
 357:  */ 
 358:  public List<DataFlavor> getFlavorsForNative(String nat)
 359:  {
 360:  List<DataFlavor> ret = new ArrayList<DataFlavor>();
 361:  if (nat == null)
 362:  {
 363:  Collection<List<DataFlavor>> all = nativeToFlavorMap.values();
 364:  for (List<DataFlavor> list : all)
 365:  {
 366:  for (DataFlavor flav : list)
 367:  {
 368:  if (! ret.contains(flav))
 369:  ret.add(flav);
 370:  }
 371:  }
 372:  }
 373:  else
 374:  {
 375:  List<DataFlavor> list = nativeToFlavorMap.get(nat);
 376:  if (list != null)
 377:  ret.addAll(list);
 378:  }
 379:  return ret;
 380:  }
 381: 
 382:  public List<String> getNativesForFlavor (DataFlavor flav)
 383:  {
 384:  List<String> ret = new ArrayList<String>();
 385:  if (flav == null)
 386:  {
 387:  Collection<List<String>> all = flavorToNativeMap.values();
 388:  for (List<String> list : all)
 389:  {
 390:  for (String nat : list)
 391:  {
 392:  if (! ret.contains(nat))
 393:  ret.add(nat);
 394:  }
 395:  }
 396:  }
 397:  else
 398:  {
 399:  List<String> list = flavorToNativeMap.get(flav);
 400:  if (list != null)
 401:  ret.addAll(list);
 402:  }
 403:  return ret;
 404:  }
 405:  
 406:  /**
 407:  * Adds a mapping from a single <code>String</code> native to a single
 408:  * <code>DataFlavor</code>. Unlike <code>getFlavorsForNative</code>, the
 409:  * mapping will only be established in one direction, and the native will
 410:  * not be encoded. To establish a two-way mapping, call
 411:  * <code>addUnencodedNativeForFlavor</code> as well. The new mapping will
 412:  * be of lower priority than any existing mapping.
 413:  * This method has no effect if a mapping from the specified
 414:  * <code>String</code> native to the specified or equal
 415:  * <code>DataFlavor</code> already exists.
 416:  *
 417:  * @param nativeStr the <code>String</code> native key for the mapping
 418:  * @param flavor the <code>DataFlavor</code> value for the mapping
 419:  * @throws NullPointerException if nat or flav is <code>null</code>
 420:  *
 421:  * @see #addUnencodedNativeForFlavor
 422:  * @since 1.4
 423:  */
 424:  public synchronized void addFlavorForUnencodedNative(String nativeStr, 
 425:  DataFlavor flavor)
 426:  {
 427:  if ((nativeStr == null) || (flavor == null))
 428:  throw new NullPointerException();
 429:  List<DataFlavor> flavors = nativeToFlavorMap.get(nativeStr);
 430:  if (flavors == null) 
 431:  {
 432:  flavors = new ArrayList<DataFlavor>();
 433:  nativeToFlavorMap.put(nativeStr, flavors);
 434:  }
 435:  else
 436:  {
 437:  if (! flavors.contains(flavor))
 438:  flavors.add(flavor);
 439:  }
 440:  }
 441:  
 442:  /**
 443:  * Adds a mapping from the specified <code>DataFlavor</code> (and all
 444:  * <code>DataFlavor</code>s equal to the specified <code>DataFlavor</code>)
 445:  * to the specified <code>String</code> native.
 446:  * Unlike <code>getNativesForFlavor</code>, the mapping will only be
 447:  * established in one direction, and the native will not be encoded. To
 448:  * establish a two-way mapping, call
 449:  * <code>addFlavorForUnencodedNative</code> as well. The new mapping will 
 450:  * be of lower priority than any existing mapping.
 451:  * This method has no effect if a mapping from the specified or equal
 452:  * <code>DataFlavor</code> to the specified <code>String</code> native
 453:  * already exists.
 454:  *
 455:  * @param flavor the <code>DataFlavor</code> key for the mapping
 456:  * @param nativeStr the <code>String</code> native value for the mapping
 457:  * @throws NullPointerException if flav or nat is <code>null</code>
 458:  *
 459:  * @see #addFlavorForUnencodedNative
 460:  * @since 1.4
 461:  */
 462:  public synchronized void addUnencodedNativeForFlavor(DataFlavor flavor,
 463:  String nativeStr) 
 464:  {
 465:  if ((nativeStr == null) || (flavor == null))
 466:  throw new NullPointerException();
 467:  List<String> natives = flavorToNativeMap.get(flavor);
 468:  if (natives == null) 
 469:  {
 470:  natives = new ArrayList<String>();
 471:  flavorToNativeMap.put(flavor, natives);
 472:  }
 473:  else
 474:  {
 475:  if (! natives.contains(nativeStr))
 476:  natives.add(nativeStr);
 477:  }
 478:  }
 479:  
 480:  /**
 481:  * Discards the current mappings for the specified <code>DataFlavor</code>
 482:  * and all <code>DataFlavor</code>s equal to the specified
 483:  * <code>DataFlavor</code>, and creates new mappings to the 
 484:  * specified <code>String</code> natives.
 485:  * Unlike <code>getNativesForFlavor</code>, the mappings will only be
 486:  * established in one direction, and the natives will not be encoded. To
 487:  * establish two-way mappings, call <code>setFlavorsForNative</code>
 488:  * as well. The first native in the array will represent the highest
 489:  * priority mapping. Subsequent natives will represent mappings of
 490:  * decreasing priority.
 491:  * <p>
 492:  * If the array contains several elements that reference equal
 493:  * <code>String</code> natives, this method will establish new mappings
 494:  * for the first of those elements and ignore the rest of them.
 495:  * <p> 
 496:  * It is recommended that client code not reset mappings established by the
 497:  * data transfer subsystem. This method should only be used for
 498:  * application-level mappings.
 499:  *
 500:  * @param flavor the <code>DataFlavor</code> key for the mappings
 501:  * @param natives the <code>String</code> native values for the mappings
 502:  * @throws NullPointerException if flav or natives is <code>null</code>
 503:  * or if natives contains <code>null</code> elements
 504:  *
 505:  * @see #setFlavorsForNative
 506:  * @since 1.4
 507:  */
 508:  public synchronized void setNativesForFlavor(DataFlavor flavor,
 509:  String[] natives) 
 510:  {
 511:  if ((natives == null) || (flavor == null))
 512:  throw new NullPointerException();
 513:  
 514:  flavorToNativeMap.remove(flavor);
 515:  for (int i = 0; i < natives.length; i++) 
 516:  {
 517:  addUnencodedNativeForFlavor(flavor, natives[i]);
 518:  }
 519:  }
 520:  
 521:  /**
 522:  * Discards the current mappings for the specified <code>String</code>
 523:  * native, and creates new mappings to the specified
 524:  * <code>DataFlavor</code>s. Unlike <code>getFlavorsForNative</code>, the
 525:  * mappings will only be established in one direction, and the natives need
 526:  * not be encoded. To establish two-way mappings, call
 527:  * <code>setNativesForFlavor</code> as well. The first
 528:  * <code>DataFlavor</code> in the array will represent the highest priority
 529:  * mapping. Subsequent <code>DataFlavor</code>s will represent mappings of
 530:  * decreasing priority.
 531:  * <p>
 532:  * If the array contains several elements that reference equal
 533:  * <code>DataFlavor</code>s, this method will establish new mappings
 534:  * for the first of those elements and ignore the rest of them.
 535:  * <p>
 536:  * It is recommended that client code not reset mappings established by the
 537:  * data transfer subsystem. This method should only be used for
 538:  * application-level mappings.
 539:  *
 540:  * @param nativeStr the <code>String</code> native key for the mappings
 541:  * @param flavors the <code>DataFlavor</code> values for the mappings
 542:  * @throws NullPointerException if nat or flavors is <code>null</code>
 543:  * or if flavors contains <code>null</code> elements
 544:  *
 545:  * @see #setNativesForFlavor
 546:  * @since 1.4
 547:  */
 548:  public synchronized void setFlavorsForNative(String nativeStr,
 549:  DataFlavor[] flavors) 
 550:  {
 551:  if ((nativeStr == null) || (flavors == null))
 552:  throw new NullPointerException();
 553:  
 554:  nativeToFlavorMap.remove(nativeStr);
 555:  for (int i = 0; i < flavors.length; i++) 
 556:  {
 557:  addFlavorForUnencodedNative(nativeStr, flavors[i]);
 558:  }
 559:  }
 560: 
 561: } // class SystemFlavorMap
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /