gt:                         if (_tabbedPane.getTabCount() > 1) {
context: /**
   * DataCleaner (community edition)
   * Copyright (C) 2014 Neopost - Customer Information Management
   *
   * This copyrighted material is made available to anyone wishing to use, modify,
   * copy, or redistribute it subject to the terms and conditions of the GNU
   * Lesser General Public License, as published by the Free Software Foundation.
   *
   * 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 Lesser General Public License
   * for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this distribution; if not, write to:
   * Free Software Foundation, Inc.
   * 51 Franklin Street, Fifth Floor
   * Boston, MA  02110-1301  USA
   */
  package org.datacleaner.windows;
  
  import java.awt.BorderLayout;
  import java.awt.Dimension;
  import java.awt.Image;
  import java.awt.Toolkit;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.WindowEvent;
  import java.awt.event.WindowListener;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Comparator;
  import java.util.IdentityHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import javax.inject.Inject;
  import javax.swing.AbstractButton;
  import javax.swing.Icon;
  import javax.swing.JButton;
  import javax.swing.JComponent;
  import javax.swing.JFrame;
  import javax.swing.JMenuItem;
  import javax.swing.SwingConstants;
  import javax.swing.SwingUtilities;
  import javax.swing.border.Border;
  import javax.swing.border.CompoundBorder;
  import javax.swing.border.EmptyBorder;
  import javax.swing.border.MatteBorder;
  
  import org.apache.commons.vfs2.FileObject;
  import org.apache.metamodel.schema.Table;
  import org.apache.metamodel.util.Func;
  import org.apache.metamodel.util.Ref;
  import org.datacleaner.actions.ExportResultToHtmlActionListener;
  import org.datacleaner.actions.PublishResultToMonitorActionListener;
  import org.datacleaner.actions.SaveAnalysisResultActionListener;
  import org.datacleaner.api.AnalyzerResult;
  import org.datacleaner.api.ComponentMessage;
  import org.datacleaner.api.ExecutionLogMessage;
  import org.datacleaner.api.InputRow;
  import org.datacleaner.bootstrap.WindowContext;
  import org.datacleaner.configuration.DataCleanerConfiguration;
  import org.datacleaner.connection.Datastore;
  import org.datacleaner.guice.JobFile;
  import org.datacleaner.guice.Nullable;
  import org.datacleaner.job.AnalysisJob;
  import org.datacleaner.job.AnalyzerJob;
  import org.datacleaner.job.ComponentJob;
  import org.datacleaner.job.FilterJob;
  import org.datacleaner.job.ImmutableAnalyzerJob;
  import org.datacleaner.job.TransformerJob;
  import org.datacleaner.job.concurrent.PreviousErrorsExistException;
  import org.datacleaner.job.runner.AnalysisJobCancellation;
  import org.datacleaner.job.runner.AnalysisJobMetrics;
  import org.datacleaner.job.runner.AnalysisListener;
  import org.datacleaner.job.runner.AnalysisListenerAdaptor;
  import org.datacleaner.job.runner.ComponentMetrics;
  import org.datacleaner.job.runner.RowProcessingMetrics;
  import org.datacleaner.panels.DCBannerPanel;
  import org.datacleaner.panels.DCPanel;
  import org.datacleaner.panels.result.AnalyzerResultPanel;
  import org.datacleaner.panels.result.ProgressInformationPanel;
  import org.datacleaner.result.AnalysisResult;
  import org.datacleaner.result.renderer.RendererFactory;
  import org.datacleaner.user.UserPreferences;
  import org.datacleaner.util.AnalysisRunnerSwingWorker;
  import org.datacleaner.util.IconUtils;
  import org.datacleaner.util.ImageManager;
  import org.datacleaner.util.LabelUtils;
  import org.datacleaner.util.StringUtils;
  import org.datacleaner.util.WidgetFactory;
  import org.datacleaner.util.WidgetUtils;
  import org.datacleaner.util.WindowSizePreferences;
  import org.datacleaner.widgets.DCPersistentSizedPanel;
  import org.datacleaner.widgets.PopupButton;
  import org.datacleaner.widgets.PopupButton.MenuPosition;
  import org.datacleaner.widgets.tabs.Tab;
  import org.datacleaner.widgets.tabs.VerticalTabbedPane;
  import org.jdesktop.swingx.VerticalLayout;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Window in which the result (and running progress information) of job
   * execution is shown.
   */
  public final class ResultWindow extends AbstractWindow implements WindowListener {
      private static final Logger logger = LoggerFactory.getLogger(ResultWindow.class);
  
      public static final List<Func<ResultWindow, JComponent>> PLUGGABLE_BANNER_COMPONENTS = new ArrayList<>(
              0);
      private static final long serialVersionUID = 1L;
      private static final ImageManager imageManager = ImageManager.get();
  
      private final VerticalTabbedPane _tabbedPane;
      private final Map<ComponentJob, Tab<AnalyzerResultPanel>> _resultPanels;
      private final AnalysisJob _job;
      private final DataCleanerConfiguration _configuration;
      private final ProgressInformationPanel _progressInformationPanel;
      private final RendererFactory _rendererFactory;
      private final FileObject _jobFilename;
      private final AnalysisRunnerSwingWorker _worker;
      private final UserPreferences _userPreferences;
      private final JButton _cancelButton;
      private final PopupButton _saveResultsPopupButton;
      private final WindowSizePreferences _windowSizePreference;
  
      private AnalysisResult _result;
  
      /**
       *
       * @param configuration
       * @param job
       *            either this or result must be available
       * @param result
       *            either this or job must be available
       * @param jobFilename
       * @param windowContext
       * @param userPreferences
       * @param rendererFactory
       */
      @Inject
      protected ResultWindow(DataCleanerConfiguration configuration, @Nullable AnalysisJob job,
              @Nullable AnalysisResult result, @Nullable @JobFile FileObject jobFilename, WindowContext windowContext,
              UserPreferences userPreferences, RendererFactory rendererFactory) {
          super(windowContext);
          final boolean running = (result == null);
  
          _resultPanels = new IdentityHashMap<>();
          _configuration = configuration;
          _job = job;
          _jobFilename = jobFilename;
          _userPreferences = userPreferences;
          _rendererFactory = rendererFactory;
  
          final Ref<AnalysisResult> resultRef = new Ref<AnalysisResult>() {
              @Override
              public AnalysisResult get() {
                  return getResult();
              }
          };
  
          Border buttonBorder = new CompoundBorder(WidgetUtils.BORDER_LIST_ITEM_SUBTLE, new EmptyBorder(10, 4, 10, 4));
          _cancelButton = WidgetFactory.createDefaultButton("Cancel job", IconUtils.ACTION_STOP);
          _cancelButton.setHorizontalAlignment(SwingConstants.LEFT);
          _cancelButton.setBorder(buttonBorder);
  
          _saveResultsPopupButton = WidgetFactory.createDefaultPopupButton("Save results", IconUtils.ACTION_SAVE_DARK);
          _saveResultsPopupButton.setHorizontalAlignment(SwingConstants.LEFT);
          _saveResultsPopupButton.setBorder(buttonBorder);
          _saveResultsPopupButton.setMenuPosition(MenuPosition.TOP);
          _saveResultsPopupButton.getMenu().setBorder(new MatteBorder(1, 0, 0, 1, WidgetUtils.BG_COLOR_MEDIUM));
  
          JMenuItem saveAsFileItem = WidgetFactory.createMenuItem("Save as result file", IconUtils.ACTION_SAVE_DARK);
          saveAsFileItem.addActionListener(new SaveAnalysisResultActionListener(resultRef, _userPreferences));
          saveAsFileItem.setBorder(buttonBorder);
          _saveResultsPopupButton.getMenu().add(saveAsFileItem);
  
          JMenuItem exportToHtmlItem = WidgetFactory.createMenuItem("Export to HTML", IconUtils.WEBSITE);
          exportToHtmlItem.addActionListener(new ExportResultToHtmlActionListener(resultRef, _configuration,
                  _userPreferences));
          exportToHtmlItem.setBorder(buttonBorder);
          _saveResultsPopupButton.getMenu().add(exportToHtmlItem);
  
          JMenuItem publishToServerItem = WidgetFactory.createMenuItem("Publish to server", IconUtils.MENU_DQ_MONITOR);
          publishToServerItem.addActionListener(new PublishResultToMonitorActionListener(getWindowContext(),
                  _userPreferences, resultRef, _jobFilename));
          publishToServerItem.setBorder(buttonBorder);
          _saveResultsPopupButton.getMenu().add(publishToServerItem);
  
          _tabbedPane = new VerticalTabbedPane() {
              private static final long serialVersionUID = 1L;
  
              @Override
              protected JComponent wrapInCollapsiblePane(final JComponent originalPanel) {
                  DCPanel buttonPanel = new DCPanel();
                  buttonPanel.setLayout(new VerticalLayout());
                  buttonPanel.setBorder(new MatteBorder(1, 0, 0, 0, WidgetUtils.BG_COLOR_MEDIUM));
  
                  buttonPanel.add(_saveResultsPopupButton);
                  buttonPanel.add(_cancelButton);
  
                  DCPanel wrappedPanel = new DCPanel();
                  wrappedPanel.setLayout(new BorderLayout());
                  wrappedPanel.add(originalPanel, BorderLayout.CENTER);
                  wrappedPanel.add(buttonPanel, BorderLayout.SOUTH);
                  return super.wrapInCollapsiblePane(wrappedPanel);
              }
          };
  
          final Dimension size = getDefaultWindowSize();
          _windowSizePreference = new WindowSizePreferences(_userPreferences, getClass(), size.width, size.height);
          _progressInformationPanel = new ProgressInformationPanel(running);
          _tabbedPane.addTab("Progress information",
                  imageManager.getImageIcon("images/model/progress_information.png", IconUtils.ICON_SIZE_TAB),
                  _progressInformationPanel);
  
          for (Func<ResultWindow, JComponent> pluggableComponent : PLUGGABLE_BANNER_COMPONENTS) {
              JComponent component = pluggableComponent.eval(this);
              if (component != null) {
                  if (component instanceof AbstractButton) {
                      AbstractButton button = (AbstractButton) component;
                      JMenuItem menuItem = WidgetFactory.createMenuItem(button.getText(), button.getIcon());
                      for (ActionListener listener : button.getActionListeners()) {
                          menuItem.addActionListener(listener);
                      }
                      menuItem.setBorder(buttonBorder);
                      _saveResultsPopupButton.getMenu().add(menuItem);
                  } else if (component instanceof JMenuItem) { // TODO: Not possible. JMenuItem is a subclass of AbstractButton. Reorder or remove?
                      JMenuItem menuItem = (JMenuItem) component;
                      menuItem.setBorder(buttonBorder);
                      _saveResultsPopupButton.getMenu().add(menuItem);
                  }
              }
          }
  
          if (running) {
              // run the job in a swing worker
              _result = null;
              _worker = new AnalysisRunnerSwingWorker(_configuration, _job, this);
  
              _cancelButton.addActionListener(new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent e) {
                      _worker.cancelIfRunning();
                  }
              });
          } else {
              // don't add the progress information, simply render the job asap
              _result = result;
              _worker = null;
  
              final Map<ComponentJob, AnalyzerResult> map = result.getResultMap();
              for (Entry<ComponentJob, AnalyzerResult> entry : map.entrySet()) {
                  final ComponentJob componentJob = entry.getKey();
                  final AnalyzerResult analyzerResult = entry.getValue();
  
                  addResult(componentJob, analyzerResult);
              }
              _progressInformationPanel.onSuccess();
  
              WidgetUtils.invokeSwingAction(new Runnable() {
                  @Override
                  public void run() {
                      if (_tabbedPane.getTabCount() > 1) {
                          // switch to the first available result panel
                          _tabbedPane.setSelectedIndex(1);
                      }
                  }
              });
          }
  
          updateButtonVisibility(running);
      }
  
      public void startAnalysis() {
          _worker.execute();
      }
  
      private Dimension getDefaultWindowSize() {
          final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
          final int screenWidth = screenSize.width;
          final int screenHeight = screenSize.height;
  
          int height = 550;
          if (screenHeight > 1000) {
              height = 900;
          } else if (screenHeight > 750) {
              height = 700;
          }
  
          int width = 750;
          if (screenWidth > 1200) {
              width = 1100;
          } else if (screenWidth > 1000) {
              width = 900;
          }
  
          return new Dimension(width, height);
      }
  
      public Tab<AnalyzerResultPanel> getOrCreateResultPanel(final ComponentJob componentJob, boolean finished) {
          synchronized (_resultPanels) {
              final Tab<AnalyzerResultPanel> existingTab = _resultPanels.get(componentJob);
              if (existingTab != null) {
                  return existingTab;
              }
  
              String title = LabelUtils.getLabel(componentJob, false, false, false);
              if (title.length() > 40) {
                  title = title.substring(0, 39) + "...";
              }
  
              final Icon icon = IconUtils.getDescriptorIcon(componentJob.getDescriptor(), IconUtils.ICON_SIZE_TAB);
              final AnalyzerResultPanel resultPanel = new AnalyzerResultPanel(_rendererFactory,
                      _progressInformationPanel, componentJob);
              final Tab<AnalyzerResultPanel> tab = _tabbedPane.addTab(title, icon, resultPanel);
              tab.setTooltip(LabelUtils.getLabel(componentJob, false, true, true));
  
              _resultPanels.put(componentJob, tab);
  
              return tab;
          }
      }
  
      public void addResult(final ComponentJob componentJob, final AnalyzerResult result) {
          final Tab<AnalyzerResultPanel> tab = getOrCreateResultPanel(componentJob, true);
          tab.getContents().setResult(result);
      }
  
      @Override
      protected boolean isWindowResizable() {
          return true;
      }
  
      @Override
      protected boolean isCentered() {
          return true;
      }
  
      @Override
      public String getWindowTitle() {
          String title = "Analysis results";
  
          String datastoreName = getDatastoreName();
          if (!StringUtils.isNullOrEmpty(datastoreName)) {
              title = datastoreName + " | " + title;
          }
  
          if (_jobFilename != null) {
              title = _jobFilename.getName().getBaseName() + " | " + title;
          }
          return title;
      }
  
      private String getDatastoreName() {
          if (_job != null) {
              Datastore datastore = _job.getDatastore();
              if (datastore != null) {
                  String datastoreName = datastore.getName();
                  if (!StringUtils.isNullOrEmpty(datastoreName)) {
                      return datastoreName;
                  }
              }
          }
          return null;
      }
  
      @Override
      public Image getWindowIcon() {
          return imageManager.getImage(IconUtils.MODEL_RESULT);
      }
  
      @Override
      protected boolean onWindowClosing() {
          boolean closing = super.onWindowClosing();
          if (closing) {
              if (_worker != null) {
                  _worker.cancelIfRunning();
              }
          }
          return closing;
      }
  
      @Override
      protected JComponent getWindowContent() {
          final String datastoreName = getDatastoreName();
          String bannerTitle = "Analysis results";
          if (!StringUtils.isNullOrEmpty(datastoreName)) {
              bannerTitle = bannerTitle + " | " + datastoreName;
  
              if (_jobFilename != null) {
                  bannerTitle = bannerTitle + " | " + _jobFilename.getName().getBaseName();
              }
          }
  
          final DCBannerPanel banner = new DCBannerPanel(imageManager.getImage("images/window/banner-results.png"),
                  bannerTitle);
          _tabbedPane.addListener(new VerticalTabbedPane.Listener() {
              @Override
              public void stateChanged(int newIndex, Tab<?> newTab) {
                  banner.setTitle2(newTab.getTitle());
                  banner.updateUI();
              }
          });
  
          final DCPanel panel = new DCPersistentSizedPanel(WidgetUtils.COLOR_DEFAULT_BACKGROUND, _windowSizePreference);
          panel.setLayout(new BorderLayout());
          panel.add(banner, BorderLayout.NORTH);
          panel.add(_tabbedPane, BorderLayout.CENTER);
          return panel;
      }
  
      public AnalysisResult getResult() {
          if (_result == null && _worker != null) {
              try {
                  _result = _worker.get();
              } catch (Exception e) {
                  WidgetUtils.showErrorMessage("Unable to fetch result", e);
              }
          }
          return _result;
      }
  
      /**
       * Sets the result, when it is ready for eg. saving
       *
       * @param result
       */
      public void setResult(AnalysisResult result) {
          _result = result;
      }
  
      public RendererFactory getRendererFactory() {
          return _rendererFactory;
      }
  
      public ProgressInformationPanel getProgressInformationPanel() {
          return _progressInformationPanel;
      }
  
      public FileObject getJobFilename() {
          return _jobFilename;
      }
  
      public DataCleanerConfiguration getConfiguration() {
          return _configuration;
      }
  
      public AnalysisJob getJob() {
          return _job;
      }
  
      public UserPreferences getUserPreferences() {
          return _userPreferences;
      }
  
      public void onUnexpectedError(AnalysisJob job, Throwable throwable) {
          if (throwable instanceof AnalysisJobCancellation) {
              _progressInformationPanel.onCancelled();
              _cancelButton.setEnabled(false);
              return;
          } else if (throwable instanceof PreviousErrorsExistException) {
              // do nothing
              return;
          }
          _progressInformationPanel.addUserLog("An error occurred in the analysis job!", throwable, true);
      }
  
      public AnalysisListener createAnalysisListener() {
          return new AnalysisListenerAdaptor() {
              @Override
              public void jobBegin(AnalysisJob job, AnalysisJobMetrics metrics) {
                  updateButtonVisibility(true);
                  _progressInformationPanel.onBegin();
              }
  
              @Override
              public void jobSuccess(AnalysisJob job, AnalysisJobMetrics metrics) {
                  WidgetUtils.invokeSwingAction(new Runnable() {
                      @Override
                      public void run() {
                          updateButtonVisibility(false);
                          _progressInformationPanel.onSuccess();
  