org.netbeans.modules.project.uiapi.CustomizerDialog Maven / Gradle / Ivy
The newest version!
/*
* 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.project.uiapi;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.spi.project.ui.support.ProjectCustomizer;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.RequestProcessor;
import org.openide.windows.WindowManager;
/** Implementation of standard customizer dialog.
*
* @author Petr Hrebejk
*/
public class CustomizerDialog {
/** Factory class only
*/
private CustomizerDialog() {}
// Option indexes
private static final int OPTION_OK = 0;
private static final int OPTION_CANCEL = OPTION_OK + 1;
// Option command names
private static final String COMMAND_OK = "OK"; // NOI18N
private static final String COMMAND_CANCEL = "CANCEL"; // NOI18N
// Close action
private static final int ACTION_CLOSE = OPTION_CANCEL + 1;
private static final String CUSTOMIZER_DIALOG_X = "CustomizerDialog.dialog.x";
private static final String CUSTOMIZER_DIALOG_Y = "CustomizerDialog.dialog.y";
private static final String CUSTOMIZER_DIALOG_WIDTH = "CustomizerDialog.dialog.width";
private static final String CUSTOMIZER_DIALOG_HEIGHT = "CustomizerDialog.dialog.height";
public static Dialog createDialog(@NonNull ActionListener okOptionListener, @NullAllowed ActionListener storeListener, final CustomizerPane innerPane,
HelpCtx helpCtx, final ProjectCustomizer.Category[] categories,
//#97998 related
ProjectCustomizer.CategoryComponentProvider componentProvider ) {
ListeningButton okButton = new ListeningButton(
NbBundle.getMessage(CustomizerDialog.class, "LBL_Customizer_Ok_Option"), // NOI18N
categories);
okButton.setEnabled(CustomizerDialog.checkValidity(categories));
// Create options
JButton options[] = {
okButton,
new JButton( NbBundle.getMessage( CustomizerDialog.class, "LBL_Customizer_Cancel_Option" ) ) , // NOI18N
};
// Set commands
options[ OPTION_OK ].setActionCommand( COMMAND_OK );
options[ OPTION_CANCEL ].setActionCommand( COMMAND_CANCEL );
//A11Y
options[ OPTION_OK ].getAccessibleContext().setAccessibleDescription ( NbBundle.getMessage( CustomizerDialog.class, "AD_Customizer_Ok_Option") ); // NOI18N
options[ OPTION_CANCEL ].getAccessibleContext().setAccessibleDescription ( NbBundle.getMessage( CustomizerDialog.class, "AD_Customizer_Cancel_Option") ); // NOI18N
// RegisterListener
ActionListener optionsListener = new OptionListener(okOptionListener, storeListener, categories , componentProvider);
options[ OPTION_OK ].addActionListener( optionsListener );
options[ OPTION_CANCEL ].addActionListener( optionsListener );
innerPane.getAccessibleContext().setAccessibleName( NbBundle.getMessage( CustomizerDialog.class, "AN_ProjectCustomizer") ); //NOI18N
innerPane.getAccessibleContext().setAccessibleDescription( NbBundle.getMessage( CustomizerDialog.class, "AD_ProjectCustomizer") ); //NOI18N
if ( helpCtx == null ) {
helpCtx = HelpCtx.DEFAULT_HELP;
}
DialogDescriptor dialogDescriptor = new DialogDescriptor(
innerPane, // innerPane
NbBundle.getMessage( CustomizerDialog.class, "LBL_Customizer_Title" ), // NOI18N // displayName
false, // modal
options, // options
options[OPTION_OK], // initial value
DialogDescriptor.BOTTOM_ALIGN, // options align
helpCtx, // helpCtx
null ); // listener
innerPane.addPropertyChangeListener( new HelpCtxChangeListener( dialogDescriptor, helpCtx ) );
if ( innerPane instanceof HelpCtx.Provider ) {
HelpCtx help = ((HelpCtx.Provider) innerPane).getHelpCtx();
if (!help.equals(HelpCtx.DEFAULT_HELP)) {
dialogDescriptor.setHelpCtx(help);
}
}
dialogDescriptor.setClosingOptions( new Object[] { options[ OPTION_OK ], options[ OPTION_CANCEL ] } );
Dialog dialog = DialogDisplayer.getDefault().createDialog( dialogDescriptor );
Preferences prefs = NbPreferences.forModule(org.netbeans.modules.project.uiapi.CustomizerDialog.class);
int dialogX = prefs.getInt(CUSTOMIZER_DIALOG_X, 0);
int dialogY = prefs.getInt(CUSTOMIZER_DIALOG_Y, 0);
int dialogWidth = prefs.getInt(CUSTOMIZER_DIALOG_WIDTH, 0);
int dialogHeight = prefs.getInt(CUSTOMIZER_DIALOG_HEIGHT, 0);
if ((dialogWidth != 0) && (dialogHeight != 0)) {
GraphicsConfiguration gf = WindowManager.getDefault().getMainWindow().getGraphicsConfiguration();
Rectangle gbounds = gf.getBounds();
//Check bounds if saved size is bigger than size of current display, dialog should use the same display
//as main window
int maxWidth = gbounds.width;
if (dialogWidth > maxWidth) {
dialogWidth = maxWidth * 3 / 4;
}
int maxHeight = gbounds.height;
if (dialogHeight > maxHeight) {
dialogHeight = maxHeight * 3 / 4;
}
int minx = gbounds.x;
int maxx = minx + gbounds.width;
int miny = gbounds.y;
int maxy = miny + gbounds.height;
dialog.setBounds(dialogX, dialogY, dialogWidth, dialogHeight);
// #187608: make sure the dialog remains in some visible area of the screen
if (dialogX < minx || dialogX > maxx || dialogY < miny || dialogY > maxy) {
dialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
}
}
dialog.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
Preferences prefs = NbPreferences.forModule(org.netbeans.modules.project.uiapi.CustomizerDialog.class);
prefs.putInt(CUSTOMIZER_DIALOG_X, e.getWindow().getX());
prefs.putInt(CUSTOMIZER_DIALOG_Y, e.getWindow().getY());
prefs.putInt(CUSTOMIZER_DIALOG_WIDTH, e.getWindow().getWidth());
prefs.putInt(CUSTOMIZER_DIALOG_HEIGHT, e.getWindow().getHeight());
innerPane.clearPanelComponentCache();
List queue = new LinkedList(Arrays.asList(categories));
while (!queue.isEmpty()) {
ProjectCustomizer.Category category = queue.remove(0);
Utilities.removeCategoryChangeSupport(category);
ActionListener listener = category.getCloseListener();
if (listener != null) {
listener.actionPerformed(new ActionEvent(this, ACTION_CLOSE, e.paramString()));
}
if (category.getSubcategories() != null) {
queue.addAll(Arrays.asList(category.getSubcategories()));
}
}
}
});
return dialog;
}
/** Returns whether all given categories are valid or not. */
private static boolean checkValidity(ProjectCustomizer.Category[] categories) {
for (ProjectCustomizer.Category c : categories) {
if (!c.isValid()) {
return false;
}
ProjectCustomizer.Category[] subCategories = c.getSubcategories();
if (subCategories != null) {
if (!checkValidity(subCategories)) {
return false;
}
}
}
return true;
}
/** Listens to the actions on the Customizer's option buttons */
private static class OptionListener implements ActionListener {
private @NonNull ActionListener okOptionListener;
private @NullAllowed ActionListener storeListener;
private ProjectCustomizer.Category[] categories;
private Lookup.Provider prov;
OptionListener(@NonNull ActionListener okOptionListener, @NullAllowed ActionListener storeListener, ProjectCustomizer.Category[] categs,
ProjectCustomizer.CategoryComponentProvider componentProvider) {
this.okOptionListener = okOptionListener;
this.storeListener = storeListener;
categories = categs;
//#97998 related
if (componentProvider instanceof Lookup.Provider) {
prov = (Lookup.Provider)componentProvider;
}
}
public void actionPerformed( final ActionEvent e ) {
String command = e.getActionCommand();
if ( COMMAND_OK.equals( command ) ) {
// Call the OK option listener
ProjectManager.mutex().writeAccess(new Mutex.Action