io.pyd.synchro.gui.JobEditor.java Source code

Java tutorial

Introduction

Here is the source code for io.pyd.synchro.gui.JobEditor.java

Source

/*
 * Copyright 2012 Charles du Jeu <charles (at) pyd.io>
 * This file is part of Pydio.
 *
 * Pydio is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Pydio is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Pydio.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The latest code can be found at <http://pyd.io/>..
 *
 */
package io.pyd.synchro.gui;

import info.ajaxplorer.client.http.AjxpAPI;
import info.ajaxplorer.client.http.RestRequest;
import info.ajaxplorer.client.http.RestStateHolder;
import info.ajaxplorer.client.model.Node;
import info.ajaxplorer.client.model.Server;
import io.pyd.synchro.CoreManager;

import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.nebula.animation.AnimationRunner;
import org.eclipse.nebula.animation.effects.AlphaEffect;
import org.eclipse.nebula.animation.effects.SetBoundsEffect;
import org.eclipse.nebula.animation.movement.ExpoOut;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
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.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.quartz.SchedulerException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

public class JobEditor extends Composite {

    public static final String AUTO_KEEP_REMOTE_DATA = "AUTOKEEPREMOTE";
    public static final String AUTO_KEEP_REMOTE = "auto_keep_remote";
    public static final String AUTO_KEEP_LOCAL_DATA = "AUTOKEEPLOCAL";
    public static final String AUTO_KEEP_LOCAL = "auto_keep_local";

    {
        //Register as a resource user - SWTResourceManager will
        //handle the obtaining and disposing of resources
        SWTResourceManager.registerResourceUser(this);
    }

    private String currentRepoId;
    private String currentRepoLabel;

    private Text tfHost;
    private ImageHyperlink buttonFileChooser;
    private Text tfRepo;
    private Text tfTarget;
    private Text tfPassword;
    private ImageHyperlink linkLoadRepositories;
    private Button radioSyncInterval2;
    private Combo comboRepository;
    private Button radioSyncInterval3;
    private Button radioSyncInterval1;
    private Combo comboDirection;
    private Button radioServerLoadLow;
    private Button radioServerLoadMedium;
    private Button radioServerLoadHigh;

    private Button keepAutoRemote;
    private Button keepAutoLocal;
    private Text tfLogin;
    private Button trustSSL;

    private Action saveAction;
    private Action closeAction;

    private FormToolkit toolkit;
    private Section connexionSection;
    private Composite sectionClient;
    private Section parametersSection;
    private Section logsSection;
    private LogViewer logs;

    // FIXME later - refactor to ensure MVC pattern.
    // all data should be stored in model object for manipulate

    private boolean currentActiveState = true;
    private boolean autoKeepRemoteState = false;
    private boolean autoKeepLocalState = false;

    // we will use TreeMap implementation so items in combo are sorted
    private Map<String, String> repoItems;
    //private ConfigPanel configPanel;

    private Form form;

    private Map<String, HashMap<String, Object>> stackData;
    private String anchorH;
    private String anchorW;
    int heightHint = 0;

    SysTray sTray;
    Node currentSynchroNode;

    /**
    * Overriding checkSubclass allows this class to extend org.eclipse.swt.widgets.Composite
    */
    protected void checkSubclass() {
    }

    public JobEditor(Shell shell, SysTray systemTray, String stack) {

        super(shell, SWT.WRAP);
        this.initShell(shell);
        this.sTray = systemTray;
        this.anchorH = "bottom";
        this.anchorW = "right";
        int fontSizeOffset = 0;
        String os = System.getProperty("os.name");
        if (os.equalsIgnoreCase("Windows XP") || os.equals("Windows NT") || os.equals("Windows 2000")) {
            fontSizeOffset = 3;
        }
        //populateToolkit(parent);   
        stackData = new LinkedHashMap<String, HashMap<String, Object>>();
        HashMap<String, Object> connData = new HashMap<String, Object>();
        connData.put("LABEL", CoreManager.getMessage("jobeditor_stack_server"));
        connData.put("WIDTH", 280);
        connData.put("HEIGHT", 240);
        connData.put("FONT_HEIGHT", 23 + fontSizeOffset);
        connData.put("FONT_WIDTH", 22 + fontSizeOffset);
        connData.put("ICON", "fa/blue/globe");
        stackData.put("connexion", connData);

        HashMap<String, Object> connData2 = new HashMap<String, Object>();
        connData2.put("LABEL", CoreManager.getMessage("jobeditor_stack_params"));
        connData2.put("WIDTH", 280);
        connData2.put("HEIGHT", 210);
        connData2.put("FONT_HEIGHT", 23 + fontSizeOffset);
        connData2.put("FONT_WIDTH", 22 + fontSizeOffset);
        connData2.put("ICON", "fa/blue/cog");
        stackData.put("parameters", connData2);

        HashMap<String, Object> connData3 = new HashMap<String, Object>();
        connData3.put("LABEL", CoreManager.getMessage("jobeditor_stack_logs"));
        connData3.put("WIDTH", 520);
        connData3.put("HEIGHT", 420);
        connData3.put("FONT_HEIGHT", 33 + fontSizeOffset);
        connData3.put("FONT_WIDTH", 40 + fontSizeOffset);
        connData3.put("ICON", "fa/blue/list-alt");
        stackData.put("logs", connData3);

        this.setLayout(new FillLayout(SWT.HORIZONTAL | SWT.VERTICAL));
        populateToolkit();
        moveShellWithMouse(getMouseHandler(), getShell());

        GC gc = new GC(shell);
        this.heightHint = gc.getFontMetrics().getHeight();
        gc.dispose();

        shell.pack();
        toggleSection(stack, false);

    }

