com.buildml.eclipse.utils.properties.SlotValuePropertyPage.java Source code

Java tutorial

Introduction

Here is the source code for com.buildml.eclipse.utils.properties.SlotValuePropertyPage.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Arapiki Solutions Inc.
 * 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:
 *    psmith - initial API and 
 *        implementation and/or initial documentation
 *******************************************************************************/

package com.buildml.eclipse.utils.properties;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import com.buildml.eclipse.bobj.UIInteger;
import com.buildml.eclipse.bobj.UISubPackage;
import com.buildml.eclipse.utils.BmlPropertyPage;
import com.buildml.eclipse.utils.EclipsePartUtils;
import com.buildml.eclipse.utils.GraphitiUtils;
import com.buildml.eclipse.utils.UndoOpAdapter;
import com.buildml.eclipse.utils.dialogs.VFSTreeSelectionDialog;
import com.buildml.model.IBuildStore;
import com.buildml.model.IFileMgr;
import com.buildml.model.IPackageMgr;
import com.buildml.model.ISlotTypes;
import com.buildml.model.ISlotTypes.SlotDetails;
import com.buildml.model.undo.MultiUndoOp;
import com.buildml.model.undo.SlotUndoOp;
import com.buildml.model.ISubPackageMgr;

/**
 * An Eclipse "property" page that allows viewing/editing of a sub-packages properties.
 * 
 * Objects of this class are referenced in the plugin.xml file and are dynamically
 * created when the properties dialog is opened for a UISubPackage object.
 * 
 * @author Peter Smith <psmith@arapiki.com>
 */
public class SlotValuePropertyPage extends BmlPropertyPage {

    /*=====================================================================================*
     * NESTED CLASSES
     *=====================================================================================*/

    /**
     * A nested class to be used by create*Editor methods to provide functionality for:
     *  1) Validating each field's current value (as entered by the user into a TextBox)
     *  2) Scheduling the necessary undo/redo work when "OK" is pressed.
     *  3) Restoring the field's default values.
     */
    private abstract class Validator {
        /**
         * @return null if the field's value is valid, else an error message.
         */
        abstract String getValidationError();

        /**
         * Schedule the necessary undo/redo work if this field's value has been user-modified.
         * @param multiOp   The MultiOp to add the changes to.
         */
        abstract void scheduleChange(MultiUndoOp multiOp);

        /**
         * Ask each field to restore itself to its default values.
         */
        abstract void restoreDefaults();
    }

    /*=====================================================================================*
     * CONSTANTS
     *=====================================================================================*/

    /** The number of lines that should appear when we're editing a text-typed slot */
    public static final int LINES_FOR_TEXT_BOX = 5;

    /*=====================================================================================*
     * FIELDS/TYPES
     *=====================================================================================*/

    /** Manager that holds package details */
    private IPackageMgr pkgMgr;

    /** Manager that holds sub-package details */
    private ISubPackageMgr subPkgMgr;

    /** Manager that holds sub-package details */
    private IFileMgr fileMgr;

    /** The validators that check the content of each entry field */
    private List<Validator> validators;

    /** The ID of the sub-package we're editing */
    private int subPkgId;

    /*=====================================================================================*
     * CONSTRUCTORS
     *=====================================================================================*/

    /**
     * Create a new SubPackagePropertyPage() object.
     */
    public SlotValuePropertyPage() {
        validators = new ArrayList<SlotValuePropertyPage.Validator>();
    }

    /*=====================================================================================*
     * PUBLIC METHODS
     *=====================================================================================*/

