com.nextep.datadesigner.vcs.gui.dialog.MergeResultGUI.java Source code

Java tutorial

Introduction

Here is the source code for com.nextep.datadesigner.vcs.gui.dialog.MergeResultGUI.java

Source

/*******************************************************************************
 * Copyright (c) 2011 neXtep Software and contributors.
 * All rights reserved.
 *
 * This file is part of neXtep designer.
 *
 * NeXtep designer 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 any later version.
 *
 * NeXtep designer 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     neXtep Softwares - initial API and implementation
 *******************************************************************************/
/**
 *
 */
package com.nextep.datadesigner.vcs.gui.dialog;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Image;
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.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import com.nextep.datadesigner.exception.ErrorException;
import com.nextep.datadesigner.gui.impl.FontFactory;
import com.nextep.datadesigner.gui.model.WizardDisplayConnector;
import com.nextep.datadesigner.model.ChangeEvent;
import com.nextep.datadesigner.model.INamedObject;
import com.nextep.datadesigner.model.IReferenceable;
import com.nextep.datadesigner.vcs.gui.external.VersionablePaintItemListener;
import com.nextep.designer.vcs.model.DifferenceType;
import com.nextep.designer.vcs.model.IComparisonItem;
import com.nextep.designer.vcs.model.MergeStatus;
import com.nextep.designer.vcs.ui.VCSImages;
import com.nextep.designer.vcs.ui.VCSUIMessages;

/**
 * A display connector featuring the results of a merge operation.
 * This display is used for user validation and ambiguity resolving
 * before applying the merge.<br>
 * <br>
 * This display connector can be used as a wizard page.
 *
 * @author Christophe Fondacci
 *
 */