    public void initShell(final Shell shell) {

        shell.setText(CoreManager.getMessage("shell_title"));
        shell.setImage(new Image(shell.getDisplay(),
                this.getClass().getClassLoader().getResourceAsStream("images/AjxpLogo16-Bi.png")));
        this.moveShellWithMouse(this, shell);
        shell.setLayout(new FillLayout(SWT.HORIZONTAL | SWT.VERTICAL));

    }

    protected void loadFormFromNode(Node baseNode) {
        Server s;
        try {
            s = new Server(baseNode.getParent());
            HashMap<String, String> values = new HashMap<String, String>();
            values.put("HOST", s.getUrl());
            values.put("LOGIN", s.getUser());
            values.put("PASSWORD", s.getPassword());
            values.put("REPOSITORY_LABEL", baseNode.getLabel());
            if (baseNode.getPropertyValue("trust_ssl") != null) {
                values.put("TRUST_SSL", baseNode.getPropertyValue("trust_ssl"));
            } else {
                values.put("TRUST_SSL", "false");
            }
            values.put("REPOSITORY_ID", baseNode.getPropertyValue("repository_id"));
            values.put("TARGET", baseNode.getPropertyValue("target_folder"));
            values.put("ACTIVE", baseNode.getPropertyValue("synchro_active"));
            values.put("DIRECTION", baseNode.getPropertyValue("synchro_direction"));
            values.put("INTERVAL", baseNode.getPropertyValue("synchro_interval"));
            values.put("MAX_DEPTH", baseNode.getPropertyValue("max_depth"));

            values.put(AUTO_KEEP_REMOTE_DATA, baseNode.getPropertyValue(AUTO_KEEP_REMOTE));
            values.put(AUTO_KEEP_LOCAL_DATA, baseNode.getPropertyValue(AUTO_KEEP_LOCAL));

            this.loadFormData(values);
            if (this.form != null) {
                //((FormHeading)this.form.getHead()).setText(CoreManager.getInstance().makeJobLabel(baseNode, true));            
                updateFormActions();
            }
            if (this.logs != null)
                this.logs.loadSynchroLog(baseNode);

        } catch (URISyntaxException e) {
            Logger.getRootLogger().error("Synchro", e);
        }
    }

    public Map<String, String> getFormData() throws Exception {
        HashMap<String, String> values = new HashMap<String, String>();
        if (repoItems == null)
            throw new Exception("Please select a workspace first!");

        values.put("HOST", tfHost.getText());
        values.put("LOGIN", tfLogin.getText());
        values.put("PASSWORD", tfPassword.getText());
        values.put("TRUST_SSL", trustSSL.getSelection() ? "true" : "false");
        values.put("REPOSITORY_LABEL", currentRepoLabel);
        values.put("REPOSITORY_ID", currentRepoId);
        values.put("TARGET", tfTarget.getText());
        values.put("ACTIVE", (currentActiveState ? "true" : "false"));

        values.put(AUTO_KEEP_REMOTE_DATA, (autoKeepRemoteState ? "true" : "false"));
        values.put(AUTO_KEEP_LOCAL_DATA, (autoKeepLocalState ? "true" : "false"));

        String dir = "bi";
        if (comboDirection.getSelectionIndex() == 1)
            dir = "up";
        else if (comboDirection.getSelectionIndex() == 2)
            dir = "down";
        values.put("DIRECTION", dir);
        String freq = "minute";
        if (radioSyncInterval2.getSelection())
            freq = "hour";
        else if (radioSyncInterval3.getSelection())
            freq = "day";
        values.put("INTERVAL", freq);
        String max_depth = "3";
        if (radioServerLoadLow.getSelection())
            max_depth = "1";
        else if (radioServerLoadHigh.getSelection())
            max_depth = "-1";
        values.put("MAX_DEPTH", max_depth);
        return values;
    }