    /**
     * The OK button has been pressed in the properties box. Save all the field values
     * into the database. This is done via the undo/redo stack. Each create*Editor method
     * provides a Validator object that schedules the necessary undo/redo operations.
     */
    @Override
    public boolean performOk() {

        MultiUndoOp multiOp = new MultiUndoOp();
        for (Validator validator : validators) {
            validator.scheduleChange(multiOp);
        }
        if (multiOp.size() > 0) {
            new UndoOpAdapter("Edit Slots", multiOp).invoke();
        }

        return super.performOk();
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * The "restore default" button has been pressed, so return everything back to its
     * original state.
     */
    @Override
    protected void performDefaults() {
        for (Validator validator : validators) {
            validator.restoreDefaults();
        }
        super.performDefaults();
    }

    /*=====================================================================================*
     * PROTECTED METHODS
     *=====================================================================================*/

    /**
     * Create the widgets that appear within the properties dialog box. For this property
     * page, we list all of the slots, along with their associated values.
     */
    @Override
    protected Control createContents(Composite parent) {

        IBuildStore buildStore = EclipsePartUtils.getActiveBuildStore();
        pkgMgr = buildStore.getPackageMgr();
        subPkgMgr = buildStore.getSubPackageMgr();
        fileMgr = buildStore.getFileMgr();

        /* 
         * Determine which "thing" (UISubPackage or UIAction) we're looking at, then
         * compute the corresponding pkgId or actionTypeId that this "thing" is an
         * instance of.
         */
        UISubPackage subPkg = (UISubPackage) GraphitiUtils.getBusinessObjectFromElement(getElement(),
                UISubPackage.class);
        if (subPkg == null) {
            return null;
        }
        subPkgId = subPkg.getId();
        int pkgId = subPkgMgr.getSubPackageType(subPkgId);
        if (pkgId < 0) {
            return null;
        }

        /* fetch the "parameter" slots, and sort them alphabetically */
        SlotDetails[] paramSlots = pkgMgr.getSlots(pkgId, ISlotTypes.SLOT_POS_PARAMETER);
        Arrays.sort(paramSlots, new Comparator<SlotDetails>() {
            @Override
            public int compare(SlotDetails arg0, SlotDetails arg1) {
                return arg0.slotName.compareTo(arg1.slotName);
            }
        });

        /* prepare the top-level Composite in which everything else is placed */
        setTitle("Sub-Package Properties:");

        /* put everything inside a scrolled composite, in case we have a very long list of slots */
        ScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.BORDER | SWT.V_SCROLL);
        scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        scrolledComposite.setLayout(new GridLayout());
        scrolledComposite.setAlwaysShowScrollBars(true);

        /* create a sub-composite that contains all the slot details */
        Composite panel = new Composite(scrolledComposite, SWT.NONE);
        panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        panel.setLayout(layout);

        /*
         * For each slot, display a group box, the slot's name and description,
         * and then an appropriate set of controls to allow editing of the
         * field's value.
         */
        for (int i = 0; i < paramSlots.length; i++) {

            SlotDetails details = paramSlots[i];

            /* add group-box around each slot's information */
            Group group = new Group(panel, SWT.BORDER);
            group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
            group.setLayout(new GridLayout());

            /* display the slot title - centered and bolded */
            Label title = new Label(group, SWT.CENTER);
            title.setLayoutData(new GridData(SWT.CENTER, SWT.None, true, false));
            title.setText(details.slotName);
            title.setFont(JFaceResources.getFontRegistry().getBold(""));

            /* display the description - wrapped */
            Label descr = new Label(group, SWT.WRAP);
            GridData gd = new GridData(GridData.FILL_BOTH);
            gd.widthHint = EclipsePartUtils.getScreenWidth() / 3;
            descr.setLayoutData(gd);
            descr.setText(details.slotDescr);

            /* fetch the slot's current value */
            boolean isSlotSet = subPkgMgr.isSlotSet(subPkgId, details.slotId);
            Object slotValue = subPkgMgr.getSlotValue(subPkgId, details.slotId);

            /*
             * For each slot type, provide the ability to edit the current value.
             */
            switch (details.slotType) {

            /* Integer-typed slots */
            case ISlotTypes.SLOT_TYPE_INTEGER:
                createIntegerEditor(group, details, isSlotSet, (Integer) details.defaultValue, (Integer) slotValue);
                break;

            /* Text-typed slots */
            case ISlotTypes.SLOT_TYPE_TEXT:
                createTextEditor(group, details, isSlotSet, (String) details.defaultValue, (String) slotValue);
                break;

            /* Boolean-typed slots */
            case ISlotTypes.SLOT_TYPE_BOOLEAN:
                createBooleanEditor(group, details, isSlotSet, (Boolean) details.defaultValue, (Boolean) slotValue);
                break;

            /* File-typed slots */
            case ISlotTypes.SLOT_TYPE_FILE:
                createFileDirEditor(group, details, isSlotSet, (Integer) details.defaultValue, (Integer) slotValue,
                        true);
                break;

            /* Directory-typed slots */
            case ISlotTypes.SLOT_TYPE_DIRECTORY:
                createFileDirEditor(group, details, isSlotSet, (Integer) details.defaultValue, (Integer) slotValue,
                        false);
                break;

            default:
                /* do nothing */
            }
        }

        /* tell the ScrolledComposite what it's managing, and how big it should be. */
        scrolledComposite.setContent(panel);
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setMinWidth(0);
        panel.setSize(panel.computeSize(SWT.DEFAULT, SWT.DEFAULT));

        return scrolledComposite;
    }

