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: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.apisupport.project.ui.customizer;
043:
044: import java.awt.Color;
045: import java.awt.Graphics2D;
046: import java.awt.image.BufferedImage;
047: import java.io.File;
048: import java.io.IOException;
049: import java.net.URL;
050: import java.util.HashSet;
051: import java.util.Locale;
052: import java.util.Set;
053: import javax.imageio.ImageIO;
054: import javax.swing.ImageIcon;
055: import javax.swing.event.ChangeListener;
056: import org.netbeans.modules.apisupport.project.Util;
057: import org.netbeans.modules.apisupport.project.suite.BrandingSupport;
058: import org.netbeans.modules.apisupport.project.suite.BrandingSupport.BrandedFile;
059: import org.netbeans.modules.apisupport.project.suite.SuiteProjectType;
060: import org.netbeans.spi.project.support.ant.PropertyUtils;
061: import org.openide.ErrorManager;
062: import org.openide.util.ChangeSupport;
063: import org.openide.util.NbBundle;
064: import org.w3c.dom.Element;
065:
066: /**
067: *
068: * @author Radek Matous
069: */
070: public class BasicBrandingModel {
071:
072: private BrandingSupport branding;
073: private final SuiteProperties suiteProps;
074:
075: /** generated properties*/
076: public static final String NAME_PROPERTY = "app.name";//NOI18N
077: public static final String TITLE_PROPERTY = "app.title";//NOI18N
078: public static final String ICON_LOCATION_PROPERTY = "app.icon";//NOI18N
079:
080: public static final String BRANDING_TOKEN_PROPERTY = "branding.token";//NOI18N
081:
082: static final int ICON_WIDTH = 48;
083: static final int ICON_HEIGHT = 48;
084:
085: /** for generating property branding.token*/
086: private boolean brandingEnabled;
087: private boolean brandingChanged = false;
088:
089: /** for properties (app.name, app.title, app.icon)*/
090: private String name;
091: private String title;
092: private BrandingSupport.BrandedFile icon = null;
093: private BrandingSupport.BrandedFile icon16 = null;
094:
095: /** representation of bundle keys depending on app.title */
096: private BrandingSupport.BundleKey productInformation = null;
097: private BrandingSupport.BundleKey mainWindowTitle = null;
098: private BrandingSupport.BundleKey splashWindowTitle = null;
099: private BrandingSupport.BundleKey mainWindowTitleNoProject = null;
100: private BrandingSupport.BundleKey currentVersion = null;
101:
102: /** representation of bundle keys for splash section */
103: private BrandingSupport.BrandedFile splash = null;
104:
105: private BrandingSupport.BundleKey splashWidth = null;
106: private BrandingSupport.BundleKey splashHeight = null;
107: private BrandingSupport.BundleKey splashShowProgressBar = null;
108: private BrandingSupport.BundleKey splashRunningTextBounds = null;
109: private BrandingSupport.BundleKey splashProgressBarBounds = null;
110: private BrandingSupport.BundleKey splashRunningTextFontSize = null;
111: private BrandingSupport.BundleKey splashRunningTextColor = null;
112: private BrandingSupport.BundleKey splashProgressBarColor = null;
113: private BrandingSupport.BundleKey splashProgressBarEdgeColor = null;
114: private BrandingSupport.BundleKey splashProgressBarCornerColor = null;
115:
116: private final ChangeSupport changeSupport = new ChangeSupport(this );
117:
118: /**all above splash BundleKeys in set*/
119: private final Set<BrandingSupport.BundleKey> splashKeys = new HashSet<BrandingSupport.BundleKey>();
120:
121: /** Creates a new instance of ApplicationDetails */
122: public BasicBrandingModel(final SuiteProperties suiteProps) {
123: this .suiteProps = suiteProps;
124: init();
125: }
126:
127: public boolean isBrandingEnabled() {
128: return brandingEnabled;
129: }
130:
131: public void setBrandingEnabled(boolean brandingEnabled) {
132: if (this .brandingEnabled != brandingEnabled) {
133: this .brandingEnabled = brandingEnabled;
134: brandingChanged = true;
135: changeSupport.fireChange();
136: }
137: }
138:
139: public String getName() {
140: return name;
141: }
142:
143: public void setName(String name) /*throws IllegalArgumentException*/{
144: /*if (name != null && !name.matches("[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*")) { // NOI18N
145: throw new IllegalArgumentException("Malformed name: " + name); // NOI18N
146: }*/
147:
148: if (isBrandingEnabled()) {
149: this .name = name;
150: suiteProps.setProperty(NAME_PROPERTY, getName());
151: suiteProps.setProperty(BRANDING_TOKEN_PROPERTY, "${"
152: + NAME_PROPERTY + "}");//NOI18N
153: }
154: }
155:
156: public String getTitle() {
157: return title;
158: }
159:
160: public void addChangeListener(ChangeListener l) {
161: changeSupport.addChangeListener(l);
162: }
163:
164: public void removeChangeListener(ChangeListener l) {
165: changeSupport.removeChangeListener(l);
166: }
167:
168: public void setTitle(String title) {
169: if (isBrandingEnabled()) {
170: this .title = title;
171: if (productInformation != null) {
172: productInformation.setValue(title);
173: }
174: if (mainWindowTitle != null) {
175: mainWindowTitle.setValue(title + " {0}"); //NOI18N
176: }
177: if (splashWindowTitle != null) {
178: StringBuilder sb = new StringBuilder();
179: sb.append(NbBundle.getMessage(BasicBrandingModel.class,
180: "LBL_splash_window_title_prefix"));//NOI18N
181: sb.append(" ").append(title);//NOI18N
182: splashWindowTitle.setValue(sb.toString());//NOI18N
183: }
184: if (mainWindowTitleNoProject != null) {
185: mainWindowTitleNoProject.setValue(title + " {0}"); //NOI18N
186: }
187: if (currentVersion != null) {
188: currentVersion.setValue(title + " {0}"); //NOI18N
189: }
190: suiteProps.setProperty(TITLE_PROPERTY, getTitle());
191: }
192: }
193:
194: public URL getIconSource() {
195: return icon != null ? icon.getBrandingSource() : null;
196: }
197:
198: public void setIconSource(final URL url) {
199: if (isBrandingEnabled()) {
200: icon.setBrandingSource(url);
201: suiteProps.setProperty(ICON_LOCATION_PROPERTY,
202: getIconLocation());
203: }
204: }
205:
206: public String getIconLocation() {
207: File prj = suiteProps.getProjectDirectoryFile();
208: String relativePath = PropertyUtils.relativizeFile(prj, icon
209: .getFileLocation());
210:
211: return relativePath;
212: }
213:
214: public String getSplashLocation() {
215: File prj = suiteProps.getProjectDirectoryFile();
216: String relativePath = PropertyUtils.relativizeFile(prj, splash
217: .getFileLocation());
218:
219: return relativePath;
220: }
221:
222: public void store() throws IOException {
223: if (brandingEnabled) {
224: getBranding().brandBundleKey(productInformation);
225: getBranding().brandBundleKey(mainWindowTitle);
226: getBranding().brandBundleKey(splashWindowTitle);
227: getBranding().brandBundleKey(mainWindowTitleNoProject);
228: getBranding().brandBundleKey(currentVersion);
229:
230: boolean isModified = icon.isModified();
231: getBranding().brandFile(
232: icon,
233: getScaleAndStoreIconTask(icon,
234: BasicBrandingModel.ICON_WIDTH,
235: BasicBrandingModel.ICON_HEIGHT));
236:
237: if (isModified) {
238: icon16.setBrandingSource(icon.getBrandingSource());
239: getBranding().brandFile(icon16,
240: getScaleAndStoreIconTask(icon16, 16, 16));
241: }
242:
243: getBranding().brandBundleKeys(splashKeys);
244: getBranding().brandFile(splash);
245: } else {
246: if (brandingChanged) {//#115737
247: suiteProps
248: .removeProperty(BasicBrandingModel.BRANDING_TOKEN_PROPERTY);
249: suiteProps
250: .removeProperty(BasicBrandingModel.NAME_PROPERTY);
251: suiteProps
252: .removeProperty(BasicBrandingModel.TITLE_PROPERTY);
253: suiteProps
254: .removeProperty(BasicBrandingModel.ICON_LOCATION_PROPERTY);
255: }
256: }
257: }
258:
259: private static Runnable getScaleAndStoreIconTask(
260: final BrandedFile icon, final int width, final int height)
261: throws IOException {
262: return new Runnable() {
263: public void run() {
264: BufferedImage bi = new BufferedImage(width, height,
265: BufferedImage.TYPE_INT_RGB);
266:
267: Graphics2D g2 = bi.createGraphics();
268: ImageIcon image = new ImageIcon(icon
269: .getBrandingSource());
270: g2.drawImage(image.getImage(), 0, 0, width, height,
271: Color.LIGHT_GRAY, null);//NOI18N
272:
273: g2.dispose();
274: try {
275: ImageIO.write(bi, "png", icon.getFileLocation());//NOI18N
276: } catch (IOException ex) {
277: ErrorManager.getDefault().notify(ex);
278: }
279: }
280: };
281: }
282:
283: private BrandingSupport getBranding() {
284: if (branding == null) {
285: try {
286: branding = BrandingSupport.getInstance(suiteProps);
287: } catch (IOException ex) {
288: ErrorManager.getDefault().notify(ex);
289: throw new IllegalStateException(ex
290: .getLocalizedMessage());
291: }
292: }
293: return branding;
294: }
295:
296: private void init() {
297: initBundleKeys();
298: initName(false);
299: initTitle(false);
300: brandingEnabledRefresh();
301: brandingChanged = false;
302: }
303:
304: void brandingEnabledRefresh() {
305: brandingEnabled = (suiteProps
306: .getProperty(BRANDING_TOKEN_PROPERTY) != null);
307: }
308:
309: private String getSimpleName() {
310: Element nameEl = Util.findElement(suiteProps.getProject()
311: .getHelper().getPrimaryConfigurationData(true), "name",
312: SuiteProjectType.NAMESPACE_SHARED); // NOI18N
313: String text = (nameEl != null) ? Util.findText(nameEl) : null;
314: return (text != null) ? text : "???"; // NOI18N
315: }
316:
317: void initName(boolean reread) {
318: if (name == null || reread) {
319: name = suiteProps.getProperty(NAME_PROPERTY);
320: }
321:
322: if (name == null) {
323: name = getSimpleName().toLowerCase(Locale.ENGLISH)
324: .replaceAll("[^a-z0-9]", "_"); // NOI18N
325: if (!name.matches("[a-z][a-z0-9]*(_[a-z][a-z0-9]*)*")) { // NOI18N
326: // Too far from a decent name, forget it.
327: name = "app"; // NOI18N
328: }
329: }
330:
331: assert name != null;
332: }
333:
334: void initTitle(boolean reread) {
335: if (title == null || reread) {
336: String initTitle = suiteProps.getProperty(TITLE_PROPERTY);
337:
338: if (initTitle == null) {
339: initTitle = getSimpleName();
340: // Just make a rough attempt to uppercase it, to hint that it can be a display name.
341: if (Character.isLowerCase(initTitle.charAt(0))) {
342: initTitle = String.valueOf(Character
343: .toLowerCase(initTitle.charAt(0)))
344: + initTitle.substring(1);
345: }
346: }
347: assert initTitle != null;
348: title = initTitle;
349: }
350: }
351:
352: private void initBundleKeys() {
353: productInformation = getBranding().getBundleKey(
354: "org.netbeans.core",//NOI18N
355: "org/netbeans/core/ui/Bundle.properties",//NOI18N
356: "LBL_ProductInformation");//NOI18N
357:
358: mainWindowTitle = getBranding().getBundleKey(
359: "org.netbeans.core.windows",//NOI18N
360: "org/netbeans/core/windows/view/ui/Bundle.properties", // NOI18N
361: "CTL_MainWindow_Title");//NOI18N
362:
363: splashWindowTitle = getBranding().getBundleKey(
364: "org.netbeans.core.startup",//NOI18N
365: "org/netbeans/core/startup/Bundle.properties",//NOI18N
366: "LBL_splash_window_title");//NOI18N
367:
368: mainWindowTitleNoProject = getBranding().getBundleKey(
369: "org.netbeans.core.windows",//NOI18N
370: "org/netbeans/core/windows/view/ui/Bundle.properties",//NOI18N
371: "CTL_MainWindow_Title_No_Project");//NOI18N
372:
373: currentVersion = getBranding().getBundleKey(
374: "org.netbeans.core.startup",//NOI18N
375: "org/netbeans/core/startup/Bundle.properties",//NOI18N
376: "currentVersion");//NOI18N
377:
378: icon = getBranding().getBrandedFile(
379: "org.netbeans.core.startup",//NOI18N
380: "org/netbeans/core/startup/frame48.gif");//NOI18N
381:
382: icon16 = getBranding().getBrandedFile(
383: "org.netbeans.core.startup",//NOI18N
384: "org/netbeans/core/startup/frame.gif");//NOI18N
385:
386: splash = getBranding().getBrandedFile(
387: "org.netbeans.core.startup",//NOI18N
388: "org/netbeans/core/startup/splash.gif");//NOI18N
389:
390: // init of splash keys
391:
392: splashWidth = getBranding().getBundleKey(
393: "org.netbeans.core.startup",//NOI18N
394: "org/netbeans/core/startup/Bundle.properties",//NOI18N
395: "SPLASH_WIDTH");//NOI18N
396:
397: splashHeight = getBranding().getBundleKey(
398: "org.netbeans.core.startup",//NOI18N
399: "org/netbeans/core/startup/Bundle.properties",//NOI18N
400: "SPLASH_HEIGHT");//NOI18N
401:
402: splashShowProgressBar = getBranding().getBundleKey(
403: "org.netbeans.core.startup",//NOI18N
404: "org/netbeans/core/startup/Bundle.properties",//NOI18N
405: "SplashShowProgressBar");//NOI18N
406:
407: splashRunningTextFontSize = getBranding().getBundleKey(
408: "org.netbeans.core.startup",//NOI18N
409: "org/netbeans/core/startup/Bundle.properties",//NOI18N
410: "SplashRunningTextFontSize");//NOI18N
411:
412: splashProgressBarBounds = getBranding().getBundleKey(
413: "org.netbeans.core.startup",//NOI18N
414: "org/netbeans/core/startup/Bundle.properties",//NOI18N
415: "SplashProgressBarBounds");//NOI18N
416:
417: splashRunningTextBounds = getBranding().getBundleKey(
418: "org.netbeans.core.startup",//NOI18N
419: "org/netbeans/core/startup/Bundle.properties",//NOI18N
420: "SplashRunningTextBounds");//NOI18N
421:
422: splashRunningTextColor = getBranding().getBundleKey(
423: "org.netbeans.core.startup",//NOI18N
424: "org/netbeans/core/startup/Bundle.properties",//NOI18N
425: "SplashRunningTextColor");//NOI18N
426:
427: splashProgressBarColor = getBranding().getBundleKey(
428: "org.netbeans.core.startup",//NOI18N
429: "org/netbeans/core/startup/Bundle.properties",//NOI18N
430: "SplashProgressBarColor");//NOI18N
431:
432: splashProgressBarEdgeColor = getBranding().getBundleKey(
433: "org.netbeans.core.startup",//NOI18N
434: "org/netbeans/core/startup/Bundle.properties",//NOI18N
435: "SplashProgressBarEdgeColor");//NOI18N
436:
437: splashProgressBarCornerColor = getBranding().getBundleKey(
438: "org.netbeans.core.startup",//NOI18N
439: "org/netbeans/core/startup/Bundle.properties",//NOI18N
440: "SplashProgressBarCornerColor");//NOI18N
441:
442: splashKeys.clear();
443:
444: if (splashWidth != null) {
445: splashKeys.add(splashWidth);
446: }
447: if (splashHeight != null) {
448: splashKeys.add(splashHeight);
449: }
450: if (splashShowProgressBar != null) {
451: splashKeys.add(splashShowProgressBar);
452: }
453: if (splashRunningTextBounds != null) {
454: splashKeys.add(splashRunningTextBounds);
455: }
456: if (splashProgressBarBounds != null) {
457: splashKeys.add(splashProgressBarBounds);
458: }
459: if (splashRunningTextFontSize != null) {
460: splashKeys.add(splashRunningTextFontSize);
461: }
462: if (splashRunningTextColor != null) {
463: splashKeys.add(splashRunningTextColor);
464: }
465: if (splashProgressBarColor != null) {
466: splashKeys.add(splashProgressBarColor);
467: }
468: if (splashProgressBarEdgeColor != null) {
469: splashKeys.add(splashProgressBarEdgeColor);
470: }
471: if (splashProgressBarCornerColor != null) {
472: splashKeys.add(splashProgressBarCornerColor);
473: }
474: splashKeys.remove(null);
475: }
476:
477: public BrandingSupport.BundleKey getSplashWidth() {
478: return splashWidth;
479: }
480:
481: public BrandingSupport.BundleKey getSplashHeight() {
482: return splashHeight;
483: }
484:
485: public BrandingSupport.BundleKey getSplashShowProgressBar() {
486: return splashShowProgressBar;
487: }
488:
489: public BrandingSupport.BundleKey getSplashRunningTextBounds() {
490: return splashRunningTextBounds;
491: }
492:
493: public BrandingSupport.BundleKey getSplashProgressBarBounds() {
494: return splashProgressBarBounds;
495: }
496:
497: public BrandingSupport.BundleKey getSplashRunningTextFontSize() {
498: return splashRunningTextFontSize;
499: }
500:
501: public BrandingSupport.BundleKey getSplashRunningTextColor() {
502: return splashRunningTextColor;
503: }
504:
505: public BrandingSupport.BundleKey getSplashProgressBarColor() {
506: return splashProgressBarColor;
507: }
508:
509: public BrandingSupport.BundleKey getSplashProgressBarEdgeColor() {
510: return splashProgressBarEdgeColor;
511: }
512:
513: public BrandingSupport.BundleKey getSplashProgressBarCornerColor() {
514: return splashProgressBarCornerColor;
515: }
516:
517: public BrandingSupport.BrandedFile getSplash() {
518: return splash;
519: }
520: }
|