    public void loadFormData(Map<String, String> values) {
        tfHost.setText(values.get("HOST"));
        trustSSL.setEnabled(tfHost.getText().startsWith("https://"));
        trustSSL.setSelection(values.get("TRUST_SSL").equals("true"));
        tfLogin.setText(values.get("LOGIN"));
        tfPassword.setText(values.get("PASSWORD"));
        currentRepoLabel = values.get("REPOSITORY_LABEL");
        currentRepoId = values.get("REPOSITORY_ID");
        tfRepo.setText(currentRepoLabel);
        repoItems = new TreeMap<String, String>();
        repoItems.put(values.get("REPOSITORY_LABEL"), values.get("REPOSITORY_ID"));
        String repoTarget = values.get("TARGET");
        tfTarget.setText(repoTarget);
        currentActiveState = values.get("ACTIVE").equals("true");

        String dir = values.get("DIRECTION");
        int selectionIndex = 0;
        if (dir.equals("bi"))
            selectionIndex = 0;
        else if (dir.equals("up"))
            selectionIndex = 1;
        else if (dir.equals("down"))
            selectionIndex = 2;
        comboDirection.select(selectionIndex);

        radioSyncInterval1.setSelection(values.get("INTERVAL").equals("minute"));
        radioSyncInterval2.setSelection(values.get("INTERVAL").equals("hour"));
        radioSyncInterval3.setSelection(values.get("INTERVAL").equals("day"));

        if (values.get("MAX_DEPTH") != null) {
            radioServerLoadLow.setSelection(values.get("MAX_DEPTH").equals("1"));
            radioServerLoadMedium.setSelection(values.get("MAX_DEPTH").equals("3"));
            radioServerLoadHigh.setSelection(values.get("MAX_DEPTH").equals("-1"));
        } else {
            radioServerLoadMedium.setSelection(true);
        }

        autoKeepRemoteState = "true".equals(values.get(AUTO_KEEP_REMOTE_DATA));
        autoKeepLocalState = "true".equals(values.get(AUTO_KEEP_LOCAL_DATA));

        updateAutoKeeping(false);

        saveAction.setEnabled(false);

    }

    public void clearFormData() {
        tfHost.setText("");
        tfLogin.setText("");
        tfPassword.setText("");
        trustSSL.setEnabled(tfHost.getText().startsWith("https://"));
        if (comboRepository != null) {
            comboRepository.setItems(new String[0]);
        }
        if (tfRepo != null) {
            tfRepo.setText("");
        }
        repoItems = new TreeMap<String, String>();
        if (tfTarget != null) {
            tfTarget.setText("");
        }
        comboDirection.select(0);

        updateAutoKeeping(true);

        radioSyncInterval1.setSelection(false);
        radioSyncInterval2.setSelection(true);
        radioSyncInterval3.setSelection(false);

        radioServerLoadLow.setSelection(false);
        radioServerLoadMedium.setSelection(true);
        radioServerLoadHigh.setSelection(false);

        if (this.form != null) {
            updateFormActions();
            saveAction.setEnabled(false);
        }

        if (this.logs != null)
            this.logs.clearSynchroLog();

    }

    public Control getMouseHandler() {
        return this.form.getHead();
    }

