001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * Portions Copyrighted 2007 Sun Microsystems, Inc.
027: */
028:
029: package org.netbeans.nbbuild;
030:
031: import java.awt.image.BufferedImage;
032: import java.io.BufferedWriter;
033: import java.io.File;
034: import java.io.FileWriter;
035: import java.io.IOException;
036: import java.io.InputStream;
037: import java.net.URL;
038: import java.text.MessageFormat;
039: import java.util.Set;
040: import java.util.SortedSet;
041: import java.util.TreeSet;
042: import javax.imageio.ImageIO;
043: import org.apache.tools.ant.BuildException;
044: import org.apache.tools.ant.Project;
045: import org.apache.tools.ant.Task;
046: import org.apache.tools.ant.types.FileSet;
047:
048: /**
049: *
050: * @author Jaroslav Tulach
051: */
052: public class PrintIcon extends Task {
053: private FileSet first;
054: private FileSet second;
055:
056: /** Creates a new instance of PrintIcon */
057: public PrintIcon() {
058: }
059:
060: private File duplicates;
061:
062: public void setDuplicates(File f) {
063: duplicates = f;
064: }
065:
066: private File difference;
067:
068: public void setDifference(File f) {
069: difference = f;
070: }
071:
072: /**
073: *
074: * @return
075: */
076: public FileSet createFirstPool() {
077: if (first != null) {
078: throw new BuildException();
079: }
080: first = new FileSet();
081: return first;
082: }
083:
084: public FileSet createSecondPool() {
085: if (second != null) {
086: throw new BuildException();
087: }
088: second = new FileSet();
089: return second;
090: }
091:
092: @Override
093: public void execute() throws BuildException {
094: if (first == null) {
095: throw new BuildException(
096: "You need to specify firstpool element for this task!"); // NOI18N
097: }
098:
099: try {
100:
101: SortedSet<IconInfo> firstSet = new TreeSet<IconInfo>();
102: for (String f : first.getDirectoryScanner(getProject())
103: .getIncludedFiles()) {
104: File baseDir = first.getDir(getProject());
105: File file = new File(baseDir, f);
106: firstSet.add(new IconInfo(file.toURI().toURL(),
107: getProject()));
108: }
109:
110: SortedSet<IconInfo> sndSet = new TreeSet<IconInfo>();
111: if (second != null) {
112: for (String f : second
113: .getDirectoryScanner(getProject())
114: .getIncludedFiles()) {
115: File baseDir = second.getDir(getProject());
116: File file = new File(baseDir, f);
117: sndSet.add(new IconInfo(file.toURI().toURL(),
118: getProject()));
119: }
120: }
121:
122: if (duplicates != null) {
123: Set<IconInfo> both = new TreeSet<IconInfo>(firstSet);
124: both.addAll(sndSet);
125:
126: BufferedWriter os = new BufferedWriter(new FileWriter(
127: duplicates));
128: IconInfo prev = null;
129: boolean prevPrinted = false;
130: for (IconInfo info : both) {
131: IconInfo p = prev;
132: prev = info;
133: if (p == null || p.hash != info.hash) {
134: prevPrinted = false;
135: continue;
136: }
137:
138: if (!prevPrinted) {
139: os.write(p.toString());
140: os.newLine();
141: prevPrinted = true;
142: }
143:
144: os.write(info.toString());
145: os.newLine();
146: }
147: os.close();
148: }
149: if (difference != null) {
150: SortedSet<IconInfo> union = new TreeSet<IconInfo>(
151: firstSet);
152: union.addAll(sndSet);
153:
154: BufferedWriter os = new BufferedWriter(new FileWriter(
155: difference));
156: for (IconInfo info : union) {
157: if (!contains(firstSet, info.hash)) {
158: os.write('+');
159: os.write(info.toString());
160: os.newLine();
161: continue;
162: }
163: if (!contains(sndSet, info.hash)) {
164: os.write('-');
165: os.write(info.toString());
166: os.newLine();
167: continue;
168: }
169: }
170: os.close();
171: }
172:
173: } catch (IOException ex) {
174: throw new BuildException(ex);
175: }
176:
177: }
178:
179: private static boolean contains(SortedSet<IconInfo> set,
180: int hashCode) {
181: IconInfo fake = new IconInfo("", "", hashCode);
182: Set<IconInfo> greaterOrEqual = set.tailSet(fake);
183: if (greaterOrEqual.isEmpty()) {
184: return false;
185: }
186: IconInfo first = greaterOrEqual.iterator().next();
187: return hashCode == first.hash;
188: }
189:
190: static final int hash(Throwable t) {
191: String msg = t.getMessage();
192: if (msg != null) {
193: return 7 + msg.hashCode();
194: }
195: return 5 + t.getClass().hashCode();
196: }
197:
198: private static final class IconInfo implements Comparable<IconInfo> {
199: final String name;
200: final String path;
201: final int hash;
202:
203: public IconInfo(URL from, Project p) throws IOException {
204: this .path = from.toExternalForm();
205: int last = this .path.lastIndexOf('/');
206: assert last >= 0;
207: this .name = this .path.substring(last + 1);
208:
209: p.log("Parsing " + from, Project.MSG_VERBOSE);
210: BufferedImage image;
211: int hash;
212: try {
213: InputStream is = from.openStream();
214: image = ImageIO.read(is);
215: is.close();
216: int w = image.getWidth();
217: int h = image.getHeight();
218: hash = w * 3 + h * 7;
219:
220: for (int i = 0; i < w; i++) {
221: for (int j = 0; j < h; j++) {
222: int rgb = image.getRGB(i, j);
223: hash += (rgb >> 2);
224: }
225: }
226: } catch (IOException e) {
227: p.log("Broken icon at " + from, Project.MSG_WARN);
228: hash = hash(e);
229: } catch (IndexOutOfBoundsException ex) {
230: p.log("Broken icon at " + from, Project.MSG_WARN);
231: hash = hash(ex);
232: }
233:
234: this .hash = hash;
235: }
236:
237: public IconInfo(String name, String path, int hash) {
238: this .name = name;
239: this .path = path;
240: this .hash = hash;
241: }
242:
243: @Override
244: public int hashCode() {
245: return hash;
246: }
247:
248: @Override
249: public boolean equals(Object obj) {
250: if (obj == null)
251: return false;
252: if (getClass() != obj.getClass())
253: return false;
254: final IconInfo other = (IconInfo) obj;
255:
256: if (this .path != other.path
257: && (this .path == null || !this .path
258: .equals(other.path)))
259: return false;
260: if (this .hash != other.hash)
261: return false;
262: return true;
263: }
264:
265: public int compareTo(IconInfo another) {
266: if (hash != another.hash) {
267: return hash - another.hash;
268: }
269:
270: return path.compareTo(another.path);
271: }
272:
273: public String toString() {
274: String h = Integer.toHexString(hash);
275: if (h.length() < 8) {
276: h = "00000000".substring(h.length()) + h;
277: }
278: String n = name;
279: if (n.length() < 30) {
280: n = n
281: + " ".substring(n
282: .length());
283: }
284:
285: return MessageFormat.format("{0} {1} {2}", h, n, path);
286: }
287: } // end of IconInfo
288: }
|