package com.googlecode.ant_deb_task; import org.apache.tools.ant.*; import org.apache.tools.ant.types.EnumeratedAttribute; import java.io.*; import java.util.*; /** * Task that generates a desktop entry file used to add menu entries. * * @antTaskName desktopentry */ public class DesktopEntry extends Task { private Properties _categories = new Properties (); private Properties _keys = new Properties (); private File _toFile; private Map _entries; private List _localizedEntries = new ArrayList (); private static final Set VALID_ONLY_SHOW_IN = new HashSet ( Arrays.asList (new String[] {"GNOME", "KDE", "ROX", "XFCE", "Old", "Unity", "LXDE", "MATE", "Cinnamon"})); public static class LocalizedEntry { private String _key; private String _lang; private String _country; private String _encoding; private String _modifier; private String _value; public LocalizedEntry (String key) { _key = key; } public void setLang (String lang) { _lang = lang; } public void setCountry (String country) { _country = country; } public void setEncoding (String encoding) { _encoding = encoding; } public void setModifier (String modifier) { _modifier = modifier; } public void setValue (String value) { _value = value; } public String toString() { StringBuffer buffer = new StringBuffer (_key); if (_lang != null) { buffer.append ('['); buffer.append (_lang.toLowerCase ()); if (_country != null) { buffer.append ('_'); buffer.append (_country.toUpperCase ()); } if (_encoding != null) { buffer.append ('.'); buffer.append (_encoding); } if (_modifier != null) { buffer.append ('@'); buffer.append (_modifier); } buffer.append (']'); } return buffer.toString (); } public String getValue () { return _value; } } public static class Name extends LocalizedEntry { public Name () { super ("Name"); } } public static class GenericName extends LocalizedEntry { public GenericName () { super ("GenericName"); } } public static class Comment extends LocalizedEntry { public Comment () { super ("Comment"); } } public static class Icon extends LocalizedEntry { public Icon () { super ("Icon"); } } public static class Type extends EnumeratedAttribute { public String[] getValues () { return new String[] {"Application", "Link", "Directory"}; } } /** * The file where the desktop entry will be generated. The file name extension should be .desktop. * * @param toFile The file name, if exisits it will be overwritten. * @antTaskParamRequired true */ public void setToFile(File toFile) { _toFile = toFile; } public void setType (Type type) { String typeValue = type.getValue(); _entries.put("Type", typeValue); if (!typeValue.equals("Application")) _entries.remove("Terminal"); } public void setName(String name) { _entries.put("Name", name); } public void setGenericName(String genericName) { _entries.put("GenericName", genericName); } public void setNoDisplay(boolean noDisplay) { _entries.put("NoDisplay", noDisplay ? "true" : "false"); } public void setComment(String comment) { _entries.put("Comment", comment); } public void setIcon(String icon) { _entries.put("Icon", icon); } public void setOnlyShowIn(String onlyShowIn) { if (_entries.containsKey ("NotShowIn")) throw new BuildException("Only one of either OnlyShowIn or NotShowIn can be set!"); String [] categories = onlyShowIn.split (";"); for (int i = 0; i < categories.length; i++) { String category = categories[i]; if (!VALID_ONLY_SHOW_IN.contains (category)) throw new BuildException(category + " is not a valid OnlyShowIn category!"); } _entries.put("OnlyShowIn", onlyShowIn); } public void setNotShowIn(String notShowIn) { if (_entries.containsKey ("OnlyShowIn")) throw new BuildException("Only one of either OnlyShowIn or NotShowIn can be set!"); String [] categories = notShowIn.split (";"); for (int i = 0; i < categories.length; i++) { String category = categories[i]; if (!VALID_ONLY_SHOW_IN.contains (category)) throw new BuildException(category + " is not a valid NotShowIn category!"); } _entries.put("NotShowIn", notShowIn); } public void setTryExec(String tryExec) { _entries.put("TryExec", tryExec); } public void setExec(String exec) { _entries.put("Exec", exec); } public void setPath(String path) { _entries.put("Path", path); } public void setTerminal(boolean terminal) { _entries.put("Terminal", terminal ? "true" : "false"); } public void setMimeType(String mimeType) { _entries.put("MimeType", mimeType); } public void setCategories(String categories) { validateCategories (categories); _entries.put("Categories", categories); } public void setUrl(String url) { _entries.put("URL", url); } public void addName(DesktopEntry.Name name) { _localizedEntries.add (name); } public void addGenericName(GenericName genericName) { _localizedEntries.add (genericName); } public void addComment(Comment comment) { _localizedEntries.add (comment); } public void addIcon(Icon icon) { _localizedEntries.add (icon); } public void init() throws BuildException { _entries = new LinkedHashMap(); _entries.put("Version", "1.0"); _entries.put("Type", "Application"); _entries.put("Terminal", "false"); try { InputStream categoriesStream = getClass ().getResourceAsStream ("DesktopEntryCategories.properties"); _categories.load (categoriesStream); log ("Loaded " + _categories.size () + " properties from DesktopEntryCategories", Project.MSG_VERBOSE); InputStream keysStream = getClass ().getResourceAsStream ("DesktopEntryKeys.properties"); _keys.load (keysStream); log ("Loaded " + _keys.size () + " properties from DesktopEntryKeys", Project.MSG_VERBOSE); } catch (Exception e) { throw new BuildException("Cannot load properties file!", e); } } public void execute() throws BuildException { try { _toFile.getParentFile().mkdirs(); log ("Generating desktop entry to: " + _toFile.getAbsolutePath ()); for (int i = 0; i < _localizedEntries.size (); i++) { LocalizedEntry localizedEntry = (LocalizedEntry) _localizedEntries.get (i); _entries.put (localizedEntry.toString (), localizedEntry.getValue ()); } validateKeys (); PrintWriter out = new UnixPrintWriter(_toFile); out.println("[Desktop Entry]"); Iterator keys = _entries.keySet().iterator(); while (keys.hasNext()) { String key = (String) keys.next(); String value = (String) _entries.get(key); out.print(key); out.print('='); out.println(value); } out.close(); } catch (FileNotFoundException e) { throw new BuildException(e); } } private void validateCategories(String categories) { int mainCnt = 0; Set categorySet = new HashSet (Arrays.asList (categories.split (";"))); for (Iterator iterator = categorySet.iterator (); iterator.hasNext ();) { String category = (String) iterator.next (); String type = _categories.getProperty ("category." + category); if (type == null) throw new BuildException("Unknown category: " + category); if ("main".equals (type)) mainCnt++; String require = _categories.getProperty ("category." + category + ".require"); if (require != null) { if (!categorySet.contains (require)) throw new BuildException("Category " + category + " also requires " + require); } else { require = _categories.getProperty ("category." + category + ".require.and"); if (require != null) { String [] requireAnd = require.split (";"); for (int j = 0; j < requireAnd.length; j++) { if (!categorySet.contains (requireAnd[j])) throw new BuildException("Category " + category + " also requires " + requireAnd[j]); } } else { require = _categories.getProperty ("category." + category + ".require.or"); if (require != null) { boolean found = false; String [] requireOr = require.split (";"); for (int j = 0; j < requireOr.length; j++) { if (categorySet.contains (requireOr[j])) { found = true; break; } } if (!found) throw new BuildException("Category " + category + " also requires one of " + require); } } } } if (mainCnt == 0) throw new BuildException ("At least one main category should be specified!"); if (mainCnt > 1) log ("Multiple main categories specified, the entry may appear under multiple menus!"); } private void validateKeys() { String type = (String) _entries.get ("Type"); Iterator keys = _entries.keySet ().iterator (); while (keys.hasNext ()) { String key = (String) keys.next (); if ("Type".equals (key)) continue; int idxSquare = key.indexOf ('['); if (idxSquare != -1) { String baseKey = key.substring (0, idxSquare); if (!_entries.containsKey (baseKey)) throw new BuildException ("Unlocalized key " + baseKey + " also needed for " + key); continue; } boolean found = false; String [] typeArr = _keys.getProperty ("key." + key).split (","); for (int i = 0; i < typeArr.length; i++) { String allowedType = typeArr[i]; if (type.equals (allowedType)) { found = true; break; } } if (!found) throw new BuildException("Key " + key + " not allowed for desktop entry of type " + type); } Iterator propertyKeys = _keys.keySet ().iterator (); while (propertyKeys.hasNext ()) { String property = (String) propertyKeys.next (); if (property.endsWith (".required")) { String [] requiredTypeArr = _keys.getProperty (property).split (","); for (int i = 0; i < requiredTypeArr.length; i++) { String requiredType = requiredTypeArr[i]; if (type.equals (requiredType)) { String key = property.substring (4, property.length () - 9); if (!_entries.containsKey (key)) throw new BuildException("Key " + key + " is required for desktop entries of type " + type); break; } } } } } }