    /**
     * Checks whetever server configuration is ok
     * 
     * @return
     */
    private boolean checkConfiguration() {
        final String host = tfHost.getText();
        final String login = tfLogin.getText();
        final String pass = tfPassword.getText();
        final boolean trust = trustSSL.getSelection();

        boolean serverOk = false;

        RestRequest rest = new RestRequest();
        try {
            Server s = new Server("Test", host, login, pass, trust, false);
            RestStateHolder.getInstance().setServer(s);
            AjxpAPI.getInstance().setServer(s);
            rest.throwAuthExceptions = true;
            rest.getHttpClient().clearCookies();
            rest.getDocumentContent(AjxpAPI.getInstance().getGetXmlRegistryUri());
            serverOk = true;
        } catch (javax.net.ssl.SSLPeerUnverifiedException sE) {
            MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                    CoreManager.getMessage("jobeditor_diag_badssl"));
        } catch (URISyntaxException e) {
            MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                    CoreManager.getMessage("jobeditor_diag_badserver"));
        } catch (Exception e) {
            MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                    CoreManager.getMessage("jobeditor_diag_baddata"));

        } finally {
            rest.release();
        }

        // check if repo is selected and local folder as well
        if (serverOk) {
            if (currentRepoId != null && !currentRepoId.trim().isEmpty() && tfTarget != null
                    && !tfTarget.isDisposed() && tfTarget.getText() != null
                    && !tfTarget.getText().trim().isEmpty()) {
                serverOk = true;
            } else {
                MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                        CoreManager.getMessage("jobeditor_diag_badlocal"));
                serverOk = false;
            }
        }

        return serverOk;
    }

    private void loadRepositories() {

        Logger.getRootLogger().debug("Updating combo repo");

        final String host = tfHost.getText();
        final String login = tfLogin.getText();
        final String pass = tfPassword.getText();
        final boolean trust = trustSSL.getSelection();

        this.getDisplay().asyncExec(new Runnable() {

            @Override
            public void run() {

                Server s;
                try {
                    s = new Server("Test", host, login, pass, trust, false);
                    RestStateHolder.getInstance().setServer(s);
                    AjxpAPI.getInstance().setServer(s);
                    RestRequest rest = new RestRequest();
                    rest.getHttpClient().clearCookies();
                    Document doc = rest.getDocumentContent(AjxpAPI.getInstance().getGetXmlRegistryUri());
                    rest.release();
                    NodeList mainTag = doc.getElementsByTagName("repositories");
                    if (mainTag.getLength() == 0) {
                        throw new Exception("No repositories found");
                    }
                    final NodeList repos = mainTag.item(0).getChildNodes();
                    repoItems = new TreeMap<String, String>();

                    if (repos != null && repos.getLength() > 0) {
                        for (int i = 0; i < repos.getLength(); i++) {
                            org.w3c.dom.Node xmlNode = repos.item(i);
                            NamedNodeMap attributes = xmlNode.getAttributes();
                            NodeList children = xmlNode.getChildNodes();
                            String label = "";
                            for (int k = 0; k < children.getLength(); k++) {
                                if (children.item(k).getNodeName().equals("label")) {
                                    label = children.item(k).getTextContent();
                                }
                            }
                            String accessType = attributes.getNamedItem("access_type").getNodeValue();
                            String repositoryId = attributes.getNamedItem("id").getNodeValue();
                            boolean excluded = false;
                            for (int p = 0; p < CoreManager.EXCLUDED_ACCESS_TYPES.length; p++) {
                                if (accessType.equalsIgnoreCase(CoreManager.EXCLUDED_ACCESS_TYPES[p])) {
                                    excluded = true;
                                    break;
                                }
                            }
                            if (excluded) {
                                continue;
                            }
                            repoItems.put(label, repositoryId);
                        }
                    }
                    comboRepository.setItems(repoItems.keySet().toArray(new String[0]));
                    comboRepository.forceFocus();
                    comboRepository.setListVisible(true);
                    comboRepository.addModifyListener(new ModifyListener() {
                        @Override
                        public void modifyText(ModifyEvent arg0) {
                            currentRepoLabel = comboRepository.getText();
                            currentRepoId = repoItems.get(currentRepoLabel);
                            getDisplay().asyncExec(new Runnable() {
                                @Override
                                public void run() {
                                    toggleRepositoryComponent();
                                    tfRepo.setText(currentRepoLabel);
                                }
                            });
                        }
                    });

                } catch (URISyntaxException e) {
                    toggleRepositoryComponent();
                    Logger.getRootLogger().error("Synchro", e);
                    saveAction.setEnabled(false);
                    MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                            CoreManager.getMessage("jobeditor_diag_baddata"));
                    return;
                } catch (Exception e) {
                    toggleRepositoryComponent();
                    Logger.getRootLogger().error("Synchro", e);
                    saveAction.setEnabled(false);
                    MessageDialog.openError(getShell(), CoreManager.getMessage("jobeditor_diag_baddata_title"),
                            CoreManager.getMessage("jobeditor_diag_baddata"));
                    return;
                }
            }
        });
    }

    public void populateToolkit() {

        toolkit = new FormToolkit(this.getDisplay());
        final Form form = toolkit.createForm(this);
        this.form = form;
        toolkit.decorateFormHeading(form);
        StackLayout sLayout = new StackLayout();
        form.getBody().setLayout(sLayout);

        connexionSection = configureSection(toolkit, form, CoreManager.getMessage("jobeditor_header_connection"),
                CoreManager.getMessage("jobeditor_legend_connection"), 1, false);
        sectionClient = toolkit.createComposite(connexionSection);
        GridLayout layout = new GridLayout();
        sectionClient.setLayout(layout);
        layout.numColumns = 3;
        layout.horizontalSpacing = 10;
        layout.verticalSpacing = 10;
        sLayout.topControl = connexionSection;
        connexionSection.setClient(sectionClient);
        stackData.get("connexion").put("SECTION", connexionSection);

        // HOST
        Label label = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_hostURL"));
        label.setLayoutData(getGridDataLabel());
        tfHost = toolkit.createText(sectionClient, "");
        tfHost.setLayoutData(getGridDataField(2));

        // TRUST
        label = toolkit.createLabel(sectionClient, "");
        label.setLayoutData(getGridDataLabel());
        trustSSL = toolkit.createButton(sectionClient, CoreManager.getMessage("jobeditor_trustSSL"), SWT.CHECK);
        trustSSL.setLayoutData(getGridDataField(2));
        trustSSL.setEnabled(false);

        tfHost.addListener(SWT.FocusOut, new Listener() {
            public void handleEvent(Event e) {
                String t = tfHost.getText().trim();
                if (!t.startsWith("http://") && !t.startsWith("https://")) {
                    tfHost.setText("http://" + t);
                }
                trustSSL.setEnabled(tfHost.getText().startsWith("https://"));
            }
        });

        // LOGIN
        label = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_login"));
        label.setLayoutData(getGridDataLabel());
        tfLogin = toolkit.createText(sectionClient, "");
        tfLogin.setLayoutData(getGridDataField(2));

        // PASSWORD
        label = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_password"));
        label.setLayoutData(getGridDataLabel());
        tfPassword = toolkit.createText(sectionClient, "", SWT.PASSWORD);
        tfPassword.setLayoutData(getGridDataField(2));

        // EXPLANATION LABEL
        Label t = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_workspace_hint"),
                SWT.WRAP | SWT.READ_ONLY);

        GridData ld = getGridDataField(3);
        if (this.heightHint > 0)
            ld.heightHint = this.heightHint * 4;
        else
            ld.heightHint = 45;
        t.setLayoutData(ld);

        // REPOSITORY CHOOSER
        label = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_repository"));
        label.setLayoutData(getGridDataLabel());

        linkLoadRepositories = toolkit.createImageHyperlink(sectionClient, SWT.NULL);
        linkLoadRepositories.setImage(new Image(getDisplay(), new ImageData(
                this.getClass().getClassLoader().getResourceAsStream("images/fa/blue/cloud-download.png"))));
        linkLoadRepositories.setLayoutData(new GridData(GridData.FILL));
        linkLoadRepositories.setUnderlined(false);
        linkLoadRepositories.addHyperlinkListener(new IHyperlinkListener() {
            @Override
            public void linkExited(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
            }

            @Override
            public void linkEntered(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
            }

            @Override
            public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
                if (tfRepo != null && (tfHost.getText().trim().equals("") || tfLogin.getText().trim().equals("")
                        || tfPassword.getText().trim().equals(""))) {
                    MessageBox dialog = new MessageBox(getShell(), SWT.ICON_WARNING | SWT.OK);
                    dialog.setText(CoreManager.getMessage("jobeditor_diag_noserverdata"));
                    dialog.setMessage(CoreManager.getMessage("jobeditor_diag_noserverdata_msg"));
                    dialog.open();
                    return;
                }
                toggleRepositoryComponent();
                if (comboRepository != null) {
                    loadRepositories();
                }
            }
        });

        tfRepo = toolkit.createText(sectionClient, "click to load the repositories...", SWT.READ_ONLY);
        tfRepo.setLayoutData(getGridDataField(1));
        tfRepo.setBackground(new Color(this.getDisplay(), 240, 240, 240));

        // TARGET FOLDER CHOOSER
        label = toolkit.createLabel(sectionClient, CoreManager.getMessage("jobeditor_localfolder"));
        label.setLayoutData(getGridDataLabel());

        buttonFileChooser = toolkit.createImageHyperlink(sectionClient, SWT.NULL);
        buttonFileChooser.setImage(new Image(getDisplay(), new ImageData(
                this.getClass().getClassLoader().getResourceAsStream("images/fa/blue/folder-open.png"))));
        buttonFileChooser.setUnderlined(false);
        buttonFileChooser.addHyperlinkListener(new IHyperlinkListener() {
            @Override
            public void linkExited(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
            }

            @Override
            public void linkEntered(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
            }

            @Override
            public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent arg0) {
                DirectoryDialog dialog = new DirectoryDialog(JobEditor.this.getShell());
                String res = dialog.open();
                if (res != null) {
                    tfTarget.setText(res);
                }
            }
        });
        tfTarget = toolkit.createText(sectionClient, "", SWT.READ_ONLY);
        tfTarget.setLayoutData(getGridDataField(1));
        tfTarget.setBackground(new Color(this.getDisplay(), 240, 240, 240));

        parametersSection = configureSection(toolkit, form, CoreManager.getMessage("jobeditor_header_execution"),
                CoreManager.getMessage("jobeditor_legend_execution"), 1, true);
        Composite sectionClient3 = toolkit.createComposite(parametersSection);
        TableWrapLayout layout2 = new TableWrapLayout();
        sectionClient3.setLayout(layout2);
        layout2.numColumns = 1;
        parametersSection.setClient(sectionClient3);
        stackData.get("parameters").put("SECTION", parametersSection);

        Label lab = toolkit.createLabel(sectionClient3, CoreManager.getMessage("jobeditor_direction") + " : ");
        lab.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        Composite rComp = toolkit.createComposite(sectionClient3);
        rComp.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        layout2 = new TableWrapLayout();
        layout2.numColumns = 1;
        rComp.setLayout(layout2);
        comboDirection = new Combo(sectionClient3, SWT.READ_ONLY | SWT.BORDER);
        comboDirection.setItems(new String[] { CoreManager.getMessage("jobeditor_bi"),
                CoreManager.getMessage("jobeditor_up"), CoreManager.getMessage("jobeditor_down") });
        //toolkit.adapt(comboDirection);
        TableWrapData test = new TableWrapData(TableWrapData.FILL_GRAB);
        test.maxWidth = 180;
        comboDirection.setLayoutData(test);
        comboDirection.select(0);
        comboDirection.addModifyListener(new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent event) {
                updateAutoKeeping(true);
            }
        });

        // checkbox for setting auto keeping remote
        keepAutoRemote = toolkit.createButton(sectionClient3, CoreManager.getMessage("jobeditor_autokeepremote"),
                SWT.CHECK);
        keepAutoRemote.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        // checkbox for setting auto keeping local
        keepAutoLocal = toolkit.createButton(sectionClient3, CoreManager.getMessage("jobeditor_autokeeplocal"),
                SWT.CHECK);
        keepAutoLocal.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));

        Label lab2 = toolkit.createLabel(sectionClient3, CoreManager.getMessage("jobeditor_frequency") + " : ");
        lab2.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        Composite rComp2 = toolkit.createComposite(sectionClient3);
        rComp2.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        layout2 = new TableWrapLayout();
        layout2.numColumns = 3;
        rComp2.setLayout(layout2);
        radioSyncInterval1 = toolkit.createButton(rComp2, CoreManager.getMessage("jobeditor_min"), SWT.RADIO);
        radioSyncInterval2 = toolkit.createButton(rComp2, CoreManager.getMessage("jobeditor_hours"), SWT.RADIO);
        radioSyncInterval3 = toolkit.createButton(rComp2, CoreManager.getMessage("jobeditor_days"), SWT.RADIO);
        radioSyncInterval2.setSelection(true);

        Label lab3 = toolkit.createLabel(sectionClient3,
                CoreManager.getMessage("jobeditor_radioserverlegend") + " : ", SWT.WRAP | SWT.READ_ONLY);

        TableWrapData twd = new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE);
        if (this.heightHint > 0)
            twd.heightHint = this.heightHint * 4;
        else
            twd.heightHint = 42;
        lab3.setLayoutData(twd);

        Composite rComp3 = toolkit.createComposite(sectionClient3);
        rComp3.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE));
        layout2 = new TableWrapLayout();
        layout2.numColumns = 3;
        rComp3.setLayout(layout2);
        radioServerLoadLow = toolkit.createButton(rComp3, CoreManager.getMessage("jobeditor_radioserverlow"),
                SWT.RADIO);
        radioServerLoadMedium = toolkit.createButton(rComp3, CoreManager.getMessage("jobeditor_radioservermedium"),
                SWT.RADIO);
        radioServerLoadHigh = toolkit.createButton(rComp3, CoreManager.getMessage("jobeditor_radioserverhigh"),
                SWT.RADIO);
        radioServerLoadMedium.setSelection(true);

        saveAction = new Action("Save", new ImageDescriptor() {
            @Override
            public ImageData getImageData() {
                return new ImageData(
                        this.getClass().getClassLoader().getResourceAsStream("images/fa/blue/check-circle-o.png"));
            }
        }) {
            @Override
            public void run() {
                super.run();
                if (saveConfig()) {
                    saveAction.setEnabled(false);
                }
            }
        };
        ModifyListener tfMod = new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent arg0) {
                saveAction.setEnabled(true);
            }
        };
        SelectionListener rSel = new SelectionListener() {

            @Override
            public void widgetSelected(SelectionEvent arg0) {
                saveAction.setEnabled(true);
            }

            @Override
            public void widgetDefaultSelected(SelectionEvent arg0) {
            }
        };
        tfHost.addModifyListener(tfMod);
        tfLogin.addModifyListener(tfMod);
        tfPassword.addModifyListener(tfMod);
        tfTarget.addModifyListener(tfMod);
        trustSSL.addSelectionListener(rSel);
        comboDirection.addModifyListener(tfMod);
        keepAutoRemote.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                super.widgetSelected(e);
                autoKeepRemoteState = keepAutoRemote.getSelection();
                autoKeepLocalState = false;
                updateAutoKeeping(false);
                saveAction.setEnabled(true);
            }
        });
        keepAutoLocal.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                super.widgetSelected(e);
                autoKeepRemoteState = false;
                autoKeepLocalState = keepAutoLocal.getSelection();
                updateAutoKeeping(false);
                saveAction.setEnabled(true);
            }
        });
        radioSyncInterval1.addSelectionListener(rSel);
        radioSyncInterval2.addSelectionListener(rSel);
        radioSyncInterval3.addSelectionListener(rSel);
        radioServerLoadLow.addSelectionListener(rSel);
        radioServerLoadMedium.addSelectionListener(rSel);
        radioServerLoadHigh.addSelectionListener(rSel);

        closeAction = new Action("Close", new ImageDescriptor() {
            @Override
            public ImageData getImageData() {
                return new ImageData(
                        this.getClass().getClassLoader().getResourceAsStream("images/fa/blue/times-circle-o.png"));
            }
        }) {
            @Override
            public void run() {
                super.run();
                if (saveAction.isEnabled()) {
                    MessageBox dialog = new MessageBox(getShell(), SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL);
                    dialog.setText(CoreManager.getMessage("jobeditor_diag_savenotchanges"));
                    dialog.setMessage(CoreManager.getMessage("jobeditor_diag_savenotchanges_msg"));
                    int returnCode = dialog.open();
                    if (returnCode == SWT.CANCEL)
                        return;
                }

                new AnimationRunner().runEffect(new AlphaEffect(getShell(), 255 /*initial value*/,
                        0 /*final value*/, 1500 /*duration*/, new ExpoOut() /*movement*/, new Runnable() {
                            @Override
                            public void run() {
                                closeConfig();
                            }
                        }, null /*run on cancel*/
                ));
            }
        };

        updateFormActions();

        logsSection = configureSection(toolkit, form, CoreManager.getMessage("jobeditor_header_execution"), null, 1,
                false);
        logs = new LogViewer(logsSection, SWT.NONE);
        logs.initGUI();
        logsSection.setClient(logs);
        stackData.get("logs").put("SECTION", logsSection);

        toolkit.paintBordersFor(sectionClient);
        toolkit.paintBordersFor(logs);
        toolkit.paintBordersFor(sectionClient3);
    }

    protected void toggleSection(String name, boolean animateSize) {

        if (stackData.get(name) == null)
            return;

        StackLayout sL = ((StackLayout) form.getBody().getLayout());

        int[] size = new int[2];
        sL.topControl = (Control) stackData.get(name).get("SECTION");
        size[0] = (Integer) stackData.get(name).get("WIDTH");
        size[1] = (Integer) stackData.get(name).get("HEIGHT");
        if (stackData.get(name).containsKey("FONT_HEIGHT")) {
            size[1] = (Integer) stackData.get(name).get("FONT_HEIGHT") * this.heightHint;
        }
        if (stackData.get(name).containsKey("FONT_WIDTH")) {
            size[0] = (Integer) stackData.get(name).get("FONT_WIDTH") * this.heightHint;
        }
        String os = System.getProperty("os.name").toLowerCase();
        if (os.indexOf("windows xp") == -1) {
            size[0] += 50;
            size[1] += 30;
        }

        Rectangle screen = getShell().getDisplay().getPrimaryMonitor().getClientArea();
        int top;
        int left;
        int margin = 10;
        if (anchorH.equals("bottom")) {
            top = screen.height - size[1] - margin;
        } else {
            top = margin;
        }
        if (anchorW.equals("right")) {
            left = screen.width - size[0] - margin;
        } else {
            left = margin;
        }

        Rectangle orig = getShell().getBounds();
        Rectangle r = new Rectangle(left, top, size[0], size[1]);
        if (animateSize) {
            new AnimationRunner()
                    .runEffect(new SetBoundsEffect(getShell(), orig, r, 1000, new ExpoOut(), null, null));
        } else {
            getShell().setAlpha(0);
            getShell().setBounds(r);
            new AnimationRunner().runEffect(new AlphaEffect(getShell(), 0 /*initial value*/, 255 /*final value*/,
                    2000 /*duration*/, new ExpoOut() /*movement*/, null, null /*run on cancel*/
            ));
        }

        updateFormActions();
        this.form.setText((String) stackData.get(name).get("LABEL"));
        this.layout();
    }

    protected void toggleRepositoryComponent() {
        if (comboRepository == null) {
            comboRepository = new Combo(sectionClient, SWT.BORDER | SWT.DROP_DOWN);
            comboRepository.setLayoutData(getGridDataField(1));
            comboRepository.setItems(new String[] { "Loading repositories..." });
            comboRepository.select(0);
            toolkit.adapt(comboRepository, true, true);
            comboRepository.moveAbove(tfRepo);
            tfRepo.dispose();
            sectionClient.layout(new Control[] { comboRepository });
            tfRepo = null;
        } else if (tfRepo == null) {
            tfRepo = toolkit.createText(sectionClient, "", SWT.READ_ONLY);
            tfRepo.setLayoutData(getGridDataField(1));
            tfRepo.moveAbove(comboRepository);
            comboRepository.dispose();
            sectionClient.layout(new Control[] { tfRepo });
            comboRepository = null;
            tfRepo.addModifyListener(new ModifyListener() {

                @Override
                public void modifyText(ModifyEvent arg0) {
                    saveAction.setEnabled(true);
                }
            });
        }
        sectionClient.redraw();
    }

    protected GridData getGridDataLabel() {
        GridData gd = new GridData(GridData.FILL);
        gd.horizontalAlignment = GridData.END;
        return gd;
    }

    protected GridData getGridDataField(int colspan) {
        GridData gd = new GridData(GridData.FILL_HORIZONTAL);
        gd.horizontalSpan = colspan;
        return gd;
    }

    protected TableWrapData getTWDataFillMiddle(int colspan) {
        return getTWDataFillMiddle(colspan, false);
    }

    protected TableWrapData getTWDataFillMiddle(int colspan, boolean wrap) {
        TableWrapData td = new TableWrapData((wrap ? TableWrapData.LEFT : TableWrapData.FILL_GRAB));
        td.valign = TableWrapData.MIDDLE;
        td.colspan = colspan;
        td.maxWidth = 200;
        return td;
    }

    protected void updateFormActions() {
        if (form == null)
            return;
        form.getToolBarManager().removeAll();
        form.getMenuManager().removeAll();

        Iterator<Entry<String, HashMap<String, Object>>> it = stackData.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, HashMap<String, Object>> e = it.next();
            final String key = e.getKey();
            final String label = (String) e.getValue().get("LABEL");
            final String icon = (String) e.getValue().get("ICON");
            Section sec = (Section) e.getValue().get("SECTION");

            Action a = new Action(label, new ImageDescriptor() {
                @Override
                public ImageData getImageData() {
                    return new ImageData(
                            this.getClass().getClassLoader().getResourceAsStream("images/" + icon + ".png"));
                }
            }) {
                @Override
                public void run() {
                    super.run();
                    toggleSection(key, true);
                }
            };
            if (((StackLayout) form.getBody().getLayout()).topControl == sec) {
                a.setEnabled(false);
            }
            form.getMenuManager().add(a);
        }

        form.getToolBarManager().add(saveAction);
        form.getToolBarManager().add(closeAction);

        form.getToolBarManager().update(true);

    }

    protected Section configureSection(FormToolkit toolkit, final Form form, String title, String description,
            int colspan, boolean expandable) {
        int style = Section.EXPANDED | Section.DESCRIPTION | Section.NO_TITLE;
        if (expandable) {
            //style = Section.TREE_NODE|Section.DESCRIPTION|Section.COMPACT;
        }
        Section section = toolkit.createSection(form.getBody(), style);
        section.descriptionVerticalSpacing = 6;
        section.clientVerticalSpacing = 8;
        section.marginWidth = 8;
        section.marginHeight = 6;

        TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB);
        td.colspan = colspan;
        section.setLayoutData(td);
        section.addExpansionListener(new ExpansionAdapter() {
            public void expansionStateChanged(ExpansionEvent e) {
                //form.reflow(true);
            }
        });
        //section.setText(title);
        //toolkit.createCompositeSeparator(section);
        if (description != null)
            section.setDescription(description);

        return section;
    }

    private void moveShellWithMouse(Control cont, final Shell shell) {

        // add ability to move shell around
        Listener moveListener = new Listener() {
            Point origin;

            public void handleEvent(Event e) {
                switch (e.type) {
                case SWT.MouseDown:
                    origin = new Point(e.x, e.y);
                    break;
                case SWT.MouseUp:
                    origin = null;
                    break;
                case SWT.MouseMove:
                    if (origin != null) {
                        Point p = shell.getDisplay().map(shell, null, e.x, e.y);
                        shell.setLocation(p.x - origin.x, p.y - origin.y);
                    }
                    break;
                }
            }
        };
        cont.addListener(SWT.MouseDown, moveListener);
        cont.addListener(SWT.MouseUp, moveListener);
        cont.addListener(SWT.MouseMove, moveListener);

    }

    protected void closeConfig() {
        sTray.closeConfiguration();
    }

    protected boolean saveConfig() {

        boolean serverOk = checkConfiguration();
        if (!serverOk) {
            return false;
        }
        try {
            Node n = CoreManager.getInstance().updateSynchroNode(getFormData(), currentSynchroNode);
            this.setCurrentNode(n);
            return true;
        } catch (SQLException e) {
            Logger.getRootLogger().error("Synchro", e);
        } catch (URISyntaxException e) {
            Logger.getRootLogger().error("Synchro", e);
        } catch (Exception e) {
            Logger.getRootLogger().error("Synchro", e);
        }
        return false;
    }

    protected void deleteConfig() {
        try {
            closeConfig();
            CoreManager.getInstance().deleteSynchroNode(currentSynchroNode);
        } catch (SchedulerException e) {
            Logger.getRootLogger().error("Synchro", e);
        } catch (SQLException e) {
            Logger.getRootLogger().error("Synchro", e);
        }
    }

    protected void setCurrentNode(Node n) {
        if (n == null) {
            currentSynchroNode = null;
            clearFormData();
            if (CoreManager.defaultHome != null) {
                tfTarget.setText(CoreManager.defaultHome);
            }
            logs.clearSynchroLog();
        } else {
            currentSynchroNode = n;
            loadFormFromNode(n);
            logs.loadSynchroLog(n);
        }
        updateTargetTextFieldEditable();
    }

    private void updateTargetTextFieldEditable() {
        // target editable if no node is selected!
        boolean targetEditable = currentSynchroNode == null;
        if (tfTarget != null) {
            tfTarget.setEnabled(targetEditable);
        }
        if (buttonFileChooser != null) {
            buttonFileChooser.setEnabled(targetEditable);
        }
    }

    public void notifyJobStateChanged(String nodeId, boolean running) {
        logs.reload();
    }

    /**
     * Updates autoKeeping checkbox states if reset - means, that user changed
     * direction option, and we need to set default states also
     * 
     * @param reset
     */
    private void updateAutoKeeping(boolean reset) {
        if (reset) {
            int index = comboDirection.getSelectionIndex();
            // BIDIRECTIONAL - both enabled and by default unselected - user
            // decides
            autoKeepLocalState = false;
            autoKeepRemoteState = false;
            keepAutoLocal.setEnabled(true);
            keepAutoRemote.setEnabled(true);
            if (index == 1) {
                // UPLOAD - local enabled and by default selected
                autoKeepLocalState = true;
                keepAutoLocal.setEnabled(true);
                keepAutoRemote.setEnabled(false);
            } else if (index == 2) {
                // DOWNLOAD - remote enabled and by default selected
                autoKeepRemoteState = true;
                keepAutoLocal.setEnabled(false);
                keepAutoRemote.setEnabled(true);
            }

        }
        keepAutoLocal.setSelection(autoKeepLocalState);
        keepAutoRemote.setSelection(autoKeepRemoteState);
    }
}