blob: 9cd2b9a3dcc5c5463085cc30827a1fdf009b17ff [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.editor.indent.project;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JSpinner;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.api.editor.settings.SimpleValueNames;
import org.netbeans.api.options.OptionsDisplayer;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.editor.indent.api.IndentUtils;
import org.netbeans.modules.editor.indent.project.api.Customizers;
import org.netbeans.modules.editor.settings.storage.api.EditorSettings;
import org.netbeans.modules.editor.settings.storage.api.EditorSettingsStorage;
import org.netbeans.modules.editor.settings.storage.spi.TypedValue;
import org.netbeans.modules.options.editor.spi.PreferencesCustomizer;
import org.netbeans.modules.options.indentation.CustomizerSelector;
import org.netbeans.modules.options.indentation.FormattingPanel;
import org.netbeans.modules.options.indentation.FormattingPanelController;
import org.netbeans.modules.options.indentation.ProxyPreferences;
import org.netbeans.spi.project.ui.support.ProjectChooser;
import org.netbeans.spi.project.ui.support.ProjectCustomizer;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.Mutex.ExceptionAction;
import org.openide.util.NbBundle;
/**
*
* @author Dusan Balek
*/
public final class FormattingCustomizerPanel extends javax.swing.JPanel implements ActionListener, HelpCtx.Provider {
// ------------------------------------------------------------------------
// ProjectCustomizer.CompositeCategoryProvider implementation
// ------------------------------------------------------------------------
/**
* Creates an instance of the 'Formatting' category in the project properties dialog.
* This method is meant to be used from XML layers by modules that wish to add
* the 'Formatting' category to their project type's properties dialog.
*
* <p>The method recognizes 'allowedMimeTypes' XML layer attribute, which should
* contain the comma separated list of mime types, which formatting settings
* customizers should be made available for the project. If the attribute is
* not specified all registered customizers are shown. If the attribute specifies
* an empty list only the 'All Languages' customizer is shown.
*
* @param attrs The map of <code>FileObject</code> attributes
*
* @return A new 'Formatting' category provider.
* @since 1.0
* @deprecated Use {@link Customizers#createFormattingCategoryProvider(java.util.Map) } instead.
*/
@Deprecated
public static ProjectCustomizer.CompositeCategoryProvider createCategoryProvider(Map attrs) {
return Customizers.createFormattingCategoryProvider(attrs);
}
public static class Factory implements ProjectCustomizer.CompositeCategoryProvider {
private static final String CATEGORY_FORMATTING = "Formatting"; // NOI18N
private final String allowedMimeTypes;
public Factory() {
this(null);
}
public Factory(String allowedMimeTypes) {
this.allowedMimeTypes = allowedMimeTypes;
}
public ProjectCustomizer.Category createCategory(Lookup context) {
return context.lookup(Project.class) == null ? null : ProjectCustomizer.Category.create(
CATEGORY_FORMATTING,
NbBundle.getMessage(Factory.class, "LBL_CategoryFormatting"), //NOI18N
null);
}
public JComponent createComponent(ProjectCustomizer.Category category, Lookup context) {
FormattingCustomizerPanel customizerPanel = new FormattingCustomizerPanel(context, allowedMimeTypes);
category.setStoreListener(customizerPanel);
return customizerPanel;
}
} // End of Factory class
// ------------------------------------------------------------------------
// ActionListener implementation
// ------------------------------------------------------------------------
// this is called when OK button is clicked to store the controlled preferences
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public @Override void run() {
if (DEFAULT_PROFILE.equals(pf.getPreferences("").parent().get(USED_PROFILE, DEFAULT_PROFILE))) { //NOI18N
// no per-project formatting settings
Preferences p = ProjectUtils.getPreferences(pf.getProject(), IndentUtils.class, true);
try {
removeAllKidsAndKeys(p);
} catch (BackingStoreException bse) {
LOG.log(Level.WARNING, null, bse);
}
} else {
pf.applyChanges();
// Find mimeTypes that do not have a customizer
Set<String> mimeTypes = new HashSet<String>(EditorSettings.getDefault().getAllMimeTypes());
mimeTypes.removeAll(selector.getMimeTypes());
// and make sure that they do NOT override basic settings from All Languages
Preferences p = ProjectUtils.getPreferences(pf.getProject(), IndentUtils.class, true);
for(String mimeType : mimeTypes) {
try {
p.node(mimeType).removeNode();
} catch (BackingStoreException bse) {
LOG.log(Level.WARNING, null, bse);
}
}
}
// XXX: just use whatever value, it's ignored anyway, this is here in order
// to fire property change events on documents, which are then intercepted by
// the new view hierarchy (DocumentView)
JTextComponent lastFocused = EditorRegistry.lastFocusedComponent();
if (lastFocused != null) {
lastFocused.getDocument().putProperty(SimpleValueNames.TEXT_LINE_WRAP, ""); //NOI18N
lastFocused.getDocument().putProperty(SimpleValueNames.TAB_SIZE, ""); //NOI18N
lastFocused.getDocument().putProperty(SimpleValueNames.TEXT_LIMIT_WIDTH, ""); //NOI18N
}
for(JTextComponent jtc : EditorRegistry.componentList()) {
if (lastFocused == null || lastFocused != jtc) {
jtc.getDocument().putProperty(SimpleValueNames.TEXT_LINE_WRAP, ""); //NOI18N
jtc.getDocument().putProperty(SimpleValueNames.TAB_SIZE, ""); //NOI18N
jtc.getDocument().putProperty(SimpleValueNames.TEXT_LIMIT_WIDTH, ""); //NOI18N
}
}
}
});
}
public HelpCtx getHelpCtx() {
return new HelpCtx( FormattingCustomizerPanel.class );
}
// ------------------------------------------------------------------------
// private implementation
// ------------------------------------------------------------------------
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
group = new javax.swing.ButtonGroup();
globalButton = new javax.swing.JRadioButton();
editGlobalButton = new javax.swing.JButton();
projectButton = new javax.swing.JRadioButton();
loadButton = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
customizerPanel = new javax.swing.JPanel();
group.add(globalButton);
org.openide.awt.Mnemonics.setLocalizedText(globalButton, org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "LBL_FormattingCustomizer_Global")); // NOI18N
globalButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
globalButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(editGlobalButton, org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "LBL_FormattingCustomizer_EditGlobal")); // NOI18N
editGlobalButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editGlobalButtonActionPerformed(evt);
}
});
group.add(projectButton);
org.openide.awt.Mnemonics.setLocalizedText(projectButton, org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "LBL_FormattingCustomizer_Project")); // NOI18N
projectButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
projectButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(loadButton, org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "LBL_ForamttingCustomizer_Load")); // NOI18N
loadButton.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
loadButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
loadButtonActionPerformed(evt);
}
});
jScrollPane1.setBorder(null);
customizerPanel.setLayout(new java.awt.BorderLayout());
jScrollPane1.setViewportView(customizerPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(projectButton, javax.swing.GroupLayout.DEFAULT_SIZE, 373, Short.MAX_VALUE)
.addComponent(globalButton, javax.swing.GroupLayout.DEFAULT_SIZE, 339, Short.MAX_VALUE))
.addGap(14, 14, 14)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(editGlobalButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(loadButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addComponent(jScrollPane1)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(globalButton)
.addComponent(editGlobalButton))
.addGap(8, 8, 8)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(projectButton)
.addComponent(loadButton))
.addGap(12, 12, 12)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE))
);
globalButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "FormattingCustomizerPanel.globalButton.AccessibleContext.accessibleDescription")); // NOI18N
editGlobalButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "FormattingCustomizerPanel.editGlobalButton.AccessibleContext.accessibleDescription")); // NOI18N
projectButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "FormattingCustomizerPanel.projectButton.AccessibleContext.accessibleDescription")); // NOI18N
loadButton.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FormattingCustomizerPanel.class, "FormattingCustomizerPanel.loadButton.AccessibleContext.accessibleDescription")); // NOI18N
}// </editor-fold>//GEN-END:initComponents
private void globalButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_globalButtonActionPerformed
NotifyDescriptor d = new NotifyDescriptor.Confirmation(
NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_use_global_settings_confirmation"), //NOI18N
NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_use_global_settings_confirmation_title"), //NOI18N
NotifyDescriptor.OK_CANCEL_OPTION
);
if (DialogDisplayer.getDefault().notify(d) == NotifyDescriptor.OK_OPTION) {
pf.getPreferences("").parent().put(USED_PROFILE, DEFAULT_PROFILE); //NOI18N
loadButton.setEnabled(false);
setEnabled(jScrollPane1, false);
} else {
projectButton.setSelected(true);
}
}//GEN-LAST:event_globalButtonActionPerformed
private void projectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_projectButtonActionPerformed
pf.getPreferences("").parent().put(USED_PROFILE, PROJECT_PROFILE); //NOI18N
loadButton.setEnabled(true);
setEnabled(jScrollPane1, true);
if (copyOnFork) {
copyOnFork = false;
// copy global settings
EditorSettingsStorage<String, TypedValue> storage = EditorSettingsStorage.<String, TypedValue>get("Preferences"); //NOI18N
for(String mimeType : selector.getMimeTypes()) {
Map<String, TypedValue> mimePathLocalPrefs;
try {
mimePathLocalPrefs = storage.load(MimePath.parse(mimeType), null, false);
} catch (IOException ioe) {
LOG.log(Level.WARNING, null, ioe);
continue;
}
Preferences projectPrefs = pf.getPreferences(mimeType);
// XXX: we should somehow be able to determine __all__ the formatting settings
// for each mime type, but there can be different sets of settings for different
// mime types (eg. all java, ruby and C++ have different formatting settings).
// The only way is to stash all formatting settings under one common Preferences node
// as it is in projects. The problem is that MimeLookup's Preferences implementation
// does not support subnodes.
// So, we at least copy the basic setting
boolean copied = false;
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.EXPAND_TABS);
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.INDENT_SHIFT_WIDTH);
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.SPACES_PER_TAB);
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.TAB_SIZE);
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.TEXT_LIMIT_WIDTH);
copied |= copyValueIfExists(mimePathLocalPrefs, projectPrefs, SimpleValueNames.TEXT_LINE_WRAP);
if (mimeType.length() > 0 && copied) {
projectPrefs.putBoolean(FormattingPanelController.OVERRIDE_GLOBAL_FORMATTING_OPTIONS, true);
}
}
}
}//GEN-LAST:event_projectButtonActionPerformed
private void loadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonActionPerformed
JFileChooser chooser = ProjectChooser.projectChooser();
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File f = FileUtil.normalizeFile(chooser.getSelectedFile());
FileObject fo = FileUtil.toFileObject(f);
if (fo != null) {
Object ret;
try {
final Project prjFrom = ProjectManager.getDefault().findProject(fo);
if (prjFrom == pf.getProject()) {
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_CodeStyle_Import_Forbidden_From_The_Same_Project"), //NOI18N
NotifyDescriptor.Message.PLAIN_MESSAGE));
return;
}
ret = ProjectManager.mutex().readAccess(new ExceptionAction<Object>() {
public Object run() throws Exception {
Preferences fromPrjPrefs = ProjectUtils.getPreferences(prjFrom, IndentUtils.class, true);
if (!fromPrjPrefs.nodeExists(CODE_STYLE_PROFILE) ||
fromPrjPrefs.node(CODE_STYLE_PROFILE).get(USED_PROFILE, null) == null
) {
return NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_No_CodeStyle_Info_To_Import"); //NOI18N
}
ProjectPreferencesFactory newPrefsFactory = new ProjectPreferencesFactory(pf.getProject());
Preferences toPrjPrefs = newPrefsFactory.projectPrefs;
removeAllKidsAndKeys(toPrjPrefs);
deepCopy(fromPrjPrefs, toPrjPrefs);
// XXX: detect somehow if the basic options are overriden in fromPrjPrefs
// and set the flag accordingly in toPrjPrefs
//dump(fromPrjPrefs, "fromPrjPrefs");
//dump(toPrjPrefs, "toPrjPrefs");
return newPrefsFactory;
}
});
} catch (Exception e) {
LOG.log(Level.INFO, null, e);
ret = e;
}
if (ret instanceof ProjectPreferencesFactory) {
String selectedMimeType = selector.getSelectedMimeType();
PreferencesCustomizer c = selector.getSelectedCustomizer();
String selectedCustomizerId = c != null ? c.getId() : null;
pf.destroy();
pf = (ProjectPreferencesFactory) ret;
selector = new CustomizerSelector(pf, false, allowedMimeTypes);
panel.setSelector(selector);
if (selectedMimeType != null) {
selector.setSelectedMimeType(selectedMimeType);
}
if (selectedCustomizerId != null) {
selector.setSelectedCustomizer(selectedCustomizerId);
}
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_CodeStyle_Import_Successful"), //NOI18N
NotifyDescriptor.Message.PLAIN_MESSAGE));
} else if (ret instanceof Exception) {
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
NbBundle.getMessage(FormattingCustomizerPanel.class, "MSG_CodeStyle_Import_Failed"), //NOI18N
NotifyDescriptor.Message.WARNING_MESSAGE));
} else {
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
(String) ret,
NotifyDescriptor.Message.PLAIN_MESSAGE));
}
}
}
}//GEN-LAST:event_loadButtonActionPerformed
private void dump(Preferences prefs, String prefsId) throws BackingStoreException {
for(String key : prefs.keys()) {
System.out.println(prefsId + ", " + prefs.absolutePath() + "/" + key + "=" + prefs.get(key, null));
}
for(String child : prefs.childrenNames()) {
dump(prefs.node(child), prefsId);
}
}
private void editGlobalButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editGlobalButtonActionPerformed
OptionsDisplayer.getDefault().open(GLOBAL_OPTIONS_CATEGORY);
}//GEN-LAST:event_editGlobalButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel customizerPanel;
private javax.swing.JButton editGlobalButton;
private javax.swing.JRadioButton globalButton;
private javax.swing.ButtonGroup group;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton loadButton;
private javax.swing.JRadioButton projectButton;
// End of variables declaration//GEN-END:variables
private static final Logger LOG = Logger.getLogger(FormattingCustomizerPanel.class.getName());
private static final String GLOBAL_OPTIONS_CATEGORY = "Editor/Formatting"; //NOI18N
private static final String CODE_STYLE_PROFILE = "CodeStyle"; // NOI18N
private static final String DEFAULT_PROFILE = "default"; // NOI18N
private static final String PROJECT_PROFILE = "project"; // NOI18N
private static final String USED_PROFILE = "usedProfile"; // NOI18N
private final String allowedMimeTypes;
private ProjectPreferencesFactory pf;
private CustomizerSelector selector;
private final FormattingPanel panel;
private boolean copyOnFork;
/** Creates new form CodeStyleCustomizerPanel */
private FormattingCustomizerPanel(Lookup context, String allowedMimeTypes) {
this.allowedMimeTypes = allowedMimeTypes;
this.pf = new ProjectPreferencesFactory(context.lookup(Project.class));
this.selector = new CustomizerSelector(pf, false, allowedMimeTypes);
this.panel = new FormattingPanel();
this.panel.setSelector(selector);
initComponents();
customizerPanel.add(panel, BorderLayout.CENTER);
Preferences prefs = pf.getPreferences("").parent(); //NOI18N
this.copyOnFork = prefs.get(USED_PROFILE, null) == null;
String profile = prefs.get(USED_PROFILE, DEFAULT_PROFILE);
if (DEFAULT_PROFILE.equals(profile)) {
globalButton.setSelected(true);
loadButton.setEnabled(false);
setEnabled(jScrollPane1, false);
// globalButton.doClick();
} else {
// projectButton.doClick();
projectButton.setSelected(true);
loadButton.setEnabled(true);
setEnabled(jScrollPane1, true);
}
}
private void setEnabled(Component component, boolean enabled) {
component.setEnabled(enabled);
if (component instanceof Container && !(component instanceof JSpinner)) {
for (Component c : ((Container)component).getComponents()) {
setEnabled(c, enabled);
}
}
}
private static boolean copyValueIfExists(Map<String, TypedValue> src, Preferences trg, String key) {
TypedValue value = src.get(key);
if (value != null) {
// since project Preferences do not support javaType we can just use simple put
trg.put(key, value.getValue());
return true;
} else {
return false;
}
}
private static void removeAllKidsAndKeys(Preferences prefs) throws BackingStoreException {
for(String kid : prefs.childrenNames()) {
// remove just the keys otherwise node listeners won't survive
removeAllKidsAndKeys(prefs.node(kid));
}
for(String key : prefs.keys()) {
prefs.remove(key);
}
}
private static void deepCopy(Preferences from, Preferences to) throws BackingStoreException {
for(String kid : from.childrenNames()) {
Preferences fromKid = from.node(kid);
Preferences toKid = to.node(kid);
deepCopy(fromKid, toKid);
}
for(String key : from.keys()) {
String value = from.get(key, null);
if (value == null) continue;
Class type = guessType(value);
if (Integer.class == type) {
to.putInt(key, from.getInt(key, -1));
} else if (Long.class == type) {
to.putLong(key, from.getLong(key, -1L));
} else if (Float.class == type) {
to.putFloat(key, from.getFloat(key, -1f));
} else if (Double.class == type) {
to.putDouble(key, from.getDouble(key, -1D));
} else if (Boolean.class == type) {
to.putBoolean(key, from.getBoolean(key, false));
} else if (String.class == type) {
to.put(key, value);
} else /* byte [] */ {
to.putByteArray(key, from.getByteArray(key, new byte [0]));
}
}
}
// XXX: this is here only to supprt deprecated Settings.class, when we are sure,
// that no code uses Settings.class we will be able to remove this
private static Class guessType(String value) {
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { //NOI18N
return Boolean.class;
}
try {
Integer.parseInt(value);
return Integer.class;
} catch (NumberFormatException nfe) { /* ignore */ }
try {
Long.parseLong(value);
return Long.class;
} catch (NumberFormatException nfe) { /* ignore */ }
try {
Float.parseFloat(value);
return Float.class;
} catch (NumberFormatException nfe) { /* ignore */ }
try {
Double.parseDouble(value);
return Double.class;
} catch (NumberFormatException nfe) { /* ignore */ }
// XXX: ignoring byte []
return String.class;
}
private static final class ProjectPreferencesFactory implements CustomizerSelector.PreferencesFactory {
public ProjectPreferencesFactory(Project project) {
this.project = project;
Preferences p = ProjectUtils.getPreferences(project, IndentUtils.class, true);
projectPrefs = ProxyPreferences.getProxyPreferences(this, p);
}
public Project getProject() {
return project;
}
public void destroy() {
accessedMimeTypes.clear();
projectPrefs.destroy();
projectPrefs = null;
}
// --------------------------------------------------------------------
// CustomizerSelector.PreferencesFactory implementation
// --------------------------------------------------------------------
public synchronized Preferences getPreferences(String mimeType) {
assert projectPrefs != null;
accessedMimeTypes.add(mimeType);
return projectPrefs.node(mimeType).node(CODE_STYLE_PROFILE).node(PROJECT_PROFILE);
}
public synchronized void applyChanges() {
for(String mimeType : accessedMimeTypes) {
if (mimeType.length() == 0) {
continue;
}
ProxyPreferences pp = (ProxyPreferences) getPreferences(mimeType);
if (null != pp.get(FormattingPanelController.OVERRIDE_GLOBAL_FORMATTING_OPTIONS, null)) {
// tabs-and-indents has been used and the basic options might have been changed
pp.silence();
if (!pp.getBoolean(FormattingPanelController.OVERRIDE_GLOBAL_FORMATTING_OPTIONS, false)) {
// remove the basic settings if a language is not overriding the 'all languages' values
pp.remove(SimpleValueNames.EXPAND_TABS);
pp.remove(SimpleValueNames.INDENT_SHIFT_WIDTH);
pp.remove(SimpleValueNames.SPACES_PER_TAB);
pp.remove(SimpleValueNames.TAB_SIZE);
pp.remove(SimpleValueNames.TEXT_LIMIT_WIDTH);
pp.remove(SimpleValueNames.TEXT_LINE_WRAP);
}
pp.remove(FormattingPanelController.OVERRIDE_GLOBAL_FORMATTING_OPTIONS);
}
}
// flush the root prefs
projectPrefs.silence();
try {
LOG.fine("Flushing root pp"); //NOI18N
projectPrefs.flush();
} catch (BackingStoreException ex) {
LOG.log(Level.WARNING, "Can't flush project codestyle root preferences", ex); //NOI18N
}
destroy();
}
public boolean isKeyOverridenForMimeType(String key, String mimeType) {
Preferences p = projectPrefs != null ? projectPrefs : ProjectUtils.getPreferences(project, IndentUtils.class, true);
p = p.node(mimeType).node(CODE_STYLE_PROFILE).node(PROJECT_PROFILE);
return p.get(key, null) != null;
}
// --------------------------------------------------------------------
// private implementation
// --------------------------------------------------------------------
private final Project project;
private final Set<String> accessedMimeTypes = new HashSet<String>();
private ProxyPreferences projectPrefs;
} // End of ProjectPreferencesFactory class
}