/******************************************************************************* * Copyright (c) 2007 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package org.eclipse.imp.preferences; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.imp.preferences.fields.FieldEditor; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; public abstract class PreferencesTab { // The following fields are shared among specific // subtypes of preferences tab, which generally represent // the various levels on which preferences are set. // However, most of the fields have language-dependent // impementations, so they are not set here. // The page on which this tab occurs protected TabbedPreferencesPage fPrefPage = null; // Utilities for creating and managing preference fields protected PreferencesUtilities fPrefUtils; // The service for storing and accessing preference values protected IPreferencesService fPrefService; // The fields that occur on this tab protected FieldEditor[] fFields = null; protected boolean fNoDetails = false; // The details links that are associated with the fields // (to be in one-to-one correspondence) protected List<Link> fDetailsLinks = new ArrayList<Link>(); protected String fLevel; // Whether this tab is valid, that is, whether // all of its fields are valid protected boolean fIsValid = true; // The buttons on this tab protected Control[] fButtons = null; // SMS 17 Nov 2006 protected TabItem fTabItem = null; public PreferencesTab(String level, boolean noDetails) { fLevel= level; fNoDetails= noDetails; } public TabItem getTabItem() { return fTabItem; } public String getLevel() { return fLevel; } public boolean getNoDetails() { return fNoDetails; } /** * Creates specific preferences fields. * Must be overridden, typically by language-specific tab classes. */ protected abstract FieldEditor[] createFields(TabbedPreferencesPage page, Composite parent); /** * Creates the contents of the entire tab. Calls createFields(). * Overridden by level-specific tab classes, but not typically overridden in language-specific * tab classes (which, instead, override createFields()). */ public abstract Composite createTabContents(TabbedPreferencesPage page, final TabFolder tabFolder); /* * Methods to set or clear an "error mark" on tab labels */ public void setErrorMarkOnTab() { if (errorMessages.isEmpty()) { return; } String label = fTabItem.getText(); if (!label.startsWith(Markings.TAB_ERROR_MARK)) { label = Markings.TAB_ERROR_MARK + label; } if (!label.endsWith(Markings.TAB_ERROR_MARK)) { label = label + Markings.TAB_ERROR_MARK; } fTabItem.setText(label); } public void clearErrorMarkOnTab() { if (!errorMessages.isEmpty()) { return; } String label = fTabItem.getText(); if (label.startsWith(Markings.TAB_ERROR_MARK)) { label = label.substring(2); } if (label.endsWith(Markings.TAB_ERROR_MARK)) { label = label.substring(0, label.length()-2); } fTabItem.setText(label); } /* * Methods and a field related to setting and clearing error messages * for the tab */ public HashMap errorMessages = new HashMap(); public void clearErrorMessages(Object key) { String currentMessage = (String) errorMessages.get(key); // System.out.println("Tab = " + tabItem.getText() + ", field = " + ((FieldEditor)key).getPreferenceName() + ": clearErrorMessages(), clearing message = " + currentMessage); errorMessages.remove(key); if (fPrefPage == null) return; if (errorMessages.size() == 0) { // System.out.println("Tab = " + tabItem.getText() + ", field = " + ((FieldEditor)key).getPreferenceName() + ": clearErrorMessages(), setting message to null"); fPrefPage.setErrorMessage(null); // to clear return; } Iterator it = errorMessages.keySet().iterator(); Object nextKey = it.next(); String nextMessage = (String) errorMessages.get(nextKey); // System.out.println("Tab = " + tabItem.getText() + ", field = " + ((FieldEditor)key).getPreferenceName() + "clearErrorMessages(), setting message to: " + nextMessage); fPrefPage.setErrorMessage(nextMessage); } public void setErrorMessage(Object key, String msg) { if (key != null && msg != null) { // System.out.println("Tab = " + tabItem.getText() + ", field = " + ((FieldEditor)key).getPreferenceName() + ": setErrorMessage(), setting message to: " + msg); errorMessages.put(key, msg); fPrefPage.setErrorMessage(msg); } } /* * A method to clear the modified mark on field labels */ public void clearModifiedMarksOnLabels() { for (int i = 0; i < fFields.length; i++) { fFields[i].clearModifiedMarkOnLabel(); } } /* * A listener class for responding to selection of the tab */ /** * A listener for responding to selection of the tab, mainly by * clearing or setting the error message on the page according to * whether there are error messages associated with the tab. */ public class TabSelectionListener implements SelectionListener { private PreferencePage page = null; private TabItem item = null; public TabSelectionListener(PreferencePage page, TabItem item) { this.page = page; this.item = item; } public void widgetSelected(SelectionEvent e) { if (fPrefPage == null) return; if (e.item != item) return; if (errorMessages.size() == 0) { fPrefPage.setErrorMessage(null); return; } Iterator it = errorMessages.keySet().iterator(); Object nextKey = it.next(); String nextMessage = (String) errorMessages.get(nextKey); fPrefPage.setErrorMessage(nextMessage); } public void widgetDefaultSelected(SelectionEvent e) {} } /* * Methods for responding to buttons, with very simple implementations. * * SMS 4 Dec 2006: These could be made abstract, but why not provide * a minimal useful representation? */ /** * Apply the currently set preferences to the preferences model. * More specifically store each field and clear its "modified" mark * (not all fields will be modified, but that's not a problem). * * This implementation of performApply is adequate for the provided * implementations of the Default, Configuration, and Instance tabs * but needs to be overridden in the Project tab to address the * situation in which the project is not set. */ public void performApply() { for (int i = 0; i < fFields.length; i++) { fFields[i].store(); fFields[i].clearModifiedMarkOnLabel(); } } public boolean performCancel() { return true; } public void performDefaults() { } /** * Apply the currently set preferences to the preferences model. * More specifically store each field and clear its "modified" mark * (not all fields will be modified, but that's not a problem). * * This implementation of performOk is adequate for the provided * implementations of the Default, Configuration, and Instance tabs * but needs to be overridden in the Project tab to address the * situation in which the project is not set and to unset the * project when it is set. * */ public boolean performOk() { if (fFields != null) { for (int i = 0; i < fFields.length; i++) { fFields[i].store(); fFields[i].clearModifiedMarkOnLabel(); // RMF 1/9/2009 - For some reason, some performOk() implementations (like the X10DT's) // call setPresentsDefaultValue(false), which seems wrong... } } return true; } /* * Methods to set and get the "valid" state of the tab * and to update the enabled state of buttons on the * tab according to the valid state. */ /** * Set the "valid" state of the tab according to the given * value in conjunction with the occurrence of error messages. * * Note: This method will be called (indirectly) whenever a * preference field is validated. However, the state of the * tab overall depends on the conjunction of the states of * all of its fields. The value provided here represents the * state of one field; */ public void setValid(boolean state) { // SMS 8 Dec 2006: added second conjunct fIsValid = /*state &&*/ errorMessages.size() == 0; if (!fIsValid) { setErrorMarkOnTab(); } else { clearErrorMarkOnTab(); } fPrefPage.notifyState(fIsValid); updateButtons(); } public boolean isValid() { //int numMessages = errorMessages.size(); return fIsValid; } public void updateButtons() { if (fButtons != null) { //System.out.println("SPT.updateButtons(): buttons not null"); for (int i = 0; i < fButtons.length; i++) { Button button = (Button) fButtons[i]; if (button != null) // TODO: define string constants for button texts if (button.getText().startsWith("Restore")) continue; button.setEnabled(isValid() /* && errorMessages.size() == 0*/); } } else { //System.out.println("SPT.updateButtons(): buttons null"); } } }