All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tinymediamanager.ui.tvshows.dialogs.TvShowEditorDialog Maven / Gradle / Ivy

/*
 * Copyright 2012 - 2019 Manuel Laggner
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.tinymediamanager.ui.tvshows.dialogs;

import static org.tinymediamanager.core.entities.Person.Type.ACTOR;
import static org.tinymediamanager.ui.TmmUIHelper.createLinkForImage;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.apache.commons.lang3.StringUtils;
import org.jdesktop.beansbinding.AutoBinding.UpdateStrategy;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.observablecollections.ObservableCollections;
import org.jdesktop.swingbinding.JListBinding;
import org.jdesktop.swingbinding.SwingBindings;
import org.tinymediamanager.core.AbstractModelObject;
import org.tinymediamanager.core.MediaFileType;
import org.tinymediamanager.core.entities.MediaFile;
import org.tinymediamanager.core.entities.Person;
import org.tinymediamanager.core.entities.Rating;
import org.tinymediamanager.core.threading.TmmTask;
import org.tinymediamanager.core.threading.TmmTaskManager;
import org.tinymediamanager.core.tvshow.TvShowList;
import org.tinymediamanager.core.tvshow.TvShowModuleManager;
import org.tinymediamanager.core.tvshow.entities.TvShow;
import org.tinymediamanager.core.tvshow.entities.TvShowEpisode;
import org.tinymediamanager.scraper.ScraperType;
import org.tinymediamanager.scraper.entities.Certification;
import org.tinymediamanager.scraper.entities.MediaAiredStatus;
import org.tinymediamanager.scraper.entities.MediaGenres;
import org.tinymediamanager.scraper.entities.MediaType;
import org.tinymediamanager.scraper.trakttv.SyncTraktTvTask;
import org.tinymediamanager.ui.IconManager;
import org.tinymediamanager.ui.MainWindow;
import org.tinymediamanager.ui.ShadowLayerUI;
import org.tinymediamanager.ui.TableColumnResizer;
import org.tinymediamanager.ui.TableSpinnerEditor;
import org.tinymediamanager.ui.UIConstants;
import org.tinymediamanager.ui.components.ImageLabel;
import org.tinymediamanager.ui.components.LinkLabel;
import org.tinymediamanager.ui.components.MainTabbedPane;
import org.tinymediamanager.ui.components.MediaIdTable;
import org.tinymediamanager.ui.components.MediaIdTable.MediaId;
import org.tinymediamanager.ui.components.MediaRatingTable;
import org.tinymediamanager.ui.components.MediaRatingTable.MediaRating;
import org.tinymediamanager.ui.components.PersonTable;
import org.tinymediamanager.ui.components.TmmLabel;
import org.tinymediamanager.ui.components.combobox.AutocompleteComboBox;
import org.tinymediamanager.ui.components.datepicker.DatePicker;
import org.tinymediamanager.ui.components.datepicker.YearSpinner;
import org.tinymediamanager.ui.components.table.TmmTable;
import org.tinymediamanager.ui.components.table.TmmTableFormat;
import org.tinymediamanager.ui.components.table.TmmTableModel;
import org.tinymediamanager.ui.dialogs.IdEditorDialog;
import org.tinymediamanager.ui.dialogs.ImageChooserDialog;
import org.tinymediamanager.ui.dialogs.ImageChooserDialog.ImageType;
import org.tinymediamanager.ui.dialogs.PersonEditorDialog;
import org.tinymediamanager.ui.dialogs.RatingEditorDialog;
import org.tinymediamanager.ui.dialogs.TmmDialog;
import org.tinymediamanager.ui.renderer.LeftDotTableCellRenderer;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.ObservableElementList;
import ca.odell.glazedlists.gui.WritableTableFormat;
import ca.odell.glazedlists.swing.AutoCompleteSupport;
import ca.odell.glazedlists.swing.DefaultEventTableModel;
import ca.odell.glazedlists.swing.GlazedListsSwing;
import net.miginfocom.swing.MigLayout;

/**
 * The Class TvShowEditor.
 * 
 * @author Manuel Laggner
 */
public class TvShowEditorDialog extends TmmDialog {
  private static final long                 serialVersionUID    = 3270218410302989845L;
  private static final Insets               BUTTON_MARGIN       = UIConstants.SMALL_BUTTON_MARGIN;
  private static final String               ORIGINAL_IMAGE_SIZE = "originalImageSize";

  private TvShow                            tvShowToEdit;
  private TvShowList                        tvShowList          = TvShowList.getInstance();
  private EventList                 actors;
  private List                 genres              = ObservableCollections.observableList(new ArrayList<>());
  private EventList                ids;
  private EventList            ratings;
  private List                      tags                = ObservableCollections.observableList(new ArrayList<>());
  private EventList episodes;
  private List                      extrafanarts        = null;
  private Rating                            userRating;
  private boolean                           continueQueue       = true;
  private boolean                           navigateBack        = false;
  private int                               queueIndex;
  private int                               queueSize;

  /**
   * UI elements
   */
  private JTextField                        tfTitle;
  private YearSpinner                       spYear;
  private JTextArea                         taPlot;
  private TmmTable                          tableActors;
  private ImageLabel                        lblPoster;
  private ImageLabel                        lblFanart;
  private ImageLabel                        lblBanner;
  private JSpinner                          spRuntime;
  private JTextField                        tfStudio;
  private JList                listGenres;
  private AutocompleteComboBox cbGenres;
  private AutoCompleteSupport  cbGenresAutoCompleteSupport;
  private JSpinner                          spRating;
  private JComboBox          cbCertification;
  private JComboBox       cbStatus;

  private AutocompleteComboBox      cbTags;
  private AutoCompleteSupport       cbTagsAutoCompleteSupport;
  private JList                     listTags;
  private JSpinner                          spDateAdded;
  private DatePicker                        dpPremiered;
  private TmmTable                          tableEpisodes;
  private JTextField                        tfSorttitle;
  private JTextField                        tfNote;

  private JTextField                        tfPoster;
  private JTextField                        tfFanart;
  private JTextField                        tfLogo;
  private JTextField                        tfClearLogo;
  private JTextField                        tfBanner;
  private JTextField                        tfClearArt;
  private JTextField                        tfThumb;

  private ImageLabel                        lblLogo;
  private ImageLabel                        lblClearlogo;
  private ImageLabel                        lblClearart;
  private ImageLabel                        lblThumb;
  private ImageLabel                        lblCharacterart;
  private ImageLabel                        lblKeyart;

  private TmmTable                          tableIds;
  private TmmTable                          tableRatings;
  private JTextField                        tfOriginalTitle;
  private JTextField                        tfCountry;
  private JTextField                        tfCharacterart;
  private JTextField                        tfKeyart;

  private LinkLabel                         lblBannerSize       = new LinkLabel();
  private LinkLabel                         lblPosterSize       = new LinkLabel();
  private LinkLabel                         lblFanartSize       = new LinkLabel();
  private LinkLabel                         lblLogoSize         = new LinkLabel();
  private LinkLabel                         lblClearlogoSize    = new LinkLabel();
  private LinkLabel                         lblClearartSize     = new LinkLabel();
  private LinkLabel                         lblThumbSize        = new LinkLabel();
  private LinkLabel                         lblCharacterartSize = new LinkLabel();
  private LinkLabel                         lblKeyartSize       = new LinkLabel();

