1 /* 2 * ResourceAction.js 3 * 4 * Sweet Home 3D, Copyright (c) 2024 Space Mushrooms <info@sweethome3d.com> 5 * 6 * This program 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 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 // Requires graphics2d.js 22 // Requires UserPreferences.js 23 // Requires URLContent.js 24 25 /** 26 * Creates an action with properties retrieved from a resource bundle 27 * in which key starts with <code>actionPrefix</code>. 28 * @param {UserPreferences} preferences user preferences used to retrieve localized description of the action 29 * @param {Object} resourceClass the class used as a context to retrieve localized properties of the action 30 * @param {string} actionPrefix prefix used in resource bundle to search action properties 31 * @param {boolean} [enabled] <code>true</code> if the action should be enabled at creation 32 * @param {Object} controller the controller object holding the method to invoke 33 * @param {string} controllerMethod the controller method to invoke 34 * @param {Object[]} parameters action parameters 35 * @constructor 36 * @extends AbstractAction 37 * @ignore 38 * @author Emmanuel Puybaret 39 */ 40 function ResourceAction(preferences, resourceClass, actionPrefix, enabled, controller, controllerMethod, parameters) { 41 AbstractAction.call(this); 42 if (enabled === undefined) { 43 parameters = controllerMethod; 44 controllerMethod = controller; 45 controller = enabled; 46 enabled = false; 47 } 48 this.putValue(ResourceAction.RESOURCE_CLASS, resourceClass); 49 this.putValue(ResourceAction.RESOURCE_PREFIX, actionPrefix); 50 this.putValue(ResourceAction.VISIBLE, true); 51 this.readActionProperties(preferences, resourceClass, actionPrefix); 52 this.setEnabled(enabled); 53 this.controller = controller; 54 this.controllerMethod = controllerMethod; 55 this.parameters = parameters; 56 var resourceAction = this; 57 preferences.addPropertyChangeListener("LANGUAGE", { 58 propertyChange : function(ev) { 59 if (resourceAction == null) { 60 (ev.getSource()).removePropertyChangeListener("LANGUAGE", this); 61 } else { 62 resourceAction.readActionProperties(ev.getSource(), 63 resourceAction.getValue(ResourceAction.RESOURCE_CLASS), resourceAction.getValue(ResourceAction.RESOURCE_PREFIX)); 64 } 65 } 66 }); 67 return this; 68 }; 69 ResourceAction.prototype = Object.create(AbstractAction.prototype); 70 ResourceAction.prototype.constructor = ResourceAction; 71 72 /** 73 * Other property keys for Sweet Home 3D. 74 */ 75 ResourceAction.RESOURCE_CLASS = "ResourceClass"; 76 ResourceAction.RESOURCE_PREFIX = "ResourcePrefix"; 77 ResourceAction.VISIBLE = "Visible"; 78 ResourceAction.POPUP = "Popup"; 79 ResourceAction.TOGGLE_BUTTON_GROUP = "ToggleButtonGroup"; 80 ResourceAction.TOOL_BAR_ICON = "ToolBarIcon"; 81 82 /** 83 * Reads from the properties of this action. 84 * @param {UserPreferences} preferences 85 * @param {Object} resourceClass 86 * @param {string} actionPrefix 87 * @private 88 */ 89 ResourceAction.prototype.readActionProperties = function(preferences, resourceClass, actionPrefix) { 90 var propertyPrefix = actionPrefix + "."; 91 this.putValue(AbstractAction.NAME, this.getOptionalString(preferences, resourceClass, propertyPrefix + AbstractAction.NAME, true)); 92 this.putValue(AbstractAction.DEFAULT, this.getValue(AbstractAction.NAME)); 93 this.putValue(ResourceAction.POPUP, this.getOptionalString(preferences, resourceClass, propertyPrefix + ResourceAction.POPUP, true)); 94 this.putValue(AbstractAction.SHORT_DESCRIPTION, this.getOptionalString(preferences, resourceClass, propertyPrefix + AbstractAction.SHORT_DESCRIPTION, false)); 95 this.putValue(AbstractAction.LONG_DESCRIPTION, this.getOptionalString(preferences, resourceClass, propertyPrefix + AbstractAction.LONG_DESCRIPTION, false)); 96 var smallIcon = this.getOptionalString(preferences, resourceClass, propertyPrefix + AbstractAction.SMALL_ICON, false); 97 if (smallIcon != null) { 98 this.putValue(AbstractAction.SMALL_ICON, smallIcon); 99 } 100 var toolBarIcon = this.getOptionalString(preferences, resourceClass, propertyPrefix + ResourceAction.TOOL_BAR_ICON, false); 101 if (toolBarIcon != null) { 102 this.putValue(ResourceAction.TOOL_BAR_ICON, toolBarIcon); 103 } 104 var propertyKey = propertyPrefix + AbstractAction.ACCELERATOR_KEY; 105 var acceleratorKey = this.getOptionalString(preferences, resourceClass, propertyKey + "." + OperatingSystem.getName(), false); 106 if (acceleratorKey == null) { 107 acceleratorKey = this.getOptionalString(preferences, resourceClass, propertyKey, false); 108 } 109 if (acceleratorKey != null) { 110 this.putValue(AbstractAction.ACCELERATOR_KEY, acceleratorKey); 111 } 112 var mnemonicKey = this.getOptionalString(preferences, resourceClass, propertyPrefix + AbstractAction.MNEMONIC_KEY, false); 113 if (mnemonicKey != null) { 114 this.putValue(AbstractAction.MNEMONIC_KEY, mnemonicKey); 115 } 116 } 117 118 /** 119 * Returns the value of <code>propertyKey</code> in <code>preferences</code>, 120 * or <code>null</code> if the property doesn't exist. 121 * @param {UserPreferences} preferences 122 * @param {Object} resourceClass 123 * @param {string} propertyKey 124 * @param {boolean} label 125 * @return {string} 126 * @private 127 */ 128 ResourceAction.prototype.getOptionalString = function(preferences, resourceClass, propertyKey, label) { 129 try { 130 var localizedText = label 131 ? ResourceAction.getLocalizedLabelText(preferences, resourceClass, propertyKey) 132 : preferences.getLocalizedString(resourceClass, propertyKey); 133 if (localizedText != null && localizedText.length > 0) { 134 return localizedText; 135 } else { 136 return null; 137 } 138 } catch (ex) { 139 return null; 140 } 141 } 142 143 /** 144 * Returns a localized text for menus items and labels depending on the system. 145 * @param {UserPreferences} preferences 146 * @param {Object} resourceClass 147 * @param {string} resourceKey 148 * @param {Array} resourceParameters 149 * @return {string} 150 * @private 151 */ 152 ResourceAction.getLocalizedLabelText = function(preferences, resourceClass, resourceKey, resourceParameters) { 153 var localizedString = preferences.getLocalizedString(resourceClass, resourceKey, resourceParameters); 154 var language = Locale.getDefault(); 155 if (/* OperatingSystem.isMacOSX() 156 && */ (language.indexOf("zh") == 0 // CHINESE 157 || language.indexOf("ja") == 0 // JAPANESE 158 || language.indexOf("ko") == 0 // KOREAN 159 || language.indexOf("uk") == 0)) { // Ukrainian 160 var openingBracketIndex = localizedString.indexOf('('); 161 if (openingBracketIndex !== -1) { 162 var closingBracketIndex = localizedString.indexOf(')'); 163 if (openingBracketIndex === closingBracketIndex - 2) { 164 var c = localizedString.charAt(openingBracketIndex + 1); 165 if (c >= 'A' && c <= 'Z') { 166 localizedString = localizedString.substring(0, openingBracketIndex) 167 + localizedString.substring(closingBracketIndex + 1); 168 } 169 } 170 } 171 } 172 return localizedString; 173 } 174 175 /** 176 * Returns the URL of the given key for a key matching a URL like an icon. 177 * @param {string} propertyKey 178 */ 179 ResourceAction.prototype.getURL = function(propertyKey) { 180 var url = this.getValue(propertyKey); 181 if (url != null && url.indexOf("://") === -1) { 182 url = ZIPTools.getScriptFolder() + url; 183 } 184 return url; 185 } 186 187 /** 188 * Calls the method on the controller given in constructor. 189 * Unsupported operation. Subclasses should override this method if they want 190 * to associate a real action to this class. 191 * @param {java.awt.event.ActionEvent} ev 192 */ 193 ResourceAction.prototype.actionPerformed = function(ev) { 194 if (this.controller != null && this.controllerMethod != null) { 195 return this.controller[this.controllerMethod].apply(this.controller, this.parameters); 196 } else { 197 AbstractAction.prototype.actionPerformed.call(this, ev); 198 } 199 } 200