public class MergeResultGUI extends WizardDisplayConnector
        implements TreeListener, SelectionListener, MouseListener, MouseWheelListener {

    private static final int ADDITIONS = 0;
    private static final int UPDATES = 1;
    private static final int DELETIONS = 2;
    private static final int UNCHANGED = 3;
    private static final String[] msgKeys = { "comparison.additionNode", "comparison.updateNode",
            "comparison.removalNode", "comparison.unchangedNode" };

    private static final Log log = LogFactory.getLog(MergeResultGUI.class);
    private Composite gui = null; //  @jve:decl-index=0:visual-constraint="10,10"
    private Tree sourceTree = null;
    private Tree targetTree = null;
    private Tree mergedTree = null;
    private TreeItem[] sourceRoot = new TreeItem[4];
    private TreeItem[] targetRoot = new TreeItem[4];
    private TreeItem[] mergedRoot = new TreeItem[4];
    private Button hideButton = null;
    private boolean hideUnchanged = true;
    private SashForm sash = null;
    //   private Label       sourceLabel = null;
    //   private Label       targetLabel = null;
    //   private Label       mergedLabel = null;

    private IComparisonItem[] result;
    private MergeNavigator sourceConn;
    private boolean showMergeColumn = false;
    private boolean repositoryMergeWindow = false;
    private boolean noSort = false;
    private String sourceRootText, targetRootText, mergedRootText;
    /** A root item check state saver to determine user selection / deselection*/
    private boolean[] rootChecked = new boolean[] { false, false, false, false };

    public MergeResultGUI(boolean showMergeColumn, IComparisonItem... result) {
        super("Result", "Merge results", null);
        this.result = result;
        this.showMergeColumn = showMergeColumn;
        setRootText("", "", "");
        noSort = false;
    }

    public void setIsRepositoryMerge(boolean repositoryMergeWindow) {
        this.repositoryMergeWindow = repositoryMergeWindow;
    }

    public void setNoSort(boolean noSort) {
        this.noSort = noSort;
    }

    public void setRootText(String sourceText, String targetText, String mergedText) {
        sourceRootText = sourceText;
        targetRootText = targetText;
        mergedRootText = mergedText;
    }

    /**
     * @see com.nextep.datadesigner.gui.model.IDisplayConnector#createSWTControl(org.eclipse.swt.widgets.Composite)
     */
    @Override
    public Control createSWTControl(Composite parent) {
        GridData gridData2 = new GridData();
        gridData2.grabExcessHorizontalSpace = true;
        gridData2.verticalAlignment = GridData.FILL;
        gridData2.grabExcessVerticalSpace = true;
        gridData2.horizontalAlignment = GridData.FILL;
        gridData2.heightHint = 400;
        GridData gridData1 = new GridData();
        gridData1.grabExcessHorizontalSpace = true;
        gridData1.verticalAlignment = GridData.FILL;
        gridData1.grabExcessVerticalSpace = true;
        gridData1.horizontalAlignment = GridData.FILL;
        gridData1.heightHint = 400;
        GridData gridData = new GridData();
        gridData.grabExcessHorizontalSpace = true;
        gridData.verticalAlignment = GridData.FILL;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalAlignment = GridData.FILL;
        gridData.heightHint = 400;
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 3;
        if (showMergeColumn) {
            gridLayout.makeColumnsEqualWidth = true;
        }
        gui = new Composite(parent, SWT.NONE);
        addNoMarginLayout(gui, 3);
        //sShell.setText("Shell");
        //      gui.setLayout(gridLayout);
        //sShell.setSize(new Point(709, 293));
        //      sourceLabel = new Label(gui, SWT.NONE);
        //      sourceLabel.setText("Source release X.X.X.X on Branch Status");
        //      targetLabel = new Label(gui, SWT.NONE);
        //      targetLabel.setText("Target release X.X.X.X Status");
        //      mergedLabel = new Label(gui, SWT.NONE);
        //      mergedLabel.setText("Merge result release X.X.X.X Status");
        hideButton = new Button(gui, SWT.PUSH);
        hideButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
        hideButton.setText((hideUnchanged ? "Show" : "Hide") + " unchanged items");
        hideButton.addSelectionListener(this);
        sash = new SashForm(gui, SWT.NONE);
        sash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        //Building trees
        Composite src = new Composite(sash, SWT.NONE);
        addNoMarginLayout(src, 1);
        Label srcLabel = new Label(src, SWT.NONE);
        srcLabel.setText(sourceRootText);
        srcLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        sourceTree = new Tree(src, SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER);
        sourceTree.setLayoutData(gridData2);
        VersionablePaintItemListener.handle(sourceTree, false, false, true);

        Composite tgt = new Composite(sash, SWT.NONE);
        addNoMarginLayout(tgt, 1);
        Label tgtLabel = new Label(tgt, SWT.NONE);
        tgtLabel.setText(targetRootText);
        tgtLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        targetTree = new Tree(tgt,
                (repositoryMergeWindow ? SWT.CHECK : SWT.NONE) | SWT.FULL_SELECTION | SWT.BORDER);
        targetTree.setLayoutData(gridData1);
        VersionablePaintItemListener.handle(targetTree, false, false, true);

        Composite mrg = new Composite(sash, SWT.NONE);
        addNoMarginLayout(mrg, 1);
        Label mrgLabel = new Label(mrg, SWT.NONE);
        mrgLabel.setText(mergedRootText);
        mrgLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        mergedTree = new Tree(mrg,
                (repositoryMergeWindow ? SWT.CHECK : SWT.NONE) | SWT.FULL_SELECTION | SWT.BORDER);
        //      mergedTree.setVisible(showMergeColumn);
        mergedTree.setLayoutData(gridData);
        VersionablePaintItemListener.handle(mergedTree, false, false, true);

        // Hiding or showing merge column via sash form weights
        if (showMergeColumn) {
            sash.setWeights(new int[] { 1, 1, 1 });
        } else {
            sash.setWeights(new int[] { 1, 1, 0 });
        }

        // Initializing arrays for 3 nodes
        String[] nodeText = new String[] { VCSUIMessages.getString("comparison.additionNode"),
                VCSUIMessages.getString("comparison.updateNode"), VCSUIMessages.getString("comparison.removalNode"),
                VCSUIMessages.getString("comparison.unchangedNode") };
        Image[] nodeImages = new Image[] { VCSImages.ICON_DIFF_ADDED, VCSImages.ICON_DIFF_CHANGED,
                VCSImages.ICON_DIFF_REMOVED, null };
        // Initializing root trees
        for (int i = 0; i < 4; i++) {
            sourceRoot[i] = new TreeItem(sourceTree, NONE);
            targetRoot[i] = new TreeItem(targetTree, NONE);
            mergedRoot[i] = new TreeItem(mergedTree, NONE);
            sourceRoot[i].setImage(nodeImages[i]);
            targetRoot[i].setImage(nodeImages[i]);
            mergedRoot[i].setImage(nodeImages[i]);
            sourceRoot[i].setText(nodeText[i]);
            targetRoot[i].setText(nodeText[i]);
            mergedRoot[i].setText(nodeText[i]);
        }

        createMergeNavigators();

        //      sourceRoot.setExpanded(true);
        //      targetRoot.setExpanded(true);
        //      mergedRoot.setExpanded(true);

        for (int i = 0; i < 3; i++) {
            expandTreeItems(sourceRoot[i]);
        }
        //Adding tree listener
        sourceTree.addTreeListener(this);
        targetTree.addTreeListener(this);
        mergedTree.addTreeListener(this);
        sourceTree.addSelectionListener(this);
        targetTree.addSelectionListener(this);
        mergedTree.addSelectionListener(this);
        sourceTree.addMouseListener(this);
        targetTree.addMouseListener(this);
        mergedTree.addMouseListener(this);

        sourceTree.addMouseWheelListener(this);
        targetTree.addMouseWheelListener(this);
        mergedTree.addMouseWheelListener(this);

        sourceTree.getVerticalBar().addSelectionListener(this);
        targetTree.getVerticalBar().addSelectionListener(this);
        mergedTree.getVerticalBar().addSelectionListener(this);
        //      mergedTree.setVisible(showMergeColumn);
        gui.layout();

        return gui;
    }

    private void expandTreeItems(TreeItem root) {
        for (TreeItem i : root.getItems()) {
            final MergeNavigator m = (MergeNavigator) i.getData();
            final IComparisonItem item = (IComparisonItem) m.getModel();
            if (item.getMergeInfo().getStatus() == MergeStatus.MERGE_RESOLVED
                    && item.getMergeInfo().getMergeProposal() != item.getSource()
                    && item.getMergeInfo().getMergeProposal() != item.getTarget()) {
                m.getSourceItem().setExpanded(true);
                m.getTargetItem().setExpanded(true);
                m.getMergedItem().setExpanded(true);
                expandTreeItems(i);
            }
        }
    }

    private void createMergeNavigators() {
        // Sorting results by source name / target name
        final List<IComparisonItem> sortedResult = Arrays.asList(result);
        // Sorting items unless told not to do so
        if (!noSort) {
            Collections.sort(sortedResult, new Comparator<IComparisonItem>() {

                @Override
                public int compare(IComparisonItem o1, IComparisonItem o2) {
                    IReferenceable src = o1.getSource() == null ? o1.getTarget() : o1.getSource();
                    IReferenceable tgt = o2.getSource() == null ? o2.getTarget() : o2.getSource();
                    return ((INamedObject) src).getName().compareTo(((INamedObject) tgt).getName());
                }

            });
        }
        // Creating merge lines items
        ProgressMonitorDialog pd = new ProgressMonitorDialog(this.getShell());
        try {
            pd.run(false, false, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                    monitor.setTaskName("Initializing...");
                    monitor.beginTask("Preparing preview for user validation...", result.length);
                    for (IComparisonItem content : sortedResult) {
                        //                  if(!hideUnchanged || content.getDifferenceType()!=DifferenceType.EQUALS) {
                        int type = UPDATES;
                        switch (content.getDifferenceType()) {
                        case EQUALS:
                            if (hideUnchanged) {
                                continue;
                            }
                            type = UNCHANGED;
                            break;
                        case DIFFER:
                            type = UPDATES;
                            break;
                        case MISSING_SOURCE:
                            type = DELETIONS;
                            break;
                        case MISSING_TARGET:
                            type = ADDITIONS;
                            break;
                        }
                        sourceConn = new MergeNavigator(sourceRoot[type], targetRoot[type], mergedRoot[type],
                                content);
                        sourceConn.setShowAllChecks(repositoryMergeWindow);
                        if (content.getDifferenceType() != DifferenceType.EQUALS) {
                            sourceConn.showUnchangedItems(!hideUnchanged);
                        } else {
                            sourceConn.showUnchangedItems(true);
                        }
                        sourceConn.create(sourceRoot[type], -1);
                        sourceConn.initialize();
                        sourceConn.refreshConnector(false);
                        monitor.worked(1);
                    }
                    //               }
                    for (int i = 0; i < 4; i++) {
                        final int count = sourceRoot[i].getItemCount();
                        if (count > 0) {
                            sourceRoot[i].setText(VCSUIMessages.getString(msgKeys[i]) + " (" + count + ")");
                            sourceRoot[i].setFont(FontFactory.FONT_BOLD);
                            // Unchecking everything to ensure reprocessing 
                            sourceRoot[i].setChecked(false);
                            targetRoot[i].setChecked(false);
                            mergedRoot[i].setChecked(false);
                            // Processing gray checks
                            gray(sourceRoot[i]);
                            gray(targetRoot[i]);
                            gray(mergedRoot[i]);
                        } else {
                            sourceRoot[i].setText(VCSUIMessages.getString(msgKeys[i]));
                            sourceRoot[i].setFont(null);
                        }
                    }
                    monitor.done();
                }

            });
        } catch (Exception e) {
            throw new ErrorException(e);
        }
    }

    /**
     * This method recursively grays the check box of the treeitem
     * when at least one child is selected.
     * 
     * @param item TreeItem to gray
     * @return a boolean indicating when the specified item is grayed or fully selected 
     */
    private boolean gray(TreeItem item) {
        if (item.getChecked())
            return true;
        boolean childSelected = false;
        for (TreeItem child : item.getItems()) {
            if (gray(child)) {
                item.setGrayed(true);
                item.setChecked(true);
                childSelected = true;
            }
        }
        return childSelected;
    }

    /**
     * @see com.nextep.datadesigner.gui.model.IConnector#getModel()
     */
    @Override
    public Object getModel() {
        return result;
    }

    /**
     * @see com.nextep.datadesigner.gui.model.IConnector#getSWTConnector()
     */
    @Override
    public Control getSWTConnector() {
        return gui;
    }

    /**
     * @see com.nextep.datadesigner.gui.model.WizardDisplayConnector#refreshConnector()
     */
    @Override
    public void refreshConnector() {
        if (sourceConn != null) {
            sourceConn.refreshConnector();
        }
    }

    /**
     * @see org.eclipse.swt.events.TreeListener#treeCollapsed(org.eclipse.swt.events.TreeEvent)
     */
    @Override
    public void treeCollapsed(TreeEvent e) {
        itemAction(e, false);
    }

    /**
     * @see org.eclipse.swt.events.TreeListener#treeExpanded(org.eclipse.swt.events.TreeEvent)
     */
    @Override
    public void treeExpanded(TreeEvent e) {
        itemAction(e, true);
    }

    private void itemAction(TreeEvent e, boolean expanded) {
        TreeItem i = (TreeItem) e.item;
        if (i != null && i.getData() instanceof MergeNavigator) {
            MergeNavigator nav = (MergeNavigator) i.getData();
            nav.getSourceItem().setExpanded(expanded);
            nav.getTargetItem().setExpanded(expanded);
            nav.getMergedItem().setExpanded(expanded);
        } else {
            for (int j = 0; j < 4; j++) {
                if (sourceRoot[j] == i || targetRoot[j] == i || mergedRoot[j] == i) {
                    sourceRoot[j].setExpanded(expanded);
                    targetRoot[j].setExpanded(expanded);
                    mergedRoot[j].setExpanded(expanded);
                }
            }
        }
    }

    /**
     * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
     */
    @Override
    public void widgetDefaultSelected(SelectionEvent e) {
        widgetSelected(e);
    }

    /**
     * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
     */
    @Override
    public void widgetSelected(SelectionEvent e) {
        if (e.getSource() instanceof ScrollBar) {
            final Object source = e.getSource();
            MergeNavigator nav = null;
            if (source == sourceTree.getVerticalBar()) {
                nav = (MergeNavigator) sourceTree.getTopItem().getData();
            } else if (source == targetTree.getVerticalBar()) {
                nav = (MergeNavigator) targetTree.getTopItem().getData();
            } else if (source == mergedTree.getVerticalBar()) {
                nav = (MergeNavigator) mergedTree.getTopItem().getData();
            }
            if (nav != null) {
                sourceTree.setTopItem(nav.getSourceItem());
                targetTree.setTopItem(nav.getTargetItem());
                mergedTree.setTopItem(nav.getMergedItem());
            } else {
                for (int i = 0; i < 4; i++) {
                    if (source == sourceTree.getVerticalBar() && sourceRoot[i] == sourceTree.getTopItem()) {
                        targetTree.setTopItem(targetRoot[i]);
                        mergedTree.setTopItem(mergedRoot[i]);
                    } else if (source == targetTree.getVerticalBar() && targetRoot[i] == targetTree.getTopItem()) {
                        sourceTree.setTopItem(sourceRoot[i]);
                        mergedTree.setTopItem(mergedRoot[i]);
                    } else if (source == mergedTree.getVerticalBar() && mergedRoot[i] == mergedTree.getTopItem()) {
                        sourceTree.setTopItem(sourceRoot[i]);
                        targetTree.setTopItem(targetRoot[i]);
                    }
                }
                //            sourceTree.setTopItem(sourceTree.getItem(0));
                //            targetTree.setTopItem(targetTree.getItem(0));
                //            mergedTree.setTopItem(mergedTree.getItem(0));
            }
        } else if (e.getSource() == hideButton) {
            hideUnchanged = !hideUnchanged;
            for (int i = 0; i < 4; i++) {
                sourceRoot[i].removeAll();
                targetRoot[i].removeAll();
                mergedRoot[i].removeAll();
            }
            createMergeNavigators();
            //         sourceRoot.setExpanded(true);
            //         targetRoot.setExpanded(true);
            //         mergedRoot.setExpanded(true);
            for (int i = 0; i < 4; i++) {
                expandTreeItems(sourceRoot[i]);
            }
            hideButton.setText((hideUnchanged ? "Show" : "Hide") + " unchanged items");
        } else if (e.item != null && e.item.getData() instanceof MergeNavigator) {
            MergeNavigator nav = (MergeNavigator) e.item.getData();
            sourceTree.setSelection(nav.getSourceItem());
            targetTree.setSelection(nav.getTargetItem());
            mergedTree.setSelection(nav.getMergedItem());
            if (e.detail == SWT.CHECK) {
                final TreeItem item = nav.getSourceItem();
                nav.handleEvent(ChangeEvent.SELECTION_CHANGED, null, (!item.getChecked() || !item.getGrayed()));
            }
        } else {
            if (e.detail == SWT.CHECK) {
                for (int j = 0; j < 4; j++) {
                    if (e.item == sourceRoot[j] || e.item == targetRoot[j] || e.item == mergedRoot[j]) {
                        // If a root is selected, selecting all child items
                        final TreeItem item = (TreeItem) e.item;
                        boolean checked = item.getChecked();
                        item.setGrayed(false);
                        //                  if(rootChecked[j]!=checked) {
                        for (TreeItem child : ((TreeItem) e.item).getItems()) {
                            child.setChecked(checked);
                            if (child.getData() instanceof MergeNavigator) {
                                MergeNavigator nav = (MergeNavigator) child.getData();
                                //                           sourceTree.setSelection(nav.getSourceItem());
                                //                           targetTree.setSelection(nav.getTargetItem());
                                //                           mergedTree.setSelection(nav.getMergedItem());
                                nav.handleEvent(ChangeEvent.SELECTION_CHANGED, null, !checked);
                                //                           nav.selectProposal((IComparisonItem)nav.getModel(), checked ? Proposal.SOURCE : Proposal.TARGET, true);
                                //                           nav.fullRefresh();
                            }
                        }
                        //                     rootChecked[j]=checked;
                        //                  }
                    }
                }
            }
        }
    }

    /**
     * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
     */
    @Override
    public void mouseDoubleClick(MouseEvent e) {
        //      // We arbitrarily take the source item to retrieve the merge
        //      // navigator which contains the comparison item as item data
        //      TreeItem[] sel = sourceTree.getSelection();
        //      if(sel.length>0) {
        //         if(sel[0].getData()==null) return;
        //         final INavigatorConnector conn = ((INavigatorConnector)sel[0].getData()); 
        //         IComparisonItem comp = (IComparisonItem)conn.getModel();
        //         MergeResultGUI mergeGUI = new MergeResultGUI(true,comp.getSubItems().toArray(new IComparisonItem[comp.getSubItems().size()]));
        //         mergeGUI.setIsRepositoryMerge(true); //NoSort(true);
        //         mergeGUI.setRootText(
        //               "Source",
        //               "Target",
        //               "Merge preview");
        //         try {
        //            mergeGUI.setNoSort(true);
        //            new GUIWrapper(mergeGUI,"Merge results",800,600).invoke();
        //            conn.refreshConnector();
        //         } catch(CancelException ce) {
        //            log.debug(ce);
        //         }
        //      }

    }

    /**
     * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
     */
    @Override
    public void mouseDown(MouseEvent e) {
    }

    /**
     * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
     */
    @Override
    public void mouseUp(MouseEvent e) {
    }

    @Override
    public void mouseScrolled(MouseEvent e) {
        MergeNavigator nav = null;
        if (e.widget == sourceTree) {
            nav = (MergeNavigator) sourceTree.getTopItem().getData();
        } else if (e.widget == targetTree) {
            nav = (MergeNavigator) targetTree.getTopItem().getData();
        } else if (e.widget == mergedTree) {
            nav = (MergeNavigator) mergedTree.getTopItem().getData();
        }
        if (nav != null) {
            sourceTree.setTopItem(nav.getSourceItem());
            targetTree.setTopItem(nav.getTargetItem());
            mergedTree.setTopItem(nav.getMergedItem());
        } else {
            Widget source = e.widget;
            for (int i = 0; i < 4; i++) {
                if (source == sourceTree && sourceRoot[i] == sourceTree.getTopItem()) {
                    targetTree.setTopItem(targetRoot[i]);
                    mergedTree.setTopItem(mergedRoot[i]);
                } else if (source == targetTree && targetRoot[i] == targetTree.getTopItem()) {
                    sourceTree.setTopItem(sourceRoot[i]);
                    mergedTree.setTopItem(mergedRoot[i]);
                } else if (source == mergedTree && mergedRoot[i] == mergedTree.getTopItem()) {
                    sourceTree.setTopItem(sourceRoot[i]);
                    targetTree.setTopItem(targetRoot[i]);
                }
            }
        }
    }
}