  /**
   * Instantiates a new tv show editor dialog.
   * 
   * @param tvShow
   *          the tv show
   * @param queueIndex
   *          the actual index in the queue
   * @param queueSize
   *          the queue size
   */
  public TvShowEditorDialog(TvShow tvShow, int queueIndex, int queueSize) {
    super(BUNDLE.getString("tvshow.edit") + (queueSize > 1 ? " " + (queueIndex + 1) + "/" + queueSize : "") + "  < " + tvShow.getPathNIO() + " >", //$NON-NLS-1$
        "tvShowEditor");

    this.tvShowToEdit = tvShow;
    this.queueIndex = queueIndex;
    this.queueSize = queueSize;
    ids = MediaIdTable.convertIdMapToEventList(tvShowToEdit.getIds());
    ratings = MediaRatingTable.convertRatingMapToEventList(tvShowToEdit.getRatings(), false);
    userRating = tvShowToEdit.getRating(Rating.USER);

    // creation of lists
    actors = new ObservableElementList<>(GlazedLists.threadSafeList(new BasicEventList<>()), GlazedLists.beanConnector(Person.class));
    episodes = new ObservableElementList<>(GlazedLists.threadSafeList(new BasicEventList<>()),
        GlazedLists.beanConnector(EpisodeEditorContainer.class));

    initComponents();
    bindingGroup = initDataBindings();

    {
      tfTitle.setText(tvShow.getTitle());
      tfOriginalTitle.setText(tvShow.getOriginalTitle());
      tfSorttitle.setText(tvShow.getSortTitle());
      taPlot.setText(tvShow.getPlot());
      lblPoster.setImagePath(tvShow.getArtworkFilename(MediaFileType.POSTER));
      lblFanart.setImagePath(tvShow.getArtworkFilename(MediaFileType.FANART));
      lblLogo.setImagePath(tvShow.getArtworkFilename(MediaFileType.LOGO));
      lblClearlogo.setImagePath(tvShow.getArtworkFilename(MediaFileType.CLEARLOGO));
      lblClearart.setImagePath(tvShow.getArtworkFilename(MediaFileType.CLEARART));
      lblThumb.setImagePath(tvShow.getArtworkFilename(MediaFileType.THUMB));
      lblBanner.setImagePath(tvShow.getArtworkFilename(MediaFileType.BANNER));
      lblCharacterart.setImagePath(tvShow.getArtworkFilename(MediaFileType.CHARACTERART));
      lblKeyart.setImagePath(tvShow.getArtworkFilename(MediaFileType.KEYART));
      tfPoster.setText(tvShow.getArtworkUrl(MediaFileType.POSTER));
      tfFanart.setText(tvShow.getArtworkUrl(MediaFileType.FANART));
      tfLogo.setText(tvShow.getArtworkUrl(MediaFileType.LOGO));
      tfClearLogo.setText(tvShow.getArtworkUrl(MediaFileType.CLEARLOGO));
      tfClearArt.setText(tvShow.getArtworkUrl(MediaFileType.CLEARART));
      tfThumb.setText(tvShow.getArtworkUrl(MediaFileType.THUMB));
      tfBanner.setText(tvShow.getArtworkUrl(MediaFileType.BANNER));
      tfCharacterart.setText(tvShow.getArtworkUrl(MediaFileType.CHARACTERART));
      tfKeyart.setText(tvShow.getArtworkUrl(MediaFileType.KEYART));

      tfStudio.setText(tvShow.getProductionCompany());
      tfCountry.setText(tvShow.getCountry());
      tfNote.setText(tvShow.getNote());
      cbStatus.setSelectedItem(tvShow.getStatus());
      spRuntime.setValue(tvShow.getRuntime());
      int year = tvShow.getYear();
      spYear.setValue(year);
      spDateAdded.setValue(tvShow.getDateAdded());
      spRating.setModel(new SpinnerNumberModel(userRating.getRating(), 0.0, 10.0, 0.1));

      for (Person origCast : tvShow.getActors()) {
        actors.add(new Person(origCast));
      }

      genres.addAll(tvShow.getGenres());
      tags.addAll(tvShowToEdit.getTags());
      if (TvShowModuleManager.SETTINGS.isImageExtraFanart()) {
        extrafanarts = new ArrayList<>(tvShowToEdit.getExtraFanartUrls());
      }

      List availableCertifications = Certification.getCertificationsforCountry(TvShowModuleManager.SETTINGS.getCertificationCountry());
      if (!availableCertifications.contains(tvShowToEdit.getCertification())) {
        availableCertifications.add(0, tvShowToEdit.getCertification());
      }
      for (Certification cert : availableCertifications) {
        cbCertification.addItem(cert);
      }
      cbCertification.setSelectedItem(tvShowToEdit.getCertification());

      List epl = new ArrayList<>(tvShowToEdit.getEpisodes());
      // custom sort per filename (just this time)
      // for unknown EPs (-1/-1) this is extremely useful to sort like on filesystem
      // and for already renamed ones, it makes no difference
      epl.sort(Comparator.comparing(s -> s.getMediaFiles(MediaFileType.VIDEO).get(0).getFile()));

      for (TvShowEpisode episode : epl) {
        EpisodeEditorContainer container = new EpisodeEditorContainer();
        container.tvShowEpisode = episode;
        container.dvdOrder = episode.isDvdOrder();
        container.season = episode.getSeason();
        container.episode = episode.getEpisode();
        episodes.add(container);
      }
    }

    // adjust columnn titles - we have to do it this way - thx to windowbuilder pro
    tableEpisodes.getColumnModel().getColumn(1).setCellRenderer(new LeftDotTableCellRenderer());
    tableEpisodes.getColumnModel().getColumn(2).setCellEditor(new TableSpinnerEditor());
    tableEpisodes.getColumnModel().getColumn(3).setCellEditor(new TableSpinnerEditor());

    // adjust table columns
    TableColumnResizer.adjustColumnPreferredWidths(tableActors, 6);
    TableColumnResizer.adjustColumnPreferredWidths(tableEpisodes, 6);
  }

