gt: 							if (e.getMessage() != null && !e.getMessage().isEmpty()) {
context: /**
   * Copyright (C) 2001-2019 by RapidMiner and the contributors
   * 
   * Complete list of developers available at our web site:
   * 
   * http://rapidminer.com
   * 
   * This program is free software: you can redistribute it and/or modify it under the terms of the
   * GNU Affero General Public License as published by the Free Software Foundation, either version 3
   * of the License, or (at your option) any later version.
   * 
   * This program 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
   * Affero General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License along with this program.
   * If not, see http://www.gnu.org/licenses/.
  */
  package com.rapidminer.repository.gui;
  
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dialog;
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.Transferable;
  import java.awt.datatransfer.UnsupportedFlavorException;
  import java.awt.event.KeyEvent;
  import java.awt.event.KeyListener;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.io.File;
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.logging.Level;
  import java.util.stream.Collectors;
  import javax.swing.Action;
  import javax.swing.Icon;
  import javax.swing.JComponent;
  import javax.swing.JPopupMenu;
  import javax.swing.JTree;
  import javax.swing.SwingUtilities;
  import javax.swing.event.EventListenerList;
  import javax.swing.event.TreeExpansionEvent;
  import javax.swing.event.TreeExpansionListener;
  import javax.swing.event.TreeSelectionEvent;
  import javax.swing.event.TreeSelectionListener;
  import javax.swing.tree.TreePath;
  import javax.swing.tree.TreeSelectionModel;
  
  import com.rapidminer.RepositoryProcessLocation;
  import com.rapidminer.gui.RapidMinerGUI;
  import com.rapidminer.gui.actions.OpenAction;
  import com.rapidminer.gui.actions.ToggleAction;
  import com.rapidminer.gui.dnd.AbstractPatchedTransferHandler;
  import com.rapidminer.gui.dnd.DragListener;
  import com.rapidminer.gui.dnd.RepositoryLocationList;
  import com.rapidminer.gui.dnd.TransferableOperator;
  import com.rapidminer.gui.dnd.TransferableRepositoryEntry;
  import com.rapidminer.gui.tools.ProgressThread;
  import com.rapidminer.gui.tools.ProgressThreadDialog;
  import com.rapidminer.gui.tools.RepositoryGuiTools;
  import com.rapidminer.gui.tools.ResourceActionAdapter;
  import com.rapidminer.gui.tools.SwingTools;
  import com.rapidminer.gui.tools.SwingTools.ResultRunnable;
  import com.rapidminer.gui.tools.components.ToolTipWindow;
  import com.rapidminer.gui.tools.components.ToolTipWindow.TipProvider;
  import com.rapidminer.gui.tools.components.ToolTipWindow.TooltipLocation;
  import com.rapidminer.gui.tools.dialogs.ConfirmDialog;
  import com.rapidminer.gui.tools.dialogs.SelectionDialog;
  import com.rapidminer.repository.DataEntry;
  import com.rapidminer.repository.Entry;
  import com.rapidminer.repository.Folder;
  import com.rapidminer.repository.ProcessEntry;
  import com.rapidminer.repository.Repository;
  import com.rapidminer.repository.RepositoryActionCondition;
  import com.rapidminer.repository.RepositoryActionConditionImplConfigRepository;
  import com.rapidminer.repository.RepositoryActionConditionImplStandard;
  import com.rapidminer.repository.RepositoryActionConditionImplStandardNoRepository;
  import com.rapidminer.repository.RepositoryException;
  import com.rapidminer.repository.RepositoryLocation;
  import com.rapidminer.repository.RepositoryManager;
  import com.rapidminer.repository.RepositorySortingMethod;
  import com.rapidminer.repository.RepositorySortingMethodListener;
  import com.rapidminer.repository.gui.actions.AbstractRepositoryAction;
  import com.rapidminer.repository.gui.actions.ConfigureRepositoryAction;
  import com.rapidminer.repository.gui.actions.CopyEntryRepositoryAction;
  import com.rapidminer.repository.gui.actions.CopyLocationAction;
  import com.rapidminer.repository.gui.actions.CreateFolderAction;
  import com.rapidminer.repository.gui.actions.CutEntryRepositoryAction;
  import com.rapidminer.repository.gui.actions.DeleteRepositoryEntryAction;
  import com.rapidminer.repository.gui.actions.OpenEntryAction;
  import com.rapidminer.repository.gui.actions.OpenInFileBrowserAction;
  import com.rapidminer.repository.gui.actions.PasteEntryRepositoryAction;
  import com.rapidminer.repository.gui.actions.RefreshRepositoryEntryAction;
  import com.rapidminer.repository.gui.actions.RenameRepositoryEntryAction;
  import com.rapidminer.repository.gui.actions.ShowProcessInRepositoryAction;
  import com.rapidminer.repository.gui.actions.SortByLastModifiedAction;
  import com.rapidminer.repository.gui.actions.SortByNameAction;
  import com.rapidminer.repository.gui.actions.StoreProcessAction;
  import com.rapidminer.repository.local.LocalRepository;
  import com.rapidminer.studio.io.gui.internal.DataImportWizardBuilder;
  import com.rapidminer.studio.io.gui.internal.DataImportWizardUtils;
  import com.rapidminer.tools.I18N;
  import com.rapidminer.tools.LogService;
  import com.rapidminer.tools.PasswordInputCanceledException;
  import com.rapidminer.tools.ProgressListener;
  import com.rapidminer.tools.usagestats.ActionStatisticsCollector;
  
  
  /**
   * A tree displaying repository contents.
   * <p>
   * To add new actions to the popup menu, call
   * {@link #addRepositoryAction(Class, RepositoryActionCondition, Class, boolean, boolean)} or
   * {@link #addRepositoryAction(Class, RepositoryActionCondition, boolean, boolean)}. Be sure to
   * follow its instructions carefully.
   *
   * @author Simon Fischer, Tobias Malbrecht, Marco Boeck, Adrian Wilke
   */
  public class RepositoryTree extends JTree {
  
  	/**
  	 * @author Nils Woehler, Adrian Wilke
  	 *
  	 */
  	private final class RepositoryTreeTransferhandler extends AbstractPatchedTransferHandler {
  
  		private static final long serialVersionUID = 1L;
  
  		// Remember whether the last cut/copy action was a MOVE
  		// A move will result in the entry being deleted upon drop / paste
  		// Unfortunately there is no easy way to know this from the TransferSupport
  		// passed to importData(). It is not even kno wn in createTransferable(), so we
  		// cannot even attach it to the Transferable
  		// This implementation implies that we can only transfer from one repository tree
  		// to the same instance since this state is not passed to other instances.
  		// REASON THIS IS HERE:
  		// ctrl+x followed by ctrl+v would copy the entry instead of moving it due to
  		// the way the transfer system is implemented. See RM-10 for further details.
  		int latestAction = 0;
  
  		public RepositoryTreeTransferhandler() {
  			addDragListener(new DragListener() {
  
  				@Override
  				public void dragStarted(Transferable t) {
  					// reset latestAction because a new drag makes the last action irrelevant
  					latestAction = 0;
  				}
  
  				@Override
  				public void dragEnded() {}
  			});
  		}
  
  		@Override
  		public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
  			List<DataFlavor> flavors = Arrays.asList(transferFlavors);
  			boolean contains = flavors.contains(DataFlavor.javaFileListFlavor);
  			contains |= flavors.contains(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_FLAVOR);
  			contains |= flavors.contains(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_LIST_FLAVOR);
  			return contains;
  		}
  
  		@Override
  		public boolean importData(final TransferSupport ts) {
  
  			// Determine where to insert
  			final Entry droppedOnEntry;
  			if (ts.isDrop()) {
  				Point dropPoint = ts.getDropLocation().getDropPoint();
  				TreePath path = getPathForLocation((int) dropPoint.getX(), (int) dropPoint.getY());
  				if (path == null) {
  					return false;
  				}
  				droppedOnEntry = (Entry) path.getLastPathComponent();
  			} else {
  				droppedOnEntry = getSelectedEntry();
  			}
  			if (droppedOnEntry == null) {
  				return false;
  			}
  
  			// Execute operation chosen by flavor
  			try {
  				List<DataFlavor> flavors = Arrays.asList(ts.getDataFlavors());
  
  				if (flavors.contains(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_FLAVOR)) {
  					// Single repository entry
  
  					final RepositoryLocation location = (RepositoryLocation) ts.getTransferable()
  							.getTransferData(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_FLAVOR);
  					List<RepositoryLocation> singleLocationList = new LinkedList<>();
  					singleLocationList.add(location);
  					return copyOrMoveRepositoryEntries(droppedOnEntry, singleLocationList, ts);
  
  				} else if (flavors.contains(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_LIST_FLAVOR)) {
  					// Multiple repository entries
  
  					Object transferData = ts.getTransferable()
  							.getTransferData(TransferableOperator.LOCAL_TRANSFERRED_REPOSITORY_LOCATION_LIST_FLAVOR);
  					List<RepositoryLocation> locations;
  					if (transferData instanceof RepositoryLocationList) {
  						locations = ((RepositoryLocationList) transferData).getAll();
  					} else if (transferData instanceof RepositoryLocation[]) {
  						locations = Arrays.asList((RepositoryLocation[]) transferData);
  					} else {
  						// should not happen
  						return false;
  					}
  					return copyOrMoveRepositoryEntries(droppedOnEntry, locations, ts);
  
  				} else if (flavors.contains(DataFlavor.javaFileListFlavor)) {
  					// Import file via wizard
  
  					@SuppressWarnings("unchecked")
  					List<File> files = (List<File>) ts.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
  					File file = files.get(0);
  					DataImportWizardBuilder builder = new DataImportWizardBuilder();
  					builder.setCallback(DataImportWizardUtils.showInResultsCallback());
  					builder.forFile(file.toPath()).build(owner).getDialog().setVisible(true);
  					return true;
  				} else {
  					// Flavor not supported
  					return false;
  				}
  			} catch (UnsupportedFlavorException e) {
  				LogService.getRoot().log(Level.WARNING, I18N.getMessage(LogService.getRoot().getResourceBundle(),
  						"com.rapidminer.repository.RepositoryTree.accepting_flavor_error", e), e);
  				return false;
  			} catch (IOException | RepositoryException | RuntimeException e) {
  				LogService.getRoot().log(Level.WARNING, I18N.getMessage(LogService.getRoot().getResourceBundle(),
  						"com.rapidminer.repository.RepositoryTree.error_during_drop", e), e);
  				return false;
  			}
  		}
  
  		/**
  		 * Copies / moves multiple repository locations.
  		 *
  		 * Additionally, at first it is checked, if the operations are allowed.
  		 */
  		private boolean copyOrMoveRepositoryEntries(final Entry droppedOnEntry, final List<RepositoryLocation> locations,
  				final TransferSupport ts) throws RepositoryException {
  
  			// First check, if operation is allowed for all locations
  			for (RepositoryLocation location : locations) {
  				if (!copyOrMoveCheck(droppedOnEntry, location, ts)) {
  					return false;
  				}
  			}
  
  			// Execute operations in new thread
  			new ProgressThread("copy_repository_entry", true) {
  
  				final class UserDecisions {
  
  					boolean repeatDecision = false;
  					boolean overwriteIfExists = false;
  					int lastDecision = 0;
  				}
  
  				private static final int INSERT = 1;
  				private static final int OVERWRITE = 2;
  				private static final int SKIP = 3;
  
  				/** Total progress of progress listener bar */
  				private int progressListenerCompleted = 0;
  
  				/** Step size for single entry operation */
  				private final int PROGRESS_LISTENER_SINGLE_STEP_SIZE = 100;
  
  				/**
  				 * Iteratively perform copy / move
  				 */
  				@Override
  				public void run() {
  
  					// Check, if repository is in location.
  					// Repositories can not be moved.
  					// This results in a copy operation.
  					boolean isRepositoryInLocations = false;
  					for (RepositoryLocation location : locations) {
  						try {
  							if (location.locateEntry() instanceof Repository) {
  								isRepositoryInLocations = true;
  							}
  						} catch (RepositoryException e) {
  							SwingTools.showSimpleErrorMessage("error_in_copy_repository_entry", e, location.toString(),
  									e.getMessage());
  							return;
  						}
  					}
  
  					boolean isSingleEntryOperation = true;
  					if (locations.size() > 1) {
  						isSingleEntryOperation = false;
  					}
  
  					TreePath droppedOnPath = RepositoryTreeModel.getPathTo(droppedOnEntry,
  							RepositoryManager.getInstance(null));
  
  					// Initialize progress listener
  					getProgressListener().setTotal(locations.size() * PROGRESS_LISTENER_SINGLE_STEP_SIZE);
  					getProgressListener().setCompleted(progressListenerCompleted);
  
  					final UserDecisions userDecisions = new UserDecisions();
  					locationLoop: for (RepositoryLocation location : locations) {
  
  						// Single entry check
  						try {
  							// Entry already exists, overwrite?
  							final String effectiveNewName = location.locateEntry().getName();
  							if (((Folder) droppedOnEntry).containsEntry(effectiveNewName)) {
  
  								// Do not confuse user with incorrect selected paths
  								RepositoryTree.this.setSelectionPath(droppedOnPath);
  
  								if (!userDecisions.repeatDecision) {
  
  									final List<String> optionsToSelect = new LinkedList<>();
  									optionsToSelect.add("existing_entry.insert");
  									optionsToSelect.add("existing_entry.overwrite");
  									optionsToSelect.add("existing_entry.skip");
  									final List<String> optionsToCheck = new LinkedList<>();
  									if (!isSingleEntryOperation) {
  										optionsToCheck.add("existing_entry.repeat");
  									}
  
  									int result = SwingTools.invokeAndWaitWithResult(new ResultRunnable<Integer>() {
  
  										@Override
  										public Integer run() {
  											SelectionDialog selectionDialog = new SelectionDialog(
  													ProgressThreadDialog.getInstance(), "existing_entry",
  													SelectionDialog.OK_CANCEL_OPTION, new String[] { effectiveNewName },
  													optionsToSelect, optionsToCheck).showDialog();
  
  											if (selectionDialog.isOptionSelected("existing_entry.insert")) {
  												userDecisions.lastDecision = INSERT;
  											} else if (selectionDialog.isOptionSelected("existing_entry.overwrite")) {
  												userDecisions.lastDecision = OVERWRITE;
  											} else {
  												userDecisions.lastDecision = SKIP;
  											}
  											if (selectionDialog.isOptionChecked("existing_entry.repeat")) {
  												userDecisions.repeatDecision = true;
  											}
  											return selectionDialog.getResult();
  										}
  									});
  
  									if (result != SelectionDialog.OK_OPTION) {
  										return;
  									}
  								}
  
  								switch (userDecisions.lastDecision) {
  									case INSERT:
  										userDecisions.overwriteIfExists = false;
  										break;
  									case OVERWRITE:
  										userDecisions.overwriteIfExists = true;
  										break;
  									case SKIP:
  									default:
  										continue locationLoop;
  								}
  							}
  						} catch (RepositoryException e) {
  							SwingTools.showSimpleErrorMessage("error_in_copy_repository_entry", e, location.toString(),
  									e.getMessage());
  							continue;
  						}
  
  						// Do copy or move operation
  						// Extracted to own method for lock handling and retry calls
  						boolean done = executeCopyOrMoveOperation(location, isRepositoryInLocations, isSingleEntryOperation,
  								userDecisions.overwriteIfExists);
  						if (!done) {
  							break;
  						}
  
  						progressListenerCompleted += PROGRESS_LISTENER_SINGLE_STEP_SIZE;
  					}
  
  					// On multi-operations, select the target folder after finishing copy/move
  					// operation
  					if (droppedOnEntry != null && !isSingleEntryOperation) {
  						SwingUtilities.invokeLater(new Runnable() {
  
  							@Override
  							public void run() {
  								TreePath droppedOnPath = RepositoryTreeModel.getPathTo(droppedOnEntry,
  										RepositoryManager.getInstance(null));
  								RepositoryTree.this.setSelectionPath(droppedOnPath);
  								RepositoryTree.this.scrollPathToVisible(droppedOnPath);
  							}
  						});
  					}
  
  					getProgressListener().complete();
  				}
  
  				/**
  				 * Runs the copy or move operation using {@link RepositoryManager}
  				 *
  				 * @return <code>false</code> if the user chose to cancel the operation;
  				 *         <code>true</code> otherwise
  				 */
  				private boolean executeCopyOrMoveOperation(RepositoryLocation location, boolean isRepositoryInLocations,
  						boolean isSingleEntryOperation, boolean overwriteIfExists) {
  					try {
  						ProgressListener progressListener = null;
  						progressListener = new RescalingProgressListener(getProgressListener(), progressListenerCompleted,
  								progressListenerCompleted + PROGRESS_LISTENER_SINGLE_STEP_SIZE);
  
  						if (isMoveOperation(ts, isRepositoryInLocations)) {
  							RepositoryManager.getInstance(null).move(location, (Folder) droppedOnEntry, null,
  									overwriteIfExists, progressListener);
  
  							// On drag and drop move operation with overwrite, two delete operations
  							// are performed. This results in a selection of a wrong tree element.
  							// For this case, select the element, which is the target of the drop
  							// operation.
  							if (overwriteIfExists && droppedOnEntry != null) {
  								SwingUtilities.invokeLater(() -> RepositoryTree.this.setSelectionPath(RepositoryTreeModel.getPathTo(droppedOnEntry,
  										RepositoryManager.getInstance(null))));
  
  							}
  
  						} else {
  							RepositoryManager.getInstance(null).copy(location, (Folder) droppedOnEntry, null,
  									overwriteIfExists, progressListener);
  						}
  					} catch (RepositoryException e) {
  						if (e.getCause() != null && e.getCause() instanceof PasswordInputCanceledException) {
  							// no extra dialog if login dialog was canceled
  							return false;
  						}
  						// Do not show "cancel" option, if is is an single entry operation
  						final int dialogMode = isSingleEntryOperation ? ConfirmDialog.YES_NO_OPTION : ConfirmDialog.YES_NO_CANCEL_OPTION;
  						final String locationName = location.getName() == null ? "" : location.getName();
  						final AtomicInteger result = new AtomicInteger();
  
  						SwingTools.invokeAndWait(() -> {
  							final ConfirmDialog dialog;
  