    /*=====================================================================================*
     * PRIVATE METHODS
     *=====================================================================================*/

    /**
     * Create the Controls necessary for editing a Text-typed slot.
     * 
     * @param group         The parent group panel to add Control into.
     * @param details      The slot's details.
     * @param isSlotSet    True if the slot currently has a value set, or false if the default
     *                   value would be used.
     * @param defaultValue    The default value for the slot.
     * @param slotValue    The slot's current value (or null if !isSlotSet).
     */
    private void createTextEditor(Composite group, final SlotDetails details, final boolean isSlotSet,
            final String defaultValue, final String slotValue) {

        /* 
         * First, show the textBox, which should extend over multiple lines.
         */
        final Text textBox = new Text(group, SWT.BORDER | SWT.MULTI);
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
        gd.heightHint = EclipsePartUtils.getFontHeight(textBox) * LINES_FOR_TEXT_BOX;
        textBox.setLayoutData(gd);

        /* 
         * Add the "Use Default" check-button. If it's checked, then we showed
         * the slot's default value in the textBox and un-enabled the textBox.
         */
        final Button checkButton = addDefaultCheckbox(group, isSlotSet);
        final SelectionListener select = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean useDefault = checkButton.getSelection();
                textBox.setEnabled(!useDefault);
                if (useDefault) {
                    textBox.setText(defaultValue);
                } else {
                    textBox.setText(isSlotSet ? slotValue : "");
                }
            }
        };
        checkButton.addSelectionListener(select);
        select.widgetSelected(null);

        /*
         * Register a validator for this field.
         */
        registerField(new Validator() {

            /* any String value is OK - never any errors given */
            @Override
            String getValidationError() {
                return null;
            }

            /* If this field has changed, schedule the undo/redo operation */
            @Override
            void scheduleChange(MultiUndoOp multiOp) {
                boolean newExists = !checkButton.getSelection();
                String newValue = newExists ? textBox.getText().trim() : slotValue;
                if ((newExists != isSlotSet) || !(slotValue.equals(newValue))) {
                    SlotUndoOp op = new SlotUndoOp(buildStore, ISlotTypes.SLOT_OWNER_PACKAGE);
                    op.recordChangeSlotValue(subPkgId, details.slotId, isSlotSet, slotValue, newExists, newValue);
                    multiOp.add(op);
                }
            }

            /* restore default values */
            @Override
            void restoreDefaults() {
                checkButton.setSelection(!isSlotSet);
                select.widgetSelected(null);
            }
        });
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Create the Controls necessary for editing an Integer-typed slot.
     * 
     * @param group         The parent group panel to add Control into.
     * @param details      The slot's details.
     * @param isSlotSet    True if the slot currently has a value set, or false if the default
     *                   value would be used.
      * @param defaultValue    The default value for the slot.
     * @param slotValue    The slot's current value (or null if !isSlotSet).
     */
    private void createIntegerEditor(Group group, final SlotDetails details, final boolean isSlotSet,
            final Integer defaultValue, final Integer slotValue) {
        /* 
         * First, show the textBox.
         */
        final Text integerBox = new Text(group, SWT.BORDER);
        integerBox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        /* 
         * Add the "Use Default" check-button. If it's checked, then we showed
         * the slot's default value in the textBox and un-enabled the textBox.
         */
        final Button checkButton = addDefaultCheckbox(group, isSlotSet);
        final SelectionListener select = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean useDefault = checkButton.getSelection();
                integerBox.setEnabled(!useDefault);
                if (useDefault) {
                    integerBox.setText(defaultValue.toString());
                } else {
                    integerBox.setText(isSlotSet ? slotValue.toString() : "0");
                }
            }
        };
        checkButton.addSelectionListener(select);
        select.widgetSelected(null);

        /*
         * Register a validator for this field.
         */
        registerField(new Validator() {

            /* Validate the text box, and return an error message */
            @Override
            String getValidationError() {
                String s = integerBox.getText();
                for (int i = 0; i != s.length(); i++) {
                    if (!Character.isDigit(s.charAt(i))) {
                        return details.slotName + ": Non-numeric characters not allowed.";
                    }
                }
                return null;
            }

            /* If our fields changed, schedule the necessary undo/redo operation to happen */
            @Override
            void scheduleChange(MultiUndoOp multiOp) {
                boolean newExists = !checkButton.getSelection();
                Integer newValue = newExists ? Integer.valueOf(integerBox.getText()) : slotValue;
                if ((newExists != isSlotSet) || !(slotValue.equals(newValue))) {
                    SlotUndoOp op = new SlotUndoOp(buildStore, ISlotTypes.SLOT_OWNER_PACKAGE);
                    op.recordChangeSlotValue(subPkgId, details.slotId, isSlotSet, slotValue, newExists, newValue);
                    multiOp.add(op);
                }
            }

            /* restore default values */
            @Override
            void restoreDefaults() {
                checkButton.setSelection(!isSlotSet);
                select.widgetSelected(null);
            }
        });

        /*
         * Monitor edits to the integerBox, to make sure it always contains a valid
         * integer value.
         */
        integerBox.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent e) {
                validateFields();
            }
        });
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Create the Controls necessary for editing a Boolean-typed slot.
     * 
     * @param group         The parent group panel to add Control into.
     * @param details      The slot's details.
     * @param isSlotSet    True if the slot currently has a value set, or false if the default
     *                   value would be used.
     * @param defaultValue    The default value for the slot.
     * @param slotValue    The slot's current value (or null if !isSlotSet).
     */
    private void createBooleanEditor(Group group, final SlotDetails details, final boolean isSlotSet,
            final Boolean defaultValue, final Boolean slotValue) {

        /* Show a pair of radio buttons - "true" and "false" */
        Composite choices = new Composite(group, SWT.NONE);
        choices.setLayoutData(new GridData(SWT.FILL, SWT.None, true, false));
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = layout.verticalSpacing = 0;
        choices.setLayout(layout);
        final Button trueButton = new Button(choices, SWT.RADIO);
        trueButton.setText("true");
        final Button falseButton = new Button(choices, SWT.RADIO);
        falseButton.setText("false");

        /* 
         * Add the "Use Default" check-button. If it's checked, then we showed
         * the slot's default value in the textBox and un-enabled the textBox.
         */
        final Button checkButton = addDefaultCheckbox(group, isSlotSet);
        final SelectionListener select = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean value = slotValue;
                boolean useDefault = checkButton.getSelection();
                if (useDefault) {
                    value = defaultValue;
                }
                trueButton.setEnabled(!useDefault);
                falseButton.setEnabled(!useDefault);
                trueButton.setSelection(value);
                falseButton.setSelection(!value);
            }
        };
        checkButton.addSelectionListener(select);
        select.widgetSelected(null);

        /*
         * Register a validator for this field.
         */
        registerField(new Validator() {

            /* any Boolean value is OK - never any errors given */
            @Override
            String getValidationError() {
                return null;
            }

            /* If this field has changed, schedule the undo/redo operation */
            @Override
            void scheduleChange(MultiUndoOp multiOp) {
                boolean newExists = !checkButton.getSelection();
                Boolean newValue = newExists ? Boolean.valueOf(trueButton.getSelection()) : slotValue;
                if ((newExists != isSlotSet) || !(slotValue.equals(newValue))) {
                    SlotUndoOp op = new SlotUndoOp(buildStore, ISlotTypes.SLOT_OWNER_PACKAGE);
                    op.recordChangeSlotValue(subPkgId, details.slotId, isSlotSet, slotValue, newExists, newValue);
                    multiOp.add(op);
                }
            }

            /* restore default values */
            @Override
            void restoreDefaults() {
                checkButton.setSelection(!isSlotSet);
                select.widgetSelected(null);
            }
        });
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Create the Controls necessary for editing a File or Directory-typed slot.
     * 
     * @param group         The parent group panel to add Control into.
     * @param details      The slot's details.
     * @param isSlotSet    True if the slot currently has a value set, or false if the default
     *                   value would be used.
     * @param defaultValue    The default value for the slot.
     * @param slotValue    The slot's current value (or null if !isSlotSet).
     * @param isFile      True if we're modifying a file field, or false for a directory field.
     */
    private void createFileDirEditor(Group group, final SlotDetails details, final boolean isSlotSet,
            Integer defaultValue, final Integer slotValue, final boolean isFile) {

        /* 
         * Create the Control that displays the current file name. We use a non-editable Text box,
         * to make it look consistent with other slots, but without letting the user edit it directly.
         */
        final Text pathLabel = new Text(group, SWT.NONE);
        pathLabel.setEditable(false);
        pathLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        /*
         * Next, show the "Browse" button and the "Use default" check-box, right next to each other.
         */
        Composite pathSelector = new Composite(group, SWT.NONE);
        pathSelector.setLayoutData(new GridData(SWT.FILL, SWT.None, true, false));
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = layout.verticalSpacing = layout.horizontalSpacing = layout.marginWidth = 0;
        pathSelector.setLayout(layout);
        final Button browseButton = new Button(pathSelector, SWT.PUSH);
        browseButton.setText("Browse");
        final Button checkButton = addDefaultCheckbox(pathSelector, isSlotSet);

        /* 
         * Associate actions with the "use default" check-box to appropriately 
         * enable/disable the "Browse" button.
         */
        final SelectionListener select = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                boolean useDefault = checkButton.getSelection();
                setPathLabel(pathLabel, useDefault ? null : slotValue);
                browseButton.setEnabled(!useDefault);
            }
        };
        checkButton.addSelectionListener(select);
        select.widgetSelected(null);

        /*
         * Define the behaviour of the "Browse" button. This will open a file-selection
         * dialog and update the path accordingly.
         */
        browseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                VFSTreeSelectionDialog dialog = new VFSTreeSelectionDialog(getShell(), buildStore,
                        "Please select the new path for this slot", !isFile, isFile);
                dialog.setAllowMultiple(false);
                int status = dialog.open();
                if (status == VFSTreeSelectionDialog.OK) {
                    Object selectedPath = dialog.getFirstResult();
                    if (selectedPath instanceof UIInteger) {
                        int pathId = ((UIInteger) selectedPath).getId();
                        setPathLabel(pathLabel, Integer.valueOf(pathId));
                    }
                }
            }
        });

        /*
         * Register a validator for this field.
         */
        registerField(new Validator() {

            /* any file value is OK - never any errors given */
            @Override
            String getValidationError() {
                return null;
            }

            /* If this field has changed, schedule the undo/redo operation */
            @Override
            void scheduleChange(MultiUndoOp multiOp) {
                boolean newExists = !checkButton.getSelection();
                int pathId = fileMgr.getPath(pathLabel.getText());
                if (pathId >= 0) {
                    Integer newValue = newExists ? pathId : null;
                    if ((newExists != isSlotSet) || !(slotValue.equals(newValue))) {
                        SlotUndoOp op = new SlotUndoOp(buildStore, ISlotTypes.SLOT_OWNER_PACKAGE);
                        op.recordChangeSlotValue(subPkgId, details.slotId, isSlotSet, slotValue, newExists,
                                newValue);
                        multiOp.add(op);
                    }
                }
            }

            /* restore default values */
            @Override
            void restoreDefaults() {
                checkButton.setSelection(!isSlotSet);
                select.widgetSelected(null);
            }
        });
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Helper method for displaying a "Use Default Value" checkbox.
     * 
     * @param composite   The Composite to add the checkbox to.
     * @param isSlotSet   True if the slot currentl has an explicit value (i.e. does not default)
     * @return The Button control, that can be queried for its status.
     */
    private Button addDefaultCheckbox(Composite composite, boolean isSlotSet) {

        /* Create the checkbox */
        Button checkButton = new Button(composite, SWT.CHECK);
        checkButton.setText("Use Default Value");
        checkButton.setSelection(!isSlotSet);
        return checkButton;
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Validate all of the fields that are being displayed. Whenever a control is modified,
     * this method is called to validate all fields (not just the field that was modified).
     * The result is that if any fields contain invalid values, an error message will be
     * displayed.
     */
    private void validateFields() {
        for (Validator validator : validators) {
            String error = validator.getValidationError();
            if (error != null) {
                setMessage(error, ERROR);
                setValid(false);
                return;
            }
        }
        setMessage(null);
        setValid(true);
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Register a field validator method. Each field editor must register an object that
     * provides the ability to validate the field, as well as to schedule the field's value
     * change as an undo/redo operation, and perhaps other things.
     * 
     * @param validator   A Validator object for the field editor.
     */
    private void registerField(Validator validator) {
        validators.add(validator);
    }

    /*-------------------------------------------------------------------------------------*/

    /**
     * Helper method for translating a pathId into a user-facing string, and then setting
     * the text of a control to that string value.
     * 
     * @param pathLabel   The Control that we'll setting the text for. 
     * @param pathId   An Integer containing the pathID (or null).
     */
    private void setPathLabel(Text pathLabel, Integer pathId) {
        if (pathId == null) {
            pathLabel.setText("<undefined>");
        } else {
            String pathName = fileMgr.getPathName(pathId);
            if (pathName == null) {
                pathLabel.setText("<invalid>");
            } else {
                pathLabel.setText(pathName);
            }
        }
    }

    /*-------------------------------------------------------------------------------------*/
}