  private void initComponents() {
    JTabbedPane tabbedPane = new MainTabbedPane() {
      private static final long serialVersionUID = 71548865608767532L;

      @Override
      public void updateUI() {
        putClientProperty("bottomBorder", Boolean.FALSE);
        super.updateUI();
      }
    };

    // to draw the shadow beneath window frame, encapsulate the panel
    JLayer rootLayer = new JLayer(tabbedPane, new ShadowLayerUI()); // removed <> because this leads WBP to crash
    getContentPane().add(rootLayer, BorderLayout.CENTER);

    /**********************************************************************************
     * DetailsPanel 1
     **********************************************************************************/
    {
      JPanel details1Panel = new JPanel();
      tabbedPane.addTab(BUNDLE.getString("metatag.details"), details1Panel);
      details1Panel.setLayout(new MigLayout("", "[][grow][50lp:75lp][][60lp:75lp][100lp:n][][25lp:n][200lp:250lp,grow]",
          "[][][][100lp:175lp][][][][][][][75lp:100lp][]"));

      {
        JLabel lblTitle = new TmmLabel(BUNDLE.getString("metatag.title")); //$NON-NLS-1$
        details1Panel.add(lblTitle, "cell 0 0,alignx right");

        tfTitle = new JTextField();
        details1Panel.add(tfTitle, "cell 1 0 6 1,growx");
      }
      {
        lblPoster = new ImageLabel();
        lblPoster.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.POSTER,
                tvShowList.getAvailableArtworkScrapers(), lblPoster, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblPoster, tfPoster);
          }
        });
        lblPoster.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        details1Panel.add(new TmmLabel(BUNDLE.getString("mediafiletype.poster")), "cell 8 0");
        details1Panel.add(lblPosterSize, "cell 8 0");
        details1Panel.add(lblPoster, "cell 8 1 1 6, grow");
        lblPoster.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblPosterSize, lblPoster, MediaFileType.POSTER));

      }
      {
        JLabel lblOriginalTitleT = new TmmLabel(BUNDLE.getString("metatag.originaltitle")); //$NON-NLS-1$
        details1Panel.add(lblOriginalTitleT, "cell 0 1,alignx right");

        tfOriginalTitle = new JTextField();
        details1Panel.add(tfOriginalTitle, "cell 1 1 6 1,growx");
      }
      {
        JLabel lblSortTitle = new TmmLabel(BUNDLE.getString("metatag.sorttitle")); //$NON-NLS-1$
        details1Panel.add(lblSortTitle, "cell 0 2,alignx right");

        tfSorttitle = new JTextField();
        details1Panel.add(tfSorttitle, "cell 1 2 6 1,growx");
      }
      {
        JLabel lblPlot = new TmmLabel(BUNDLE.getString("metatag.plot")); //$NON-NLS-1$
        details1Panel.add(lblPlot, "cell 0 3,alignx right,aligny top");

        JScrollPane scrollPanePlot = new JScrollPane();
        details1Panel.add(scrollPanePlot, "cell 1 3 6 1,grow");

        taPlot = new JTextArea();
        taPlot.setLineWrap(true);
        taPlot.setWrapStyleWord(true);
        taPlot.setForeground(UIManager.getColor("TextField.foreground")); //$NON-NLS-1$
        scrollPanePlot.setViewportView(taPlot);
      }
      {
        JLabel lblYear = new TmmLabel(BUNDLE.getString("metatag.year")); //$NON-NLS-1$
        details1Panel.add(lblYear, "cell 0 4,alignx right");

        spYear = new YearSpinner();
        details1Panel.add(spYear, "cell 1 4,growx");
      }
      {
        JLabel lblpremiered = new TmmLabel(BUNDLE.getString("metatag.premiered")); //$NON-NLS-1$
        details1Panel.add(lblpremiered, "cell 3 4,alignx right");

        dpPremiered = new DatePicker(tvShowToEdit.getFirstAired());
        details1Panel.add(dpPremiered, "cell 4 4 2 1,growx");
      }
      {
        JLabel lblStudio = new TmmLabel(BUNDLE.getString("metatag.studio")); //$NON-NLS-1$
        details1Panel.add(lblStudio, "cell 0 5,alignx right");

        tfStudio = new JTextField();
        details1Panel.add(tfStudio, "cell 1 5 6 1,growx");
      }
      {
        JLabel lblCountryT = new TmmLabel(BUNDLE.getString("metatag.country")); //$NON-NLS-1$
        details1Panel.add(lblCountryT, "cell 0 6,alignx trailing");

        tfCountry = new JTextField();
        details1Panel.add(tfCountry, "cell 1 6 6 1,growx");
      }
      {
        JLabel lblRuntime = new TmmLabel(BUNDLE.getString("metatag.runtime")); //$NON-NLS-1$
        details1Panel.add(lblRuntime, "cell 0 7,alignx right");

        spRuntime = new JSpinner();
        details1Panel.add(spRuntime, "flowx,cell 1 7,growx");

        JLabel lblMin = new TmmLabel(BUNDLE.getString("metatag.minutes")); //$NON-NLS-1$
        details1Panel.add(lblMin, "cell 1 7");
      }
      {
        JLabel lblStatus = new TmmLabel(BUNDLE.getString("metatag.status")); //$NON-NLS-1$
        details1Panel.add(lblStatus, "cell 3 7,alignx right");

        cbStatus = new JComboBox(MediaAiredStatus.values());
        details1Panel.add(cbStatus, "cell 4 7,growx");
      }
      {
        JLabel lblCertification = new TmmLabel(BUNDLE.getString("metatag.certification")); //$NON-NLS-1$
        details1Panel.add(lblCertification, "cell 0 8,alignx right");

        cbCertification = new JComboBox();
        details1Panel.add(cbCertification, "cell 1 8,growx");
      }
      {
        JLabel lblRating = new TmmLabel(BUNDLE.getString("metatag.userrating")); //$NON-NLS-1$
        details1Panel.add(lblRating, "cell 0 9,alignx right");

        spRating = new JSpinner();
        details1Panel.add(spRating, "cell 1 9,growx");
      }
      {
        JLabel lblRatingsT = new TmmLabel(BUNDLE.getString("metatag.ratings")); //$NON-NLS-1$
        details1Panel.add(lblRatingsT, "flowy,cell 0 10,alignx right,aligny top");

        JScrollPane scrollPaneRatings = new JScrollPane();
        details1Panel.add(scrollPaneRatings, "cell 1 10 4 1,growx");

        tableRatings = new MediaRatingTable(ratings);
        tableRatings.configureScrollPane(scrollPaneRatings);
        scrollPaneRatings.setViewportView(tableRatings);
      }
      {
        lblFanart = new ImageLabel();
        lblFanart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblFanart.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.FANART,
                tvShowList.getAvailableArtworkScrapers(), lblFanart, null, extrafanarts, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblFanart, tfFanart);
          }
        });
        details1Panel.add(new TmmLabel(BUNDLE.getString("mediafiletype.fanart")), "cell 8 8");
        details1Panel.add(lblFanartSize, "cell 8 8");
        details1Panel.add(lblFanart, "cell 8 9 1 4,grow");
        lblFanart.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblFanartSize, lblFanart, MediaFileType.FANART));
      }

      JButton btnAddRating = new JButton(new AddRatingAction());
      btnAddRating.setMargin(BUTTON_MARGIN);
      details1Panel.add(btnAddRating, "cell 0 10,alignx right,aligny top");

      JButton btnRemoveRating = new JButton(new RemoveRatingAction());
      btnRemoveRating.setMargin(BUTTON_MARGIN);
      details1Panel.add(btnRemoveRating, "cell 0 10,alignx right,aligny top");

      {
        JLabel lblNoteT = new TmmLabel(BUNDLE.getString("metatag.note"));
        details1Panel.add(lblNoteT, "cell 0 11,alignx trailing");

        tfNote = new JTextField();
        details1Panel.add(tfNote, "cell 1 11 6 1,growx");
      }
    }

    /**********************************************************************************
     * DetailsPanel 2
     **********************************************************************************/
    {
      JPanel details2Panel = new JPanel();
      tabbedPane.addTab(BUNDLE.getString("metatag.details2"), details2Panel); //$NON-NLS-1$

      details2Panel.setLayout(
          new MigLayout("", "[][150lp:400lp,grow][20lp:n][][150lp:300lp,grow]", "[][:150lp:200lp,grow][20lp:n][100lp:150lp,grow][][100lp,grow 200]"));
      {
        JLabel lblActors = new TmmLabel(BUNDLE.getString("metatag.actors")); //$NON-NLS-1$
        details2Panel.add(lblActors, "flowy,cell 0 0 1 2,alignx right,aligny top");

        JScrollPane scrollPaneActors = new JScrollPane();
        details2Panel.add(scrollPaneActors, "cell 1 0 1 2,grow");
        tableActors = new PersonTable(actors, true);
        tableActors.configureScrollPane(scrollPaneActors);

        JButton btnAddActor = new JButton(new AddActorAction());
        btnAddActor.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnAddActor, "cell 0 0,alignx right");

        JButton btnRemoveActor = new JButton(new RemoveActorAction()); // $NON-NLS-1$
        btnRemoveActor.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnRemoveActor, "cell 0 0,alignx right,aligny top");

        JButton btnMoveActorUp = new JButton(new MoveActorUpAction());
        btnMoveActorUp.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveActorUp, "cell 0 0,alignx right");

        JButton btnMoveActorDown = new JButton(new MoveActorDownAction());
        btnMoveActorDown.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveActorDown, "cell 0 0,alignx right,aligny top");
      }
      {
        JLabel lblDateAdded = new TmmLabel(BUNDLE.getString("metatag.dateadded")); //$NON-NLS-1$
        details2Panel.add(lblDateAdded, "cell 3 0,alignx right");

        spDateAdded = new JSpinner(new SpinnerDateModel());
        details2Panel.add(spDateAdded, "cell 4 0");
      }
      {
        JLabel lblIds = new TmmLabel("Ids");
        details2Panel.add(lblIds, "flowy,cell 3 1,alignx right,aligny top");

        JScrollPane scrollPaneIds = new JScrollPane();
        details2Panel.add(scrollPaneIds, "cell 4 1,grow");

        tableIds = new MediaIdTable(ids);
        tableIds.configureScrollPane(scrollPaneIds);

        JButton btnAddId = new JButton(new AddIdAction());
        btnAddId.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnAddId, "cell 3 1,alignx right");

        JButton btnRemoveId = new JButton(new RemoveIdAction());
        btnRemoveId.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnRemoveId, "cell 3 1,alignx right,aligny top");
      }
      {
        JLabel lblGenres = new TmmLabel(BUNDLE.getString("metatag.genre")); //$NON-NLS-1$
        details2Panel.add(lblGenres, "flowy,cell 0 3,alignx right,aligny top");

        JScrollPane scrollPaneGenres = new JScrollPane();
        details2Panel.add(scrollPaneGenres, "cell 1 3,grow");

        listGenres = new JList<>();
        scrollPaneGenres.setViewportView(listGenres);

        JButton btnAddGenre = new JButton(new AddGenreAction());
        btnAddGenre.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnAddGenre, "cell 0 3,alignx right");

        JButton btnRemoveGenre = new JButton(new RemoveGenreAction());
        btnRemoveGenre.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnRemoveGenre, "cell 0 3,alignx right,aligny top");

        JButton btnMoveGenreUp = new JButton(new MoveGenreUpAction());
        btnMoveGenreUp.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveGenreUp, "cell 0 3,alignx right,aligny top");

        JButton btnMoveGenreDown = new JButton(new MoveGenreDownAction());
        btnMoveGenreDown.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveGenreDown, "cell 0 3,alignx right,aligny top");

        cbGenres = new AutocompleteComboBox(MediaGenres.values());
        cbGenresAutoCompleteSupport = cbGenres.getAutoCompleteSupport();
        InputMap im = cbGenres.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        Object enterAction = im.get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
        cbGenres.getActionMap().put(enterAction, new AddGenreAction());
        details2Panel.add(cbGenres, "cell 1 4,growx");
      }
      {
        JLabel lblTags = new TmmLabel(BUNDLE.getString("metatag.tags")); //$NON-NLS-1$
        details2Panel.add(lblTags, "flowy,cell 3 3,alignx right,aligny top");

        JScrollPane scrollPaneTags = new JScrollPane();
        details2Panel.add(scrollPaneTags, "cell 4 3,grow");
        listTags = new JList();
        scrollPaneTags.setViewportView(listTags);

        JButton btnAddTag = new JButton(new AddTagAction());
        btnAddTag.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnAddTag, "cell 3 3,alignx right");

        JButton btnRemoveTag = new JButton(new RemoveTagAction());
        btnRemoveTag.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnRemoveTag, "cell 3 3,alignx right,aligny top");

        JButton btnMoveTagUp = new JButton(new MoveTagUpAction());
        btnMoveTagUp.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveTagUp, "cell 3 3,alignx right,aligny top");

        JButton btnMoveTagDown = new JButton(new MoveTagDownAction());
        btnMoveTagDown.setMargin(BUTTON_MARGIN);
        details2Panel.add(btnMoveTagDown, "cell 3 3,alignx right,aligny top");

        cbTags = new AutocompleteComboBox<>(tvShowList.getTagsInTvShows());
        cbTagsAutoCompleteSupport = cbTags.getAutoCompleteSupport();
        InputMap im = cbTags.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        Object enterAction = im.get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
        cbTags.getActionMap().put(enterAction, new AddTagAction());
        details2Panel.add(cbTags, "cell 4 4,growx");
      }
    }

    /**********************************************************************************
     * local artwork pane
     **********************************************************************************/
    {
      JPanel artworkPanel = new JPanel();
      tabbedPane.addTab(BUNDLE.getString("metatag.extraartwork"), null, artworkPanel, null);
      artworkPanel.setLayout(new MigLayout("", "[200lp:300lp,grow][20lp:n][200lp:300lp,grow][20lp:n][100lp:200lp,grow]",
          "[][100lp:125lp,grow][20lp:n][][100lp:125lp,grow][20lp:n][][100lp:150lp,grow]"));

      {
        JLabel lblClearlogoT = new TmmLabel(BUNDLE.getString("mediafiletype.clearlogo")); //$NON-NLS-1$

        artworkPanel.add(lblClearlogoT, "cell 0 0");
        artworkPanel.add(lblClearlogoSize, "cell 0 0");
        lblClearlogo = new ImageLabel();
        lblClearlogo.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblClearlogo.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.CLEARLOGO,
                tvShowList.getAvailableArtworkScrapers(), lblClearlogo, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblClearlogo, tfClearLogo);
          }
        });
        artworkPanel.add(lblClearlogo, "cell 0 1,grow");
        lblClearlogo.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE,
            e -> setImageSizeAndCreateLink(lblClearlogoSize, lblClearlogo, MediaFileType.CLEARLOGO));
      }
      {
        JLabel lblBannerT = new TmmLabel(BUNDLE.getString("mediafiletype.banner")); //$NON-NLS-1$
        artworkPanel.add(lblBannerT, "cell 2 0 3 1");
        artworkPanel.add(lblBannerSize, "cell 2 0 3 1");
        lblBanner = new ImageLabel();
        lblBanner.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblBanner.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.BANNER,
                tvShowList.getAvailableArtworkScrapers(), lblBanner, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblBanner, tfBanner);

          }
        });
        artworkPanel.add(lblBanner, "cell 2 1 3 1,grow");
        lblBanner.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblBannerSize, lblBanner, MediaFileType.BANNER));
      }
      {
        JLabel lblClearartT = new TmmLabel(BUNDLE.getString("mediafiletype.clearart")); //$NON-NLS-1$
        artworkPanel.add(lblClearartT, "cell 2 3");
        artworkPanel.add(lblClearartSize, "cell 2 3");
        lblClearart = new ImageLabel();
        lblClearart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblClearart.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.CLEARART,
                tvShowList.getAvailableArtworkScrapers(), lblClearart, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblClearart, tfClearArt);
          }
        });
        artworkPanel.add(lblClearart, "cell 2 4,grow");
        lblClearart.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE,
            e -> setImageSizeAndCreateLink(lblClearartSize, lblClearart, MediaFileType.CLEARART));
      }
      {
        JLabel lblLogoT = new TmmLabel(BUNDLE.getString("mediafiletype.logo")); //$NON-NLS-1$
        artworkPanel.add(lblLogoT, "cell 0 3");
        artworkPanel.add(lblLogoSize, "cell 0 3");
        lblLogo = new ImageLabel();
        lblLogo.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblLogo.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.LOGO,
                tvShowList.getAvailableArtworkScrapers(), lblLogo, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblLogo, tfLogo);
          }
        });
        artworkPanel.add(lblLogo, "cell 0 4,grow");
        lblLogo.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblLogoSize, lblLogo, MediaFileType.LOGO));
      }
      {
        JLabel lblKeyartT = new TmmLabel(BUNDLE.getString("mediafiletype.keyart")); //$NON-NLS-1$
        artworkPanel.add(lblKeyartT, "cell 4 3");
        artworkPanel.add(lblKeyartSize, "cell 4 3");
        lblKeyart = new ImageLabel();
        lblKeyart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblKeyart.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.KEYART,
                tvShowList.getAvailableArtworkScrapers(), lblKeyart, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblKeyart, tfKeyart);
          }
        });
        artworkPanel.add(lblKeyart, "cell 4 4 1 4,grow");
        lblKeyart.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblKeyartSize, lblKeyart, MediaFileType.KEYART));
      }
      {
        JLabel lblThumbT = new TmmLabel(BUNDLE.getString("mediafiletype.thumb")); //$NON-NLS-1$
        artworkPanel.add(lblThumbT, "cell 0 6");
        artworkPanel.add(lblThumbSize, "cell 0 6");
        lblThumb = new ImageLabel();
        lblThumb.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblThumb.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.THUMB,
                tvShowList.getAvailableArtworkScrapers(), lblThumb, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblThumb, tfThumb);
          }
        });
        artworkPanel.add(lblThumb, "cell 0 7,grow");
        lblThumb.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE, e -> setImageSizeAndCreateLink(lblThumbSize, lblThumb, MediaFileType.THUMB));
      }
      {
        JLabel lblCharacterartT = new TmmLabel(BUNDLE.getString("mediafiletype.characterart")); //$NON-NLS-1$
        artworkPanel.add(lblCharacterartT, "cell 2 6");
        artworkPanel.add(lblCharacterartSize, "cell 2 6");
        lblCharacterart = new ImageLabel();
        lblCharacterart.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lblCharacterart.addMouseListener(new MouseAdapter() {
          @Override
          public void mouseClicked(MouseEvent e) {
            ImageChooserDialog dialog = new ImageChooserDialog(TvShowEditorDialog.this, new HashMap<>(tvShowToEdit.getIds()), ImageType.CHARACTERART,
                tvShowList.getAvailableArtworkScrapers(), lblCharacterart, null, null, MediaType.TV_SHOW);
            dialog.setLocationRelativeTo(MainWindow.getActiveInstance());
            dialog.setVisible(true);
            updateArtworkUrl(lblCharacterart, tfCharacterart);
          }
        });
        artworkPanel.add(lblCharacterart, "cell 2 7, grow");
        lblCharacterart.addPropertyChangeListener(ORIGINAL_IMAGE_SIZE,
            e -> setImageSizeAndCreateLink(lblCharacterartSize, lblCharacterart, MediaFileType.CHARACTERART));
      }
    }

    /**********************************************************************************
     * artwork urls
     **********************************************************************************/
    {
      JPanel artworkPanel = new JPanel();
      tabbedPane.addTab(BUNDLE.getString("edit.artwork"), null, artworkPanel, null);
      artworkPanel.setLayout(new MigLayout("", "[][grow]", "[][][][][][][][][]"));
      {
        JLabel lblPosterT = new TmmLabel(BUNDLE.getString("mediafiletype.poster")); //$NON-NLS-1$
        artworkPanel.add(lblPosterT, "cell 0 0,alignx right");

        tfPoster = new JTextField();
        artworkPanel.add(tfPoster, "cell 1 0,growx");
      }
      {
        JLabel lblFanartT = new TmmLabel(BUNDLE.getString("mediafiletype.fanart")); //$NON-NLS-1$
        artworkPanel.add(lblFanartT, "cell 0 1,alignx right");

        tfFanart = new JTextField();
        artworkPanel.add(tfFanart, "cell 1 1,growx");
      }
      {
        JLabel lblLogoT = new TmmLabel(BUNDLE.getString("mediafiletype.logo")); //$NON-NLS-1$
        artworkPanel.add(lblLogoT, "cell 0 2,alignx right");

        tfLogo = new JTextField();
        artworkPanel.add(tfLogo, "cell 1 2,growx");
      }
      {
        JLabel lblClearLogoT = new TmmLabel(BUNDLE.getString("mediafiletype.clearlogo")); //$NON-NLS-1$
        artworkPanel.add(lblClearLogoT, "cell 0 3,alignx right");

        tfClearLogo = new JTextField();
        artworkPanel.add(tfClearLogo, "cell 1 3,growx");
      }
      {
        JLabel lblBannerT = new TmmLabel(BUNDLE.getString("mediafiletype.banner")); //$NON-NLS-1$
        artworkPanel.add(lblBannerT, "cell 0 4,alignx right");

        tfBanner = new JTextField();
        artworkPanel.add(tfBanner, "cell 1 4,growx");
      }
      {
        JLabel lblClearArtT = new TmmLabel(BUNDLE.getString("mediafiletype.clearart")); //$NON-NLS-1$
        artworkPanel.add(lblClearArtT, "cell 0 5,alignx right");

        tfClearArt = new JTextField();
        artworkPanel.add(tfClearArt, "cell 1 5,growx");
      }
      {
        JLabel lblThumbT = new TmmLabel(BUNDLE.getString("mediafiletype.thumb")); //$NON-NLS-1$
        artworkPanel.add(lblThumbT, "cell 0 6,alignx right");

        tfThumb = new JTextField();
        artworkPanel.add(tfThumb, "cell 1 6,growx");
      }
      {
        JLabel lblCharacterartT = new TmmLabel(BUNDLE.getString("mediafiletype.characterart")); //$NON-NLS-1$
        artworkPanel.add(lblCharacterartT, "cell 0 7,alignx trailing");

        tfCharacterart = new JTextField();
        artworkPanel.add(tfCharacterart, "cell 1 7,growx");
      }
      {
        JLabel lblKeyartT = new TmmLabel(BUNDLE.getString("mediafiletype.keyart")); //$NON-NLS-1$
        artworkPanel.add(lblKeyartT, "cell 0 8,alignx trailing");

        tfKeyart = new JTextField();
        artworkPanel.add(tfKeyart, "cell 1 8,growx");
      }
    }

    /**********************************************************************************
     * episode pane
     **********************************************************************************/
    {
      JPanel episodesPanel = new JPanel();

      tabbedPane.addTab(BUNDLE.getString("metatag.episodes"), episodesPanel);
      episodesPanel.setLayout(new MigLayout("", "[][grow]", "[][100px:n,grow]"));
      {
        JButton btnCloneEpisode = new JButton(new CloneEpisodeAction());
        btnCloneEpisode.setMargin(BUTTON_MARGIN);
        episodesPanel.add(btnCloneEpisode, "cell 0 0");
      }
      {
        JScrollPane scrollPaneEpisodes = new JScrollPane();
        episodesPanel.add(scrollPaneEpisodes, "cell 1 0 1 2,grow");

        DefaultEventTableModel episodeTableModel = new TmmTableModel<>(GlazedListsSwing.swingThreadProxyList(episodes),
            new EpisodeTableFormat());
        tableEpisodes = new TmmTable(episodeTableModel);
        tableEpisodes.configureScrollPane(scrollPaneEpisodes);
      }
      {
        JButton btnRemoveEpisode = new JButton(new RemoveEpisodeAction());
        btnRemoveEpisode.setMargin(BUTTON_MARGIN);
        episodesPanel.add(btnRemoveEpisode, "cell 0 1,aligny top");
      }
    }

    /**********************************************************************************
     * button pane
     **********************************************************************************/
    {
      if (queueSize > 1) {
        JButton btnAbort = new JButton(new AbortAction());
        addButton(btnAbort);
        if (queueIndex > 0) {
          JButton backButton = new JButton(new NavigateBackAction());
          addButton(backButton);
        }
      }

      JButton cancelButton = new JButton(new CancelAction());
      addButton(cancelButton);

      JButton okButton = new JButton(new OKAction());
      addDefaultButton(okButton);
    }
  }

  private void updateArtworkUrl(ImageLabel imageLabel, JTextField textField) {
    if (StringUtils.isNotBlank(imageLabel.getImageUrl())) {
      textField.setText(imageLabel.getImageUrl());
    }
  }

  private class OKAction extends AbstractAction {
    private static final long serialVersionUID = 6699599213348390696L;

    OKAction() {
      putValue(NAME, BUNDLE.getString("Button.ok")); //$NON-NLS-1$
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tvshow.change")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.APPLY_INV);
      putValue(LARGE_ICON_KEY, IconManager.APPLY_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      tvShowToEdit.setTitle(tfTitle.getText());
      tvShowToEdit.setOriginalTitle(tfOriginalTitle.getText());
      tvShowToEdit.setSortTitle(tfSorttitle.getText());
      tvShowToEdit.setYear((Integer) spYear.getValue());
      tvShowToEdit.setPlot(taPlot.getText());
      tvShowToEdit.setRuntime((Integer) spRuntime.getValue());

      // sync of media ids
      // first round -> add existing ids
      for (MediaId id : ids) {
        // only process non empty ids
        // changed; if empty/0/null value gets set, it is removed in setter ;)
        // if (StringUtils.isAnyBlank(id.key, id.value)) {
        // continue;
        // }
        // first try to cast it into an Integer
        try {
          Integer value = Integer.parseInt(id.value);
          // cool, it is an Integer
          tvShowToEdit.setId(id.key, value);
        }
        catch (NumberFormatException ex) {
          // okay, we set it as a String
          tvShowToEdit.setId(id.key, id.value);
        }
      }
      // second round -> remove deleted ids
      List removeIds = new ArrayList<>();
      for (Entry entry : tvShowToEdit.getIds().entrySet()) {
        MediaId id = new MediaId(entry.getKey());
        if (!ids.contains(id)) {
          removeIds.add(entry.getKey());
        }
      }
      for (String id : removeIds) {
        // set a null value causes to fire the right events
        tvShowToEdit.setId(id, null);
      }

      Object certification = cbCertification.getSelectedItem();
      if (certification instanceof Certification) {
        tvShowToEdit.setCertification((Certification) certification);
      }

      if (StringUtils.isNotEmpty(tfPoster.getText()) && !tfPoster.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.POSTER))) {
        tvShowToEdit.setArtworkUrl(tfPoster.getText(), MediaFileType.POSTER);
        tvShowToEdit.downloadArtwork(MediaFileType.POSTER);
      }
      else if (StringUtils.isEmpty(tfPoster.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.POSTER);
      }

      if (StringUtils.isNotEmpty(tfFanart.getText()) && !tfFanart.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.FANART))) {
        tvShowToEdit.setArtworkUrl(tfFanart.getText(), MediaFileType.FANART);
        tvShowToEdit.downloadArtwork(MediaFileType.FANART);
      }
      else if (StringUtils.isEmpty(tfFanart.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.FANART);
      }

      if (StringUtils.isNotEmpty(tfBanner.getText()) && !tfBanner.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.BANNER))) {
        tvShowToEdit.setArtworkUrl(tfBanner.getText(), MediaFileType.BANNER);
        tvShowToEdit.downloadArtwork(MediaFileType.BANNER);
      }
      else if (StringUtils.isEmpty(tfBanner.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.BANNER);
      }

      if (StringUtils.isNotEmpty(tfLogo.getText()) && !tfLogo.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.LOGO))) {
        tvShowToEdit.setArtworkUrl(tfLogo.getText(), MediaFileType.LOGO);
        tvShowToEdit.downloadArtwork(MediaFileType.LOGO);
      }
      else if (StringUtils.isEmpty(tfLogo.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.LOGO);
      }

      if (StringUtils.isNotEmpty(tfClearLogo.getText()) && !tfClearLogo.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.CLEARLOGO))) {
        tvShowToEdit.setArtworkUrl(tfClearLogo.getText(), MediaFileType.CLEARLOGO);
        tvShowToEdit.downloadArtwork(MediaFileType.CLEARLOGO);
      }
      else if (StringUtils.isEmpty(tfClearLogo.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.CLEARLOGO);
      }

      if (StringUtils.isNotEmpty(tfClearArt.getText()) && !tfClearArt.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.CLEARART))) {
        tvShowToEdit.setArtworkUrl(tfClearArt.getText(), MediaFileType.CLEARART);
        tvShowToEdit.downloadArtwork(MediaFileType.CLEARART);
      }
      else if (StringUtils.isEmpty(tfClearArt.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.CLEARART);
      }

      if (StringUtils.isNotEmpty(tfThumb.getText()) && !tfThumb.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.THUMB))) {
        tvShowToEdit.setArtworkUrl(tfThumb.getText(), MediaFileType.THUMB);
        tvShowToEdit.downloadArtwork(MediaFileType.THUMB);
      }
      else if (StringUtils.isEmpty(tfThumb.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.THUMB);
      }

      if (StringUtils.isNotEmpty(tfCharacterart.getText())
          && !tfCharacterart.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.CHARACTERART))) {
        tvShowToEdit.setArtworkUrl(tfCharacterart.getText(), MediaFileType.CHARACTERART);
        tvShowToEdit.downloadArtwork(MediaFileType.CHARACTERART);
      }
      else if (StringUtils.isEmpty(tfCharacterart.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.CHARACTERART);
      }

      if (StringUtils.isNotEmpty(tfKeyart.getText()) && !tfKeyart.getText().equals(tvShowToEdit.getArtworkUrl(MediaFileType.KEYART))) {
        tvShowToEdit.setArtworkUrl(tfKeyart.getText(), MediaFileType.KEYART);
        tvShowToEdit.downloadArtwork(MediaFileType.KEYART);
      }
      else if (StringUtils.isEmpty(tfKeyart.getText())) {
        tvShowToEdit.removeArtworkUrl(MediaFileType.KEYART);
      }

      // set extrafanarts
      if (extrafanarts != null && (extrafanarts.size() != tvShowToEdit.getExtraFanartUrls().size()
          || !extrafanarts.containsAll(tvShowToEdit.getExtraFanartUrls()) || !tvShowToEdit.getExtraFanartUrls().containsAll(extrafanarts))) {
        tvShowToEdit.setExtraFanartUrls(extrafanarts);
        tvShowToEdit.downloadArtwork(MediaFileType.EXTRAFANART);
      }

      tvShowToEdit.setProductionCompany(tfStudio.getText());
      tvShowToEdit.setCountry(tfCountry.getText());
      tvShowToEdit.setNote(tfNote.getText());
      tvShowToEdit.setActors(actors);
      tvShowToEdit.setGenres(genres);

      tvShowToEdit.setTags(tags);
      tvShowToEdit.setDateAdded((Date) spDateAdded.getValue());
      tvShowToEdit.setFirstAired(dpPremiered.getDate());

      tvShowToEdit.setStatus((MediaAiredStatus) cbStatus.getSelectedItem());

      // user rating
      Map newRatings = new HashMap<>();

      if ((double) spRating.getValue() > 0) {
        newRatings.put(Rating.USER, new Rating(Rating.USER, (double) spRating.getValue(), 1, 10));
      }

      // other ratings
      for (MediaRating mediaRating : TvShowEditorDialog.this.ratings) {
        if (StringUtils.isNotBlank(mediaRating.key) && mediaRating.value > 0) {
          newRatings.put(mediaRating.key, new Rating(mediaRating.key, mediaRating.value, mediaRating.votes, mediaRating.maxValue));
        }
      }
      tvShowToEdit.setRatings(newRatings);

      // adapt episodes according to the episode table (in a 2 way sync)
      // remove episodes
      for (int i = tvShowToEdit.getEpisodeCount() - 1; i >= 0; i--) {
        boolean found = false;
        TvShowEpisode episode = tvShowToEdit.getEpisodes().get(i);
        for (EpisodeEditorContainer container : episodes) {
          if (container.tvShowEpisode == episode) {
            found = true;
            break;
          }
        }

        if (!found) {
          tvShowToEdit.removeEpisode(episode);
        }
      }

      // add episodes
      for (EpisodeEditorContainer container : episodes) {
        boolean found = false;
        boolean shouldStore = false;

        if (container.dvdOrder != container.tvShowEpisode.isDvdOrder()) {
          container.tvShowEpisode.setDvdOrder(container.dvdOrder);
          shouldStore = true;
        }

        if (container.episode != container.tvShowEpisode.getEpisode()) {
          if (container.dvdOrder) {
            container.tvShowEpisode.setDvdEpisode(container.episode);
          }
          else {
            container.tvShowEpisode.setAiredEpisode(container.episode);
          }

          shouldStore = true;
        }

        if (container.season != container.tvShowEpisode.getSeason()) {
          if (container.dvdOrder) {
            container.tvShowEpisode.setDvdSeason(container.season);
          }
          else {
            container.tvShowEpisode.setAiredSeason(container.season);
          }
          shouldStore = true;
        }

        for (TvShowEpisode episode : tvShowToEdit.getEpisodes()) {
          if (container.tvShowEpisode == episode) {
            found = true;
            break;
          }
        }

        if (!found) {
          container.tvShowEpisode.writeNFO();
          container.tvShowEpisode.saveToDb();
          tvShowToEdit.addEpisode(container.tvShowEpisode);
        }
        else if (shouldStore) {
          container.tvShowEpisode.writeNFO();
          container.tvShowEpisode.saveToDb();
        }
      }

      tvShowToEdit.writeNFO();
      tvShowToEdit.saveToDb();

      if (TvShowModuleManager.SETTINGS.getSyncTrakt()) {
        TmmTask task = new SyncTraktTvTask(null, Collections.singletonList(tvShowToEdit));
        TmmTaskManager.getInstance().addUnnamedTask(task);
      }

      setVisible(false);
    }
  }

  private class CancelAction extends AbstractAction {
    private static final long serialVersionUID = -4617793684152607277L;

    CancelAction() {
      putValue(NAME, BUNDLE.getString("Button.cancel")); //$NON-NLS-1$
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("edit.discard")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.CANCEL_INV);
      putValue(LARGE_ICON_KEY, IconManager.CANCEL_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      setVisible(false);
    }
  }

  private class AddRatingAction extends AbstractAction {
    private static final long serialVersionUID = 2903255414533349267L;

    private AddRatingAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("rating.add")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ADD_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      MediaRating mediaRating = new MediaRating("");
      // default values
      mediaRating.maxValue = 10;
      mediaRating.votes = 1;

      RatingEditorDialog dialog = new RatingEditorDialog(SwingUtilities.getWindowAncestor(tableActors), BUNDLE.getString("rating.add"), mediaRating);
      dialog.setVisible(true);

      if (StringUtils.isNotBlank(mediaRating.key) && mediaRating.value > 0 && mediaRating.maxValue > 0 && mediaRating.votes > 0) {
        ratings.add(mediaRating);
      }
    }
  }

  private class RemoveRatingAction extends AbstractAction {
    private static final long serialVersionUID = -7079821950827356996L;

    private RemoveRatingAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("rating.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableRatings.getSelectedRow();
      if (row > -1) {
        row = tableRatings.convertRowIndexToModel(row);
        ratings.remove(row);
      }
    }
  }

  private class AddActorAction extends AbstractAction {
    private static final long serialVersionUID = -5879601617842300526L;

    AddActorAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("cast.actor.add")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ADD_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      Person actor = new Person(ACTOR, BUNDLE.getString("cast.actor.unknown"), BUNDLE.getString("cast.role.unknown")); //$NON-NLS-1$
      PersonEditorDialog dialog = new PersonEditorDialog(SwingUtilities.getWindowAncestor(tableActors), BUNDLE.getString("cast.actor.add"), actor);
      dialog.setVisible(true);

      if (StringUtils.isNotBlank(actor.getName()) && !actor.getName().equals(BUNDLE.getString("cast.actor.unknown"))) {
        actors.add(0, actor);
      }
    }
  }

  private class RemoveActorAction extends AbstractAction {
    private static final long serialVersionUID = 6970920169867315771L;

    RemoveActorAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("cast.actor.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableActors.getSelectedRow();
      if (row > -1) {
        row = tableActors.convertRowIndexToModel(row);
        actors.remove(row);
      }
    }
  }

  private class MoveActorUpAction extends AbstractAction {
    private static final long serialVersionUID = 5775423424097844658L;

    MoveActorUpAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.moveactorup")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_UP_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableActors.getSelectedRow();
      if (row > 0) {
        Collections.rotate(actors.subList(row - 1, row + 1), 1);
        tableActors.getSelectionModel().setSelectionInterval(row - 1, row - 1);
      }
    }
  }

  private class MoveActorDownAction extends AbstractAction {
    private static final long serialVersionUID = -6564146895819191932L;

    MoveActorDownAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.moveactordown")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_DOWN_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableActors.getSelectedRow();
      if (row < actors.size() - 1) {
        Collections.rotate(actors.subList(row, row + 2), -1);
        tableActors.getSelectionModel().setSelectionInterval(row + 1, row + 1);
      }
    }
  }

  private class AddGenreAction extends AbstractAction {
    private static final long serialVersionUID = 6666302391216952247L;

    AddGenreAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("genre.add")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ADD_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      MediaGenres newGenre = null;
      Object item = cbGenres.getSelectedItem();

      // check, if text is selected (from auto completion), in this case we just
      // remove the selection
      Component editorComponent = cbGenres.getEditor().getEditorComponent();
      if (editorComponent instanceof JTextField) {
        JTextField tf = (JTextField) editorComponent;
        String selectedText = tf.getSelectedText();
        if (selectedText != null) {
          tf.setSelectionStart(0);
          tf.setSelectionEnd(0);
          tf.setCaretPosition(tf.getText().length());
          return;
        }
      }

      // genre
      if (item instanceof MediaGenres) {
        newGenre = (MediaGenres) item;
      }

      // newly created genre?
      if (item instanceof String) {
        newGenre = MediaGenres.getGenre((String) item);
      }

      // add genre if it is not already in the list
      if (newGenre != null && !genres.contains(newGenre)) {
        genres.add(newGenre);

        // set text combobox text input to ""
        if (editorComponent instanceof JTextField) {
          cbGenresAutoCompleteSupport.setFirstItem(null);
          cbGenres.setSelectedIndex(0);
          cbGenresAutoCompleteSupport.removeFirstItem();
        }
      }
    }
  }

  private class RemoveGenreAction extends AbstractAction {
    private static final long serialVersionUID = -5459615776560234688L;

    RemoveGenreAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("genre.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      for (MediaGenres genre : listGenres.getSelectedValuesList()) {
        genres.remove(genre);
      }
    }
  }

  private class MoveGenreUpAction extends AbstractAction {
    private static final long serialVersionUID = -6855661707692602266L;

    MoveGenreUpAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.movegenreup")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_UP_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = listGenres.getSelectedIndex();
      if (row > 0) {
        Collections.rotate(genres.subList(row - 1, row + 1), 1);
        listGenres.getSelectionModel().setSelectionInterval(row - 1, row - 1);
      }
    }
  }

  private class MoveGenreDownAction extends AbstractAction {
    private static final long serialVersionUID = -1135108943010008069L;

    MoveGenreDownAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.movegenredown")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_DOWN_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = listGenres.getSelectedIndex();
      if (row < genres.size() - 1) {
        Collections.rotate(genres.subList(row, row + 2), -1);
        listGenres.getSelectionModel().setSelectionInterval(row + 1, row + 1);
      }
    }
  }

  /**
   * Shows the dialog and returns whether the work on the queue should be continued.
   * 
   * @return true, if successful
   */
  public boolean showDialog() {
    setVisible(true);
    return continueQueue;
  }

  private class AddTagAction extends AbstractAction {
    private static final long serialVersionUID = 9160043031922897785L;

    AddTagAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tag.add")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ADD_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      String newTag = (String) cbTags.getSelectedItem();
      if (StringUtils.isBlank(newTag)) {
        return;
      }

      // check, if text is selected (from auto completion), in this case we just
      // remove the selection
      Component editorComponent = cbTags.getEditor().getEditorComponent();
      if (editorComponent instanceof JTextField) {
        JTextField tf = (JTextField) editorComponent;
        String selectedText = tf.getSelectedText();
        if (selectedText != null) {
          tf.setSelectionStart(0);
          tf.setSelectionEnd(0);
          tf.setCaretPosition(tf.getText().length());
          return;
        }
      }

      // search if this tag already has been added
      boolean tagFound = false;
      for (String tag : tags) {
        if (tag.equals(newTag)) {
          tagFound = true;
          break;
        }
      }

      // add tag
      if (!tagFound) {
        tags.add(newTag);

        // set text combobox text input to ""
        if (editorComponent instanceof JTextField) {
          cbTagsAutoCompleteSupport.setFirstItem("");
          cbTags.setSelectedIndex(0);
          cbTagsAutoCompleteSupport.removeFirstItem();
        }
      }
    }
  }

  private class AddIdAction extends AbstractAction {
    private static final long serialVersionUID = 2903255414553349267L;

    AddIdAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("id.add")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ADD_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      MediaId mediaId = new MediaId();
      IdEditorDialog dialog = new IdEditorDialog(SwingUtilities.getWindowAncestor(tableIds), BUNDLE.getString("id.add"), mediaId,
          ScraperType.TV_SHOW);
      dialog.setVisible(true);

      if (StringUtils.isNoneBlank(mediaId.key, mediaId.value)) {
        ids.add(mediaId);
      }
    }
  }

  private class RemoveIdAction extends AbstractAction {
    private static final long serialVersionUID = -7079826950827356996L;

    RemoveIdAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("id.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableIds.getSelectedRow();
      if (row > -1) {
        row = tableIds.convertRowIndexToModel(row);
        ids.remove(row);
      }
    }
  }

  private class RemoveTagAction extends AbstractAction {
    private static final long serialVersionUID = -1580945350962234235L;

    RemoveTagAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tag.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      for (String tag : listTags.getSelectedValuesList()) {
        tags.remove(tag);
      }
    }
  }

  private class MoveTagUpAction extends AbstractAction {
    private static final long serialVersionUID = -6855661707692602266L;

    MoveTagUpAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.movetagup")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_UP_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = listTags.getSelectedIndex();
      if (row > 0) {
        Collections.rotate(tags.subList(row - 1, row + 1), 1);
        listTags.getSelectionModel().setSelectionInterval(row - 1, row - 1);
      }
    }
  }

  private class MoveTagDownAction extends AbstractAction {
    private static final long serialVersionUID = -1135108943010008069L;

    MoveTagDownAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("movie.edit.movetagdown")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.ARROW_DOWN_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = listTags.getSelectedIndex();
      if (row < tags.size() - 1) {
        Collections.rotate(tags.subList(row, row + 2), -1);
        listTags.getSelectionModel().setSelectionInterval(row + 1, row + 1);
      }
    }
  }

  private class AbortAction extends AbstractAction {
    private static final long serialVersionUID = -7652218354710642510L;

    AbortAction() {
      putValue(NAME, BUNDLE.getString("Button.abortqueue")); //$NON-NLS-1$
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tvshow.edit.abortqueue.desc")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.STOP_INV);
      putValue(LARGE_ICON_KEY, IconManager.STOP_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      continueQueue = false;
      setVisible(false);
    }
  }

  private class NavigateBackAction extends AbstractAction {
    private static final long serialVersionUID = -1652218154720642310L;

    private NavigateBackAction() {
      putValue(NAME, BUNDLE.getString("Button.back")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.BACK_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      navigateBack = true;
      setVisible(false);
    }
  }

  private class EpisodeEditorContainer extends AbstractModelObject {
    TvShowEpisode tvShowEpisode;
    int           season;
    int           episode;
    boolean       dvdOrder = false;

    public String getEpisodeTitle() {
      return tvShowEpisode.getTitle();
    }

    public String getMediaFilename() {
      List mfs = tvShowEpisode.getMediaFiles(MediaFileType.VIDEO);
      if (mfs != null && mfs.size() > 0) {
        return mfs.get(0).getFile().toString();
      }
      else {
        return "";
      }
    }

    public int getEpisode() {
      return episode;
    }

    public void setEpisode(int newValue) {
      int oldValue = this.episode;
      this.episode = newValue;
      firePropertyChange("episode", oldValue, newValue);
    }

    public int getSeason() {
      return season;
    }

    public void setSeason(int newValue) {
      int oldValue = this.season;
      this.season = newValue;
      firePropertyChange("season", oldValue, newValue);
    }

    public boolean isDvdOrder() {
      return this.dvdOrder;
    }

    public void setDvdOrder(boolean newValue) {
      boolean oldValue = this.dvdOrder;
      this.dvdOrder = newValue;
      firePropertyChange("dvdOrder", oldValue, newValue);
    }
  }

  @Override
  public void dispose() {
    super.dispose();

    dpPremiered.cleanup();
  }

  public boolean isContinueQueue() {
    return continueQueue;
  }

  public boolean isNavigateBack() {
    return navigateBack;
  }

  private class CloneEpisodeAction extends AbstractAction {
    private static final long serialVersionUID = -3255090541823134232L;

    CloneEpisodeAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tvshowepisode.clone")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.COPY_INV);
      putValue(LARGE_ICON_KEY, IconManager.COPY_INV);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
      int row = tableEpisodes.getSelectedRow();
      if (row > -1) {
        row = tableEpisodes.convertRowIndexToModel(row);
        EpisodeEditorContainer origContainer = episodes.get(row);
        EpisodeEditorContainer newContainer = new EpisodeEditorContainer();
        newContainer.tvShowEpisode = new TvShowEpisode(origContainer.tvShowEpisode);
        newContainer.tvShowEpisode.setTitle(origContainer.tvShowEpisode.getTitle() + " (clone)");
        newContainer.episode = -1;
        newContainer.season = newContainer.tvShowEpisode.getSeason();
        episodes.add(row + 1, newContainer);
      }
    }
  }

  private class RemoveEpisodeAction extends AbstractAction {
    private static final long serialVersionUID = -8233854057648972649L;

    RemoveEpisodeAction() {
      putValue(SHORT_DESCRIPTION, BUNDLE.getString("tvshowepisode.remove")); //$NON-NLS-1$
      putValue(SMALL_ICON, IconManager.REMOVE_INV);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      int row = tableEpisodes.getSelectedRow();
      if (row > -1) {
        row = tableEpisodes.convertRowIndexToModel(row);
        episodes.remove(row);
      }
    }
  }

  private static class EpisodeTableFormat extends TmmTableFormat implements WritableTableFormat {
    EpisodeTableFormat() {
      /*
       * title
       */
      Column col = new Column(BUNDLE.getString("metatag.title"), "name", EpisodeEditorContainer::getEpisodeTitle, String.class);
      col.setColumnResizeable(true);
      addColumn(col);

      /*
       * MF name
       */
      col = new Column(BUNDLE.getString("metatag.filename"), "filename", EpisodeEditorContainer::getMediaFilename, String.class);
      col.setColumnResizeable(true);
      addColumn(col);

      /*
       * season
       */
      col = new Column(BUNDLE.getString("metatag.season"), "season", EpisodeEditorContainer::getSeason, Integer.class);
      col.setColumnResizeable(false);
      addColumn(col);

      /*
       * episode
       */
      col = new Column(BUNDLE.getString("metatag.episode"), "episode", EpisodeEditorContainer::getEpisode, Integer.class);
      col.setColumnResizeable(false);
      addColumn(col);

      /*
       * DVD order
       */
      col = new Column(BUNDLE.getString("metatag.dvdorder"), "name", EpisodeEditorContainer::isDvdOrder, Boolean.class);
      col.setColumnResizeable(false);
      addColumn(col);
    }

    @Override
    public boolean isEditable(EpisodeEditorContainer episodeEditorContainer, int i) {
      switch (i) {
        case 2:
        case 3:
        case 4:
          return true;

        default:
          return false;
      }
    }

    @Override
    public EpisodeEditorContainer setColumnValue(EpisodeEditorContainer episodeEditorContainer, Object o, int i) {
      switch (i) {
        case 2:
          episodeEditorContainer.setSeason((Integer) o);
          break;

        case 3:
          episodeEditorContainer.setEpisode((Integer) o);
          break;

        case 4:
          episodeEditorContainer.setDvdOrder((Boolean) o);
          break;

        default:
          break;
      }
      return episodeEditorContainer;
    }
  }

  protected BindingGroup initDataBindings() {
    JListBinding, JList> jListBinding = SwingBindings.createJListBinding(UpdateStrategy.READ, genres, listGenres);
    jListBinding.bind();
    //
    JListBinding, JList> jListBinding_1 = SwingBindings.createJListBinding(UpdateStrategy.READ, tags, listTags);
    jListBinding_1.bind();
    //
    BindingGroup bindingGroup = new BindingGroup();
    //
    bindingGroup.addBinding(jListBinding);
    bindingGroup.addBinding(jListBinding_1);
    return bindingGroup;
  }

  private void setImageSizeAndCreateLink(LinkLabel lblSize, ImageLabel imageLabel, MediaFileType type) {
    createLinkForImage(lblSize, imageLabel);
    Dimension dimension = tvShowToEdit.getArtworkDimension(type);
    if (dimension.width == 0 && dimension.height == 0) {
      lblSize.setText(imageLabel.getOriginalImageSize().width + "x" + imageLabel.getOriginalImageSize().height);
    }
    else {
      lblSize.setText(dimension.width + "x" + dimension.height);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy