	private void initActions() {
		btnNewButton.addActionListener(ae -> {
			newsPanel.setMagicNews(new MagicNews());
			newsPanel.setVisible(true);
		});

		btnSave.addActionListener(ae -> {
			try {
				MTGControler.getInstance().getEnabled(MTGDao.class).saveOrUpdateNews(newsPanel.getMagicNews());
				initTree();
			} catch (SQLException ex) {
				logger.error("Error saving news", ex);
				MTGControler.getInstance().notify(ex);
			}
		});

		btnDelete.addActionListener(ae -> {
			try {
				MTGControler.getInstance().getEnabled(MTGDao.class).deleteNews(newsPanel.getMagicNews());
				initTree();
			} catch (SQLException ex) {
				logger.error("Error delete news", ex);
				MTGControler.getInstance().notify(ex);
			}
		});

		tree.addTreeSelectionListener(tse -> {
			TreePath path = tse.getPath();
			curr = (DefaultMutableTreeNode) path.getLastPathComponent();

			if (curr.getUserObject() instanceof MagicNews)
			{
				SwingWorker<List<MagicNewsContent>, MagicNews> sw = new SwingWorker<>()
				{

					@Override
					protected List<MagicNewsContent> doInBackground() throws Exception {
						MagicNews n = (MagicNews) curr.getUserObject();
						return n.getProvider().listNews(n);
					}

					@Override
					protected void done() {
						try {
							model.init(get());
							model.fireTableDataChanged();

						} catch (Exception e) {
							logger.error(e);
						}
						lblLoading.end();
					}

				};

				lblLoading.start();
				newsPanel.setMagicNews((MagicNews) curr.getUserObject());
				ThreadManager.getInstance().runInEdt(sw,"loading rss");

			}
		});

		table.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent me) {
				List<MagicNewsContent> sels = UITools.getTableSelections(table, 0);
				MagicNewsContent sel = sels.get(0);
				if (me.getClickCount() == 2) {
					try {
						Desktop.getDesktop().browse(sel.getLink().toURI());

					} catch (Exception e1) {
						logger.error(e1);
					}
				} else {

					SwingWorker<Void, URL> sw = new SwingWorker<>()
					{
						@Override
						protected void done() {
							lblLoading.end();
							editorPane.setCaretPosition(0);

						}

						@Override
						protected void process(java.util.List<URL> chunks) {
							try {
								editorPane.setPage(chunks.get(0));
							} catch (IOException e) {
								logger.error("error loading " + chunks.get(0),e);
							}

						}

						@Override
						protected Void doInBackground() throws Exception {
							publish(sel.getLink());
							return null;
						}

					};

					lblLoading.start();
					ThreadManager.getInstance().runInEdt(sw,"loading "+sel.getLink());
				}
			}
		});

	}

	private void initActions() {
		btnNewButton.addActionListener(ae -> {
			newsPanel.setMagicNews(new MagicNews());
			newsPanel.setVisible(true);
		});

		btnSave.addActionListener(ae -> {
			try {
				MTGControler.getInstance().getEnabled(MTGDao.class).saveOrUpdateNews(newsPanel.getMagicNews());
				initTree();
			} catch (SQLException ex) {
				logger.error("Error saving news", ex);
				MTGControler.getInstance().notify(ex);
			}
		});

		btnDelete.addActionListener(ae -> {
			try {
				MTGControler.getInstance().getEnabled(MTGDao.class).deleteNews(newsPanel.getMagicNews());
				initTree();
			} catch (SQLException ex) {
				logger.error("Error delete news", ex);
				MTGControler.getInstance().notify(ex);
			}
		});

		tree.addTreeSelectionListener(tse -> {
			TreePath path = tse.getPath();
			curr = (DefaultMutableTreeNode) path.getLastPathComponent();

			if (curr.getUserObject() instanceof MagicNews)
			{
				SwingWorker<List<MagicNewsContent>, MagicNews> sw = new SwingWorker<List<MagicNewsContent>, MagicNews>()
				{

					@Override
					protected List<MagicNewsContent> doInBackground() throws Exception {
						MagicNews n = (MagicNews) curr.getUserObject();
						return n.getProvider().listNews(n);
					}

					@Override
					protected void done() {
						try {
							model.init(get());
							model.fireTableDataChanged();

						} catch (Exception e) {
							logger.error(e);
						}
						lblLoading.end();
					}

				};

				lblLoading.start();
				newsPanel.setMagicNews((MagicNews) curr.getUserObject());
				ThreadManager.getInstance().runInEdt(sw,"loading rss");

			}
		});

		table.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent me) {
				List<MagicNewsContent> sels = UITools.getTableSelections(table, 0);
				MagicNewsContent sel = sels.get(0);
				if (me.getClickCount() == 2) {
					try {
						Desktop.getDesktop().browse(sel.getLink().toURI());

					} catch (Exception e1) {
						logger.error(e1);
					}
				} else {

					SwingWorker<Void, URL> sw = new SwingWorker<Void, URL>()
					{
						@Override
						protected void done() {
							lblLoading.end();
							editorPane.setCaretPosition(0);

						}

						@Override
						protected void process(java.util.List<URL> chunks) {
							try {
								editorPane.setPage(chunks.get(0));
							} catch (IOException e) {
								logger.error("error loading " + chunks.get(0),e);
							}

						}

						@Override
						protected Void doInBackground() throws Exception {
							publish(sel.getLink());
							return null;
						}

					};

					lblLoading.start();
					ThreadManager.getInstance().runInEdt(sw,"loading "+sel.getLink());
				}
			}
		});

	}

Replace Generic With Diamond SwingWorker<List<MagicNewsContent>,MagicNews> with SwingWorker<> in method private initActions() : void from class org.magic.gui.RssGUI


			@Override
			public void mouseClicked(MouseEvent me) {
				List<MagicNewsContent> sels = UITools.getTableSelections(table, 0);
				MagicNewsContent sel = sels.get(0);
				if (me.getClickCount() == 2) {
					try {
						Desktop.getDesktop().browse(sel.getLink().toURI());

					} catch (Exception e1) {
						logger.error(e1);
					}
				} else {

					SwingWorker<Void, URL> sw = new SwingWorker<>()
					{
						@Override
						protected void done() {
							lblLoading.end();
							editorPane.setCaretPosition(0);

						}

						@Override
						protected void process(java.util.List<URL> chunks) {
							try {
								editorPane.setPage(chunks.get(0));
							} catch (IOException e) {
								logger.error("error loading " + chunks.get(0),e);
							}

						}

						@Override
						protected Void doInBackground() throws Exception {
							publish(sel.getLink());
							return null;
						}

					};

					lblLoading.start();
					ThreadManager.getInstance().runInEdt(sw,"loading "+sel.getLink());
				}
			}

			@Override
			public void mouseClicked(MouseEvent me) {
				List<MagicNewsContent> sels = UITools.getTableSelections(table, 0);
				MagicNewsContent sel = sels.get(0);
				if (me.getClickCount() == 2) {
					try {
						Desktop.getDesktop().browse(sel.getLink().toURI());

					} catch (Exception e1) {
						logger.error(e1);
					}
				} else {

					SwingWorker<Void, URL> sw = new SwingWorker<Void, URL>()
					{
						@Override
						protected void done() {
							lblLoading.end();
							editorPane.setCaretPosition(0);

						}

						@Override
						protected void process(java.util.List<URL> chunks) {
							try {
								editorPane.setPage(chunks.get(0));
							} catch (IOException e) {
								logger.error("error loading " + chunks.get(0),e);
							}

						}

						@Override
						protected Void doInBackground() throws Exception {
							publish(sel.getLink());
							return null;
						}

					};

					lblLoading.start();
					ThreadManager.getInstance().runInEdt(sw,"loading "+sel.getLink());
				}
			}

Replace Generic With Diamond SwingWorker<Void,URL> with SwingWorker<> in method public mouseClicked(me MouseEvent) : void from class org.magic.gui.RssGUI.initActions.addMouseListener.new MouseAdapter


	private void initTree() {
		rootNode.removeAllChildren();

		SwingWorker<Void, MagicNews> sw = new SwingWorker<>() {

			@Override
			protected void process(List<MagicNews> chunks) {
				chunks.forEach(cat->add(cat.getCategorie(), cat));
			}

			@Override
			protected Void doInBackground() throws Exception {
				for (MagicNews cat : MTGControler.getInstance().getEnabled(MTGDao.class).listNews())
					publish(cat);

				return null;
			}

			@Override
			protected void done() {
				((DefaultTreeModel) tree.getModel()).reload();

				for (int i = 0; i < tree.getRowCount(); i++)
					tree.expandRow(i + 1);

			}

		};

		ThreadManager.getInstance().runInEdt(sw,"Loading News Tree");
	}

	private void initTree() {
		rootNode.removeAllChildren();

		SwingWorker<Void, MagicNews> sw = new SwingWorker<Void, MagicNews>() {

			@Override
			protected void process(List<MagicNews> chunks) {
				chunks.forEach(cat->add(cat.getCategorie(), cat));
			}

			@Override
			protected Void doInBackground() throws Exception {
				for (MagicNews cat : MTGControler.getInstance().getEnabled(MTGDao.class).listNews())
					publish(cat);

				return null;
			}

			@Override
			protected void done() {
				((DefaultTreeModel) tree.getModel()).reload();

				for (int i = 0; i < tree.getRowCount(); i++)
					tree.expandRow(i + 1);

			}

		};

		ThreadManager.getInstance().runInEdt(sw,"Loading News Tree");
	}

Replace Generic With Diamond SwingWorker<Void,MagicNews> with SwingWorker<> in method private initTree() : void from class org.magic.gui.RssGUI


	public StockPanelGUI() {

		initGUI();

		btnSave.addActionListener(e ->{
			List<MagicCardStock> updates = model.getItems().stream().filter(MagicCardStock::isUpdate).collect(Collectors.toList());
			AbstractObservableWorker<Void, MagicCardStock,MTGDao> sw = new AbstractObservableWorker<>(lblLoading, MTGControler.getInstance().getEnabled(MTGDao.class),updates.size())
			{
				@Override
				protected void done() {
					super.done();
					model.fireTableDataChanged();
				}

				@Override
				protected Void doInBackground(){
					for (MagicCardStock ms : updates)
					{
						try {
							plug.saveOrUpdateStock(ms);
							ms.setUpdate(false);
						} catch (Exception e1) {
							logger.error(e1);
						}
					}
					return null;
				}
			};

			ThreadManager.getInstance().runInEdt(sw,"Batch stock save");

		});

		table.getSelectionModel().addListSelectionListener(event -> {
			if (!multiselection && !event.getValueIsAdjusting()) {
				int viewRow = table.getSelectedRow();
				if (viewRow > -1) {
					MagicCardStock selectedStock = UITools.getTableSelection(table, 0);
					btnDelete.setEnabled(true);
					updatePanels(selectedStock);
				}
			}
		});

		btnDelete.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CONFIRM_DELETE",table.getSelectedRows().length + " item(s)"),
					MTGControler.getInstance().getLangService().getCapitalize("DELETE") + " ?",JOptionPane.YES_NO_OPTION);

			if (res == JOptionPane.YES_OPTION) {

				List<MagicCardStock> stocks = UITools.getTableSelections(table, 0);
				model.removeItem(stocks);
				AbstractObservableWorker<Void, MagicCardStock, MTGDao> sw = new AbstractObservableWorker<>(lblLoading,MTGControler.getInstance().getEnabled(MTGDao.class),stocks.size()) {
					@Override
					protected Void doInBackground(){
						stocks.removeIf(st->st.getIdstock()==-1);
						if(!stocks.isEmpty())
						{
							try {
								plug.deleteStock(stocks);

							} catch (Exception e) {
								logger.error(e);
							}
						}

						return null;
					}

					@Override
					protected void process(List<MagicCardStock> chunks) {
						super.process(chunks);
						model.removeItem(chunks);
					}

					@Override
					protected void done() {
						super.done();
						model.fireTableDataChanged();
						updateCount();
					}
				};
				ThreadManager.getInstance().runInEdt(sw,"delete stocks");
			}
		});

		btnReload.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CANCEL_CHANGES"),MTGControler.getInstance().getLangService().getCapitalize("CONFIRM_UNDO"),JOptionPane.YES_NO_OPTION);
			if (res == JOptionPane.YES_OPTION)
			{
				logger.debug("reload collection");
				AbstractObservableWorker<Void, MagicCardStock, MTGDao> sw = new AbstractObservableWorker<>(lblLoading, MTGControler.getInstance().getEnabled(MTGDao.class), -1) {
					@Override
					protected Void doInBackground() throws Exception {
						model.init(plug.listStocks());
						return null;
					}
					@Override
					protected void done()
					{
						super.done();
						updateCount();
					}
				};
				ThreadManager.getInstance().runInEdt(sw, "reload stock");

			}

		});

		btnshowMassPanel.addActionListener(event -> rightPanel.setVisible(!rightPanel.isVisible()));

		btnImport.addActionListener(ae -> {
			JPopupMenu menu = new JPopupMenu();

			JMenuItem mnuImportSearch = new JMenuItem(MTGControler.getInstance().getLangService()
					.getCapitalize("IMPORT_FROM", MTGControler.getInstance().getLangService().get("SEARCH_MODULE")));
			mnuImportSearch.setIcon(MTGConstants.ICON_SEARCH);

			mnuImportSearch.addActionListener(importAE -> {
				CardSearchImportDialog cdSearch = new CardSearchImportDialog();
				cdSearch.setVisible(true);
				if (cdSearch.getSelection() != null) {
					for (MagicCard mc : cdSearch.getSelection())
						addCard(mc);
				}
			});
			menu.add(mnuImportSearch);

			for (final MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.IMPORT) {

					JMenuItem it = new JMenuItem();
					it.setIcon(exp.getIcon());
					it.setText(exp.getName());
					it.addActionListener(itemEvent -> {
						JFileChooser jf = new JFileChooser(".");
						jf.setFileFilter(new FileFilter() {

							@Override
							public String getDescription() {
								return exp.getName();
							}

							@Override
							public boolean accept(File f) {
								if (f.isDirectory())
									return true;
								return f.getName().endsWith(exp.getFileExtension());
							}
						});

						int res = -1;
						if (!exp.needDialogGUI()) {
							res = jf.showOpenDialog(null);
							fileImport = jf.getSelectedFile();
						} else {
							try {
								exp.importStock(null).forEach(this::addStock);

							} catch (IOException e1) {
								logger.error(e1);
							}

						}

						if (res == JFileChooser.APPROVE_OPTION)
						{
							AbstractObservableWorker<List<MagicCardStock>, MagicCard, MTGCardsExport> sw = new AbstractObservableWorker<>(lblLoading,exp)
							{
								@Override
								protected List<MagicCardStock> doInBackground() throws Exception {
									return plug.importStock(fileImport);
								}

								@Override
								protected void notifyEnd() {
									MTGControler.getInstance().notify(new MTGNotification(
										MTGControler.getInstance().getLangService().combine("IMPORT", FINISHED),
										exp.getName() + " "+ MTGControler.getInstance().getLangService().getCapitalize(FINISHED),
										MESSAGE_TYPE.INFO
									));
								}

								@Override
								protected void done() {
									super.done();
									if(getResult()!=null)
									{
										for (MagicCardStock mc : getResult()) {
											addStock(mc);
										}
										model.fireTableDataChanged();
										updateCount();
									}
								}
							};
							ThreadManager.getInstance().runInEdt(sw,"import stocks from " + fileImport);

						}
					});
					menu.add(it);
				}
			}

			Component b = (Component) ae.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());
		});

		btnExport.addActionListener(event -> {
			JPopupMenu menu = new JPopupMenu();

			for (final MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.EXPORT) {

					JMenuItem it = new JMenuItem();
					it.setIcon(exp.getIcon());
					it.setText(exp.getName());
					it.addActionListener(itEvent -> {
						JFileChooser jf = new JFileChooser(".");
						jf.setFileFilter(new FileFilter() {

							@Override
							public String getDescription() {
								return exp.getName();
							}

							@Override
							public boolean accept(File f) {
								return (f.isDirectory() || (f.getName().endsWith(exp.getFileExtension())));
							}
						});
						int res = jf.showSaveDialog(null);
						final File fileExport = jf.getSelectedFile();

						if (res == JFileChooser.APPROVE_OPTION)
						{

							AbstractObservableWorker<Void, MagicCardStock, MTGCardsExport> sw = new AbstractObservableWorker<>(lblLoading,exp,model.getItems().size()) {

								@Override
								protected Void doInBackground() throws Exception {
									plug.exportStock(model.getItems(), fileExport);
									return null;
								}

								@Override
								protected void notifyEnd() {
									MTGControler.getInstance().notify(new MTGNotification(MTGControler.getInstance().getLangService().combine("EXPORT", FINISHED),exp.getName() + " "
											+ MTGControler.getInstance().getLangService()
											.getCapitalize(FINISHED),MESSAGE_TYPE.INFO));

								}

							};

							ThreadManager.getInstance().runInEdt(sw, "export " + exp);
						}
					});
					menu.add(it);
				}
			}

			Component b = (Component) event.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());

		});

		btnGeneratePrice.addActionListener(ae -> {
			lblLoading.start(table.getSelectedRows().length);

			SwingWorker<Void,MagicCardStock> sw = new SwingWorker<>() {

				@Override
				public void done() {
					lblLoading.end();
				}

				@Override
				protected void process(List<MagicCardStock> chunks) {
					lblLoading.progressSmooth(chunks.size());
					model.fireTableDataChanged();
				}

				@Override
				protected Void doInBackground(){

					for (int i : table.getSelectedRows())
					{
						MagicCardStock s = (MagicCardStock) table.getModel().getValueAt(table.convertRowIndexToModel(i), 0);
						logger.debug("prices for" + s.getMagicCard());

						Collection<Double> prices;
						Double price = 0.0;
						try {
							prices = MTGControler.getInstance().getEnabled(MTGDashBoard.class).getPriceVariation(s.getMagicCard(), null).values();
							if (!prices.isEmpty())
								price = (Double) prices.toArray()[prices.size() - 1];
							else
								price = 0.0;

						} catch (IOException e) {
							logger.error("error getting price for " + s.getMagicCard(),e);
							price = 0.0;
						}
						double old = s.getPrice();
						s.setPrice(price);
						if (old != s.getPrice())
							s.setUpdate(true);

						publish(s);
					}
					return null;
				}

			};

			ThreadManager.getInstance().runInEdt(sw, "generate prices for stock");
		});

		cboSelections.addItemListener(ie -> {
			multiselection = true;
			if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[1])) {
				table.clearSelection();

				for (int i = 0; i < table.getRowCount(); i++) {
					if (table.getValueAt(i, 0).toString().equals("-1")) {
						table.addRowSelectionInterval(i, i);
					}
				}

			} else if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[2])) {
				table.clearSelection();

				for (int i = 0; i < table.getRowCount(); i++) {
					if (((MagicCardStock) table.getValueAt(i, 0)).isUpdate())
						table.addRowSelectionInterval(i, i);
				}
			}
			else if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[3])) {
				table.clearSelection();
				table.addRowSelectionInterval(0, table.getRowCount()-1);
			}
			multiselection = false;
		});

		btnApplyModification.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CHANGE_X_ITEMS",
							table.getSelectedRowCount()),
					MTGControler.getInstance().getLangService().getCapitalize("CONFIRMATION"),
					JOptionPane.YES_NO_CANCEL_OPTION);
			if (res == JOptionPane.YES_OPTION) {

				List<MagicCardStock> list = UITools.getTableSelections(table,0);

				for (MagicCardStock  s : list) {
					s.setUpdate(true);
					if (((Integer) spinner.getValue()).intValue() > 0)
						s.setQte((Integer) spinner.getValue());
					if (!textPane.getText().equals(""))
						s.setComment(textPane.getText());
					if (cboAltered.getSelectedItem() != null)
						s.setAltered((Boolean) cboAltered.getSelectedItem());
					if (cboSigned.getSelectedItem() != null)
						s.setSigned((Boolean) cboSigned.getSelectedItem());
					if (cboFoil.getSelectedItem() != null)
						s.setFoil((Boolean) cboFoil.getSelectedItem());
					if (cboLanguages != null)
						s.setLanguage(String.valueOf(cboLanguages.getSelectedItem()));
					if (cboQuality.getSelectedItem() != null)
						s.setCondition((EnumCondition) cboQuality.getSelectedItem());
					if (cboCollection.getSelectedItem() != null)
						s.setMagicCollection((MagicCollection) cboCollection.getSelectedItem());

				}
				model.fireTableDataChanged();
			}
		});

	}

	public StockPanelGUI() {

		initGUI();

		btnSave.addActionListener(e ->{
			List<MagicCardStock> updates = model.getItems().stream().filter(MagicCardStock::isUpdate).collect(Collectors.toList());
			AbstractObservableWorker<Void, MagicCardStock,MTGDao> sw = new AbstractObservableWorker<Void, MagicCardStock,MTGDao>(lblLoading, MTGControler.getInstance().getEnabled(MTGDao.class),updates.size())
			{
				@Override
				protected void done() {
					super.done();
					model.fireTableDataChanged();
				}

				@Override
				protected Void doInBackground(){
					for (MagicCardStock ms : updates)
					{
						try {
							plug.saveOrUpdateStock(ms);
							ms.setUpdate(false);
						} catch (Exception e1) {
							logger.error(e1);
						}
					}
					return null;
				}
			};

			ThreadManager.getInstance().runInEdt(sw,"Batch stock save");

		});

		table.getSelectionModel().addListSelectionListener(event -> {
			if (!multiselection && !event.getValueIsAdjusting()) {
				int viewRow = table.getSelectedRow();
				if (viewRow > -1) {
					MagicCardStock selectedStock = UITools.getTableSelection(table, 0);
					btnDelete.setEnabled(true);
					updatePanels(selectedStock);
				}
			}
		});

		btnDelete.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CONFIRM_DELETE",table.getSelectedRows().length + " item(s)"),
					MTGControler.getInstance().getLangService().getCapitalize("DELETE") + " ?",JOptionPane.YES_NO_OPTION);

			if (res == JOptionPane.YES_OPTION) {

				List<MagicCardStock> stocks = UITools.getTableSelections(table, 0);
				model.removeItem(stocks);
				AbstractObservableWorker<Void, MagicCardStock, MTGDao> sw = new AbstractObservableWorker<Void, MagicCardStock, MTGDao>(lblLoading,MTGControler.getInstance().getEnabled(MTGDao.class),stocks.size()) {
					@Override
					protected Void doInBackground(){
						stocks.removeIf(st->st.getIdstock()==-1);
						if(!stocks.isEmpty())
						{
							try {
								plug.deleteStock(stocks);

							} catch (Exception e) {
								logger.error(e);
							}
						}

						return null;
					}

					@Override
					protected void process(List<MagicCardStock> chunks) {
						super.process(chunks);
						model.removeItem(chunks);
					}

					@Override
					protected void done() {
						super.done();
						model.fireTableDataChanged();
						updateCount();
					}
				};
				ThreadManager.getInstance().runInEdt(sw,"delete stocks");
			}
		});

		btnReload.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CANCEL_CHANGES"),MTGControler.getInstance().getLangService().getCapitalize("CONFIRM_UNDO"),JOptionPane.YES_NO_OPTION);
			if (res == JOptionPane.YES_OPTION)
			{
				logger.debug("reload collection");
				AbstractObservableWorker<Void, MagicCardStock, MTGDao> sw = new AbstractObservableWorker<Void, MagicCardStock, MTGDao>(lblLoading, MTGControler.getInstance().getEnabled(MTGDao.class), -1) {
					@Override
					protected Void doInBackground() throws Exception {
						model.init(plug.listStocks());
						return null;
					}
					@Override
					protected void done()
					{
						super.done();
						updateCount();
					}
				};
				ThreadManager.getInstance().runInEdt(sw, "reload stock");

			}

		});

		btnshowMassPanel.addActionListener(event -> rightPanel.setVisible(!rightPanel.isVisible()));

		btnImport.addActionListener(ae -> {
			JPopupMenu menu = new JPopupMenu();

			JMenuItem mnuImportSearch = new JMenuItem(MTGControler.getInstance().getLangService()
					.getCapitalize("IMPORT_FROM", MTGControler.getInstance().getLangService().get("SEARCH_MODULE")));
			mnuImportSearch.setIcon(MTGConstants.ICON_SEARCH);

			mnuImportSearch.addActionListener(importAE -> {
				CardSearchImportDialog cdSearch = new CardSearchImportDialog();
				cdSearch.setVisible(true);
				if (cdSearch.getSelection() != null) {
					for (MagicCard mc : cdSearch.getSelection())
						addCard(mc);
				}
			});
			menu.add(mnuImportSearch);

			for (final MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.IMPORT) {

					JMenuItem it = new JMenuItem();
					it.setIcon(exp.getIcon());
					it.setText(exp.getName());
					it.addActionListener(itemEvent -> {
						JFileChooser jf = new JFileChooser(".");
						jf.setFileFilter(new FileFilter() {

							@Override
							public String getDescription() {
								return exp.getName();
							}

							@Override
							public boolean accept(File f) {
								if (f.isDirectory())
									return true;
								return f.getName().endsWith(exp.getFileExtension());
							}
						});

						int res = -1;
						if (!exp.needDialogGUI()) {
							res = jf.showOpenDialog(null);
							fileImport = jf.getSelectedFile();
						} else {
							try {
								exp.importStock(null).forEach(this::addStock);

							} catch (IOException e1) {
								logger.error(e1);
							}

						}

						if (res == JFileChooser.APPROVE_OPTION)
						{
							AbstractObservableWorker<List<MagicCardStock>, MagicCard, MTGCardsExport> sw = new AbstractObservableWorker<List<MagicCardStock>, MagicCard, MTGCardsExport>(lblLoading,exp)
							{
								@Override
								protected List<MagicCardStock> doInBackground() throws Exception {
									return plug.importStock(fileImport);
								}

								@Override
								protected void notifyEnd() {
									MTGControler.getInstance().notify(new MTGNotification(
										MTGControler.getInstance().getLangService().combine("IMPORT", FINISHED),
										exp.getName() + " "+ MTGControler.getInstance().getLangService().getCapitalize(FINISHED),
										MESSAGE_TYPE.INFO
									));
								}

								@Override
								protected void done() {
									super.done();
									if(getResult()!=null)
									{
										for (MagicCardStock mc : getResult()) {
											addStock(mc);
										}
										model.fireTableDataChanged();
										updateCount();
									}
								}
							};
							ThreadManager.getInstance().runInEdt(sw,"import stocks from " + fileImport);

						}
					});
					menu.add(it);
				}
			}

			Component b = (Component) ae.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());
		});

		btnExport.addActionListener(event -> {
			JPopupMenu menu = new JPopupMenu();

			for (final MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.EXPORT) {

					JMenuItem it = new JMenuItem();
					it.setIcon(exp.getIcon());
					it.setText(exp.getName());
					it.addActionListener(itEvent -> {
						JFileChooser jf = new JFileChooser(".");
						jf.setFileFilter(new FileFilter() {

							@Override
							public String getDescription() {
								return exp.getName();
							}

							@Override
							public boolean accept(File f) {
								return (f.isDirectory() || (f.getName().endsWith(exp.getFileExtension())));
							}
						});
						int res = jf.showSaveDialog(null);
						final File fileExport = jf.getSelectedFile();

						if (res == JFileChooser.APPROVE_OPTION)
						{

							AbstractObservableWorker<Void, MagicCardStock, MTGCardsExport> sw = new AbstractObservableWorker<Void, MagicCardStock, MTGCardsExport>(lblLoading,exp,model.getItems().size()) {

								@Override
								protected Void doInBackground() throws Exception {
									plug.exportStock(model.getItems(), fileExport);
									return null;
								}

								@Override
								protected void notifyEnd() {
									MTGControler.getInstance().notify(new MTGNotification(MTGControler.getInstance().getLangService().combine("EXPORT", FINISHED),exp.getName() + " "
											+ MTGControler.getInstance().getLangService()
											.getCapitalize(FINISHED),MESSAGE_TYPE.INFO));

								}

							};

							ThreadManager.getInstance().runInEdt(sw, "export " + exp);
						}
					});
					menu.add(it);
				}
			}

			Component b = (Component) event.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());

		});

		btnGeneratePrice.addActionListener(ae -> {
			lblLoading.start(table.getSelectedRows().length);

			SwingWorker<Void,MagicCardStock> sw = new SwingWorker<Void, MagicCardStock>() {

				@Override
				public void done() {
					lblLoading.end();
				}

				@Override
				protected void process(List<MagicCardStock> chunks) {
					lblLoading.progressSmooth(chunks.size());
					model.fireTableDataChanged();
				}

				@Override
				protected Void doInBackground(){

					for (int i : table.getSelectedRows())
					{
						MagicCardStock s = (MagicCardStock) table.getModel().getValueAt(table.convertRowIndexToModel(i), 0);
						logger.debug("prices for" + s.getMagicCard());

						Collection<Double> prices;
						Double price = 0.0;
						try {
							prices = MTGControler.getInstance().getEnabled(MTGDashBoard.class).getPriceVariation(s.getMagicCard(), null).values();
							if (!prices.isEmpty())
								price = (Double) prices.toArray()[prices.size() - 1];
							else
								price = 0.0;

						} catch (IOException e) {
							logger.error("error getting price for " + s.getMagicCard(),e);
							price = 0.0;
						}
						double old = s.getPrice();
						s.setPrice(price);
						if (old != s.getPrice())
							s.setUpdate(true);

						publish(s);
					}
					return null;
				}

			};

			ThreadManager.getInstance().runInEdt(sw, "generate prices for stock");
		});

		cboSelections.addItemListener(ie -> {
			multiselection = true;
			if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[1])) {
				table.clearSelection();

				for (int i = 0; i < table.getRowCount(); i++) {
					if (table.getValueAt(i, 0).toString().equals("-1")) {
						table.addRowSelectionInterval(i, i);
					}
				}

			} else if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[2])) {
				table.clearSelection();

				for (int i = 0; i < table.getRowCount(); i++) {
					if (((MagicCardStock) table.getValueAt(i, 0)).isUpdate())
						table.addRowSelectionInterval(i, i);
				}
			}
			else if (String.valueOf(cboSelections.getSelectedItem()).equals(selections[3])) {
				table.clearSelection();
				table.addRowSelectionInterval(0, table.getRowCount()-1);
			}
			multiselection = false;
		});

		btnApplyModification.addActionListener(event -> {
			int res = JOptionPane.showConfirmDialog(null,
					MTGControler.getInstance().getLangService().getCapitalize("CHANGE_X_ITEMS",
							table.getSelectedRowCount()),
					MTGControler.getInstance().getLangService().getCapitalize("CONFIRMATION"),
					JOptionPane.YES_NO_CANCEL_OPTION);
			if (res == JOptionPane.YES_OPTION) {

				List<MagicCardStock> list = UITools.getTableSelections(table,0);

				for (MagicCardStock  s : list) {
					s.setUpdate(true);
					if (((Integer) spinner.getValue()).intValue() > 0)
						s.setQte((Integer) spinner.getValue());
					if (!textPane.getText().equals(""))
						s.setComment(textPane.getText());
					if (cboAltered.getSelectedItem() != null)
						s.setAltered((Boolean) cboAltered.getSelectedItem());
					if (cboSigned.getSelectedItem() != null)
						s.setSigned((Boolean) cboSigned.getSelectedItem());
					if (cboFoil.getSelectedItem() != null)
						s.setFoil((Boolean) cboFoil.getSelectedItem());
					if (cboLanguages != null)
						s.setLanguage(String.valueOf(cboLanguages.getSelectedItem()));
					if (cboQuality.getSelectedItem() != null)
						s.setCondition((EnumCondition) cboQuality.getSelectedItem());
					if (cboCollection.getSelectedItem() != null)
						s.setMagicCollection((MagicCollection) cboCollection.getSelectedItem());

				}
				model.fireTableDataChanged();
			}
		});

	}

Replace Generic With Diamond AbstractObservableWorker<Void,MagicCardStock,MTGDao> with AbstractObservableWorker<> in method public StockPanelGUI() from class org.magic.gui.StockPanelGUI


	public void initStories() {

		SwingWorker<Void, MTGStory> sw = new SwingWorker<>() {

			@Override
			protected Void doInBackground(){
				try {
					for (MTGStory story : provider.next())
						resultListModel.addElement(story);
				} catch (IOException e) {
					logger.error(e);
				}

				return null;
			}

			@Override
			protected void done() {
				lblLoading.end();
			}

		};

		lblLoading.start();
		ThreadManager.getInstance().runInEdt(sw, "loading stories");
	}

	public void initStories() {

		SwingWorker<Void, MTGStory> sw = new SwingWorker<Void, MTGStory>() {

			@Override
			protected Void doInBackground(){
				try {
					for (MTGStory story : provider.next())
						resultListModel.addElement(story);
				} catch (IOException e) {
					logger.error(e);
				}

				return null;
			}

			@Override
			protected void done() {
				lblLoading.end();
			}

		};

		lblLoading.start();
		ThreadManager.getInstance().runInEdt(sw, "loading stories");
	}

Replace Generic With Diamond SwingWorker<Void,MTGStory> with SwingWorker<> in method public initStories() : void from class org.magic.gui.StoriesGUI


	public void setEdition(MagicEdition ed) {

		this.ed=ed;
		removeAll();
		revalidate();

		if(sw!=null && !sw.isDone())
			sw.cancel(true);

		if(ed!=null)
		{
			sw = new SwingWorker<>() {
				@Override
				protected void process(List<SimpleEntry<Packaging, ImageIcon>> chunks) {
					chunks.forEach(e->addTab(e.getKey().toString(), new JLabel(e.getValue())));
				}

				@Override
				protected ImageIcon doInBackground() {

					List<Packaging> l = PackagesProvider.inst().get(ed,TYPE.BOOSTER);
					logger.trace("loading booster :" + l);
					l.forEach(i->
					{
						try {
							publish(new SimpleEntry<>(i,new ImageIcon(resizeBooster(PackagesProvider.inst().get(i)))));
						}catch(Exception e)
						{
							logger.error("error " + e);
						}
					});
					return null;
				}
			};
			ThreadManager.getInstance().runInEdt(sw,"load booster pic for " + ed);
		}
	}

	public void setEdition(MagicEdition ed) {

		this.ed=ed;
		removeAll();
		revalidate();

		if(sw!=null && !sw.isDone())
			sw.cancel(true);

		if(ed!=null)
		{
			sw = new SwingWorker<ImageIcon, SimpleEntry<Packaging, ImageIcon>>() {
				@Override
				protected void process(List<SimpleEntry<Packaging, ImageIcon>> chunks) {
					chunks.forEach(e->addTab(e.getKey().toString(), new JLabel(e.getValue())));
				}

				@Override
				protected ImageIcon doInBackground() {

					List<Packaging> l = PackagesProvider.inst().get(ed,TYPE.BOOSTER);
					logger.trace("loading booster :" + l);
					l.forEach(i->
					{
						try {
							publish(new SimpleEntry<>(i,new ImageIcon(resizeBooster(PackagesProvider.inst().get(i)))));
						}catch(Exception e)
						{
							logger.error("error " + e);
						}
					});
					return null;
				}
			};
			ThreadManager.getInstance().runInEdt(sw,"load booster pic for " + ed);
		}
	}

Replace Generic With Diamond SwingWorker<ImageIcon,SimpleEntry<Packaging,ImageIcon>> with SwingWorker<> in method public setEdition(ed MagicEdition) : void from class org.magic.gui.components.BoosterPicsPanel


	public void initGUI() {
		cardsModeltable = new MagicCardTableModel();
		JPanel panelResultsCards;
		JPanel panelFilters;
		JPanel panelmana;
		JPanel editionDetailPanel;
		JPanel panneauHaut;
		JPanel panneauCard;
		JPanel panneauStat;
		JTextField txtFilter;
		JComboBox<MagicEdition> cboEdition;
		JButton btnClear;
		JButton btnFilter;

		DefaultRowSorter<DefaultTableModel, Integer> sorterCards;
		sorterCards = new TableRowSorter<>(cardsModeltable);
		sorterCards.setComparator(7, (String num1, String num2) -> {
			try {
				num1 = num1.replaceAll("a", "").replaceAll("b", "").trim();
				num2 = num2.replaceAll("a", "").replaceAll("b", "").trim();
				if (Integer.parseInt(num1) > Integer.parseInt(num2))
					return 1;
				else
					return -1;
			} catch (NumberFormatException e) {
				return -1;
			}
		});

		List<MagicEdition> li = new ArrayList<>();
		try {
			li = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).loadEditions();
			Collections.sort(li);
		} catch (Exception e2) {
			logger.error("error no edition loaded", e2);
		}

		//////// INIT COMPONENTS

		JScrollPane scrollThumbnails = new JScrollPane();
		JSplitPane panneauCentral = new JSplitPane();
		panneauStat = new JPanel();
		panneauHaut = new JPanel();
		panneauCard = new JPanel();
		JTabbedPane tabbedCardsInfo = new JTabbedPane(JTabbedPane.TOP);
		editionDetailPanel = new JPanel();
		panelResultsCards = new JPanel();
		cmcChart = new CmcChartPanel();
		manaRepartitionPanel = new ManaRepartitionPanel();
		typeRepartitionPanel = new TypeRepartitionPanel();
		historyChartPanel = new HistoryPricesPanel(true);
		cardsPicPanel = new CardsPicPanel();
		priceTablePanel = new PricesTablePanel();
		rarityRepartitionPanel = new RarityRepartitionPanel();
		detailCardPanel = new MagicCardDetailPanel();
		panelmana = new JPanel();
		panelFilters = new JPanel();
		ManaPanel pan = new ManaPanel();
		panelJson = new ObjectViewerPanel();
		tabbedCardsView = new JTabbedPane(JTabbedPane.TOP);
		thumbnailPanel = new HandPanel();
		thumbnailPanel.setBackground(MTGConstants.THUMBNAIL_BACKGROUND_COLOR);
		btnExport = new JButton(MTGConstants.ICON_EXPORT);
		btnFilter = new JButton(MTGConstants.ICON_FILTER);
		btnClear = new JButton(MTGConstants.ICON_CLEAR);
		similarityPanel = new SimilarityCardPanel();
		cboQuereableItems = UITools.createCombobox(MTGControler.getInstance().getEnabled(MTGCardsProvider.class).getQueryableAttributs());
		cboCollections = UITools.createComboboxCollection();
		tableCards = new JXTable();
		lblLoading = AbstractBuzyIndicatorComponent.createProgressComponent();
		JLabel lblFilter = new JLabel();
		listEdition = new JList<>();

		txtSearch = UITools.createSearchField();

		txtRulesArea = new JTextArea();

		txtFilter = new JTextField();

		UITools.initTableFilter(tableCards);

		cboEdition = UITools.createComboboxEditions();

		deckPanel = new CardsDeckCheckerPanel();

		//////// MODELS
		listEdition.setModel(new DefaultListModel<MagicEdition>());
		tableCards.setModel(cardsModeltable);

		//////// RENDERER
		tableCards.getColumnModel().getColumn(2).setCellRenderer(new ManaCellRenderer());
		tableCards.getColumnModel().getColumn(6).setCellRenderer(new MagicEditionsJLabelRenderer());
		listEdition.setCellRenderer(new MagicEditionIconListRenderer());

		///////// CONFIGURE COMPONENTS
		txtRulesArea.setLineWrap(true);
		txtRulesArea.setWrapStyleWord(true);
		txtRulesArea.setEditable(false);
		btnFilter.setToolTipText(MTGControler.getInstance().getLangService().getCapitalize("FILTER"));
		btnExport.setToolTipText(MTGControler.getInstance().getLangService().getCapitalize("EXPORT_RESULTS"));
		btnExport.setEnabled(false);
		cboQuereableItems.addItem("collections");
		listEdition.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		thumbnailPanel.enableDragging(false);
		panneauCentral.setOrientation(JSplitPane.VERTICAL_SPLIT);
		panneauCentral.setRightComponent(tabbedCardsInfo);
		panneauCentral.setLeftComponent(tabbedCardsView);
		tableCards.setRowHeight(MTGConstants.TABLE_ROW_HEIGHT);
		tableCards.setRowSorter(sorterCards);
		tableCards.getColumnExt(cardsModeltable.getColumnName(8)).setVisible(false);
		tableCards.getColumnExt(cardsModeltable.getColumnName(9)).setVisible(false);
		panneauCentral.setDividerLocation(0.5);
		panneauCentral.setResizeWeight(0.5);

		/////// LAYOUT
		setLayout(new BorderLayout());
		panneauStat.setLayout(new GridLayout(2, 2, 0, 0));
		panneauCard.setLayout(new BorderLayout());
		editionDetailPanel.setLayout(new BorderLayout());
		panelResultsCards.setLayout(new BorderLayout(0, 0));
		panelmana.setLayout(new GridLayout(1, 0, 2, 2));

		FlowLayout flpanelFilters = (FlowLayout) panelFilters.getLayout();
		flpanelFilters.setAlignment(FlowLayout.LEFT);

		FlowLayout flowLayout = (FlowLayout) panneauHaut.getLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);

		/////// DIMENSION
		thumbnailPanel.setThumbnailSize(new Dimension(179, 240));
		tabbedCardsInfo.setPreferredSize(new Dimension(0, 350));
		historyChartPanel.setPreferredSize(new Dimension(400, 10));
		cardsPicPanel.setPreferredSize(new Dimension(500, 10));
		tabbedCardsInfo.setMinimumSize(new Dimension(23, 200));
		scrollThumbnails.getVerticalScrollBar().setUnitIncrement(10);
		txtFilter.setColumns(25);
		txtSearch.setColumns(50);

		/////// VISIBILITY
		tableCards.setColumnControlVisible(true);
		panelFilters.setVisible(false);
		lblLoading.setVisible(false);
		cboCollections.setVisible(false);
		tableCards.setShowVerticalLines(false);
		cboEdition.setVisible(false);

		////// ADD PANELS
		for (String s : new String[] { "W", "U", "B", "R", "G", "C", "1" }) {
			final JButton btnG = new JButton();
			btnG.setToolTipText(s);
			if (s.equals("1"))
				btnG.setToolTipText("[0-9]*");

			btnG.setIcon(new ImageIcon(pan.getManaSymbol(s).getScaledInstance(15, 15, Image.SCALE_SMOOTH)));
			btnG.setForeground(btnG.getBackground());
			btnG.addActionListener(e -> {
				txtFilter.setText("\\{" + btnG.getToolTipText() + "}");
				sorterCards.setRowFilter(RowFilter.regexFilter(txtFilter.getText()));
			});
			panelmana.add(btnG);

		}
		scrollThumbnails.setViewportView(thumbnailPanel);

		panneauHaut.add(cboQuereableItems);
		panneauHaut.add(cboCollections);
		panneauHaut.add(txtSearch);
		panneauHaut.add(cboEdition);
		panneauHaut.add(btnFilter);
		panneauHaut.add(btnExport);
		panneauHaut.add(lblLoading);
		panneauCard.add(new JScrollPane(listEdition), BorderLayout.SOUTH);
		panneauCard.add(cardsPicPanel, BorderLayout.CENTER);

		panelResultsCards.add(panelFilters, BorderLayout.NORTH);
		panelResultsCards.add(new JScrollPane(tableCards));
		magicEditionDetailPanel = new MagicEditionDetailPanel();

		editionDetailPanel.add(magicEditionDetailPanel, BorderLayout.CENTER);

		panelFilters.add(lblFilter);
		panelFilters.add(txtFilter);
		panelFilters.add(btnClear);
		panelFilters.add(panelmana);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("DETAILS"), MTGConstants.ICON_TAB_DETAILS,
				detailCardPanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("EDITION"), MTGConstants.ICON_BACK,
				editionDetailPanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("PRICES"), MTGConstants.ICON_TAB_PRICES,
				priceTablePanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("RULES"), MTGConstants.ICON_TAB_RULES,
				new JScrollPane(txtRulesArea), null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("PRICE_VARIATIONS"), MTGConstants.ICON_TAB_VARIATIONS,
				historyChartPanel, null);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("MORE_LIKE_THIS"), MTGConstants.ICON_TAB_SIMILARITY,similarityPanel, null);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("DECK_MODULE"), MTGConstants.ICON_TAB_DECK,deckPanel, null);

		if (MTGControler.getInstance().get("debug-json-panel").equalsIgnoreCase("true"))
			tabbedCardsInfo.addTab("Object", MTGConstants.ICON_TAB_JSON, panelJson, null);

		panneauStat.add(cmcChart);
		panneauStat.add(manaRepartitionPanel);
		panneauStat.add(typeRepartitionPanel);
		panneauStat.add(rarityRepartitionPanel);

		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("RESULTS"),  MTGConstants.ICON_TAB_RESULTS,panelResultsCards, null);
		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("THUMBNAIL"), MTGConstants.ICON_TAB_THUMBNAIL,scrollThumbnails, null);
		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("STATS"), MTGConstants.ICON_TAB_ANALYSE, panneauStat,null);

		add(panneauHaut, BorderLayout.NORTH);
		add(panneauCard, BorderLayout.EAST);
		add(panneauCentral, BorderLayout.CENTER);

		/////// Right click
		try {
			initPopupCollection();
		} catch (Exception e2) {
			logger.error(e2);
		}

		/////// Action listners
		addComponentListener(new ComponentAdapter() {
			@Override
		    public void componentShown(ComponentEvent componentEvent){
		        txtSearch.requestFocus();
				panneauCentral.setDividerLocation(.45);

				removeComponentListener(this);
		    }
		});

		similarityPanel.getTableSimilarity().addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent evt) {

				if(similarityPanel.getTableSimilarity().getSelectedRow()==-1)
					return;

				MagicCard mc = (MagicCard) similarityPanel.getTableSimilarity().getValueAt(similarityPanel.getTableSimilarity().getSelectedRow(), 0);
				cardsPicPanel.showPhoto(mc);
			}
		});

		cboEdition.addActionListener(ae -> {
				txtSearch.setText(((MagicEdition) cboEdition.getSelectedItem()).getId());
				txtSearch.postActionEvent();
				});

		cboCollections.addActionListener(ae -> {
			txtSearch.setText(((MagicCollection) cboCollections.getSelectedItem()).getName());
			txtSearch.postActionEvent();
		});

		btnClear.addActionListener(ae -> {
			txtFilter.setText("");
			sorterCards.setRowFilter(null);
		});

		btnFilter.addActionListener(ae -> panelFilters.setVisible(!panelFilters.isVisible()));

		cboQuereableItems.addActionListener(e -> {
			if (cboQuereableItems.getSelectedItem().toString().equalsIgnoreCase("set")) {
				txtSearch.setVisible(false);
				cboEdition.setVisible(true);
				cboCollections.setVisible(false);
			} else if (cboQuereableItems.getSelectedItem().toString().equalsIgnoreCase("collections")) {
				txtSearch.setVisible(false);
				cboEdition.setVisible(false);
				cboCollections.setVisible(true);
			} else {
				txtSearch.setVisible(true);
				cboEdition.setVisible(false);
				cboCollections.setVisible(false);
			}
		});

		txtSearch.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				txtSearch.setText("");
			}
		});

		txtSearch.addActionListener(ae -> {

			selectedEdition = null;
			if (txtSearch.getText().equals("") && !cboCollections.isVisible())
				return;

			lblLoading.start();
			lblLoading.setText(MTGControler.getInstance().getLangService().getCapitalize("SEARCHING"));

			MTGPlugin plug = (cboCollections.isVisible()) ? MTGControler.getInstance().getEnabled(MTGDao.class):MTGControler.getInstance().getEnabled(MTGCardsProvider.class);
			String searchName = txtSearch.getText().trim();
			cardsModeltable.clear();

			AbstractObservableWorker<List<MagicCard>, MagicCard, MTGPlugin> wk = new AbstractObservableWorker<>(lblLoading,plug) {
				@Override
				protected List<MagicCard> doInBackground() throws Exception {
					List<MagicCard> cards;

					if (cboCollections.isVisible()) {
						cards=((MTGDao)plug).listCardsFromCollection((MagicCollection) cboCollections.getSelectedItem());
					}
					else if(cboEdition.isVisible()) {
						cards=((MTGCardsProvider)plug).searchCardByEdition((MagicEdition)cboEdition.getSelectedItem());
					}
					else {
						cards=((MTGCardsProvider)plug).searchCardByCriteria(cboQuereableItems.getSelectedItem().toString(), searchName, null, false);
					}

					try {
						Collections.sort(cards, new CardsEditionSorter());
					}
					catch(IllegalArgumentException e)
					{
						logger.error("error sorting result "+e);
					}

					return cards;
				}

				@Override
				protected void process(List<MagicCard> chunks) {
					super.process(chunks);
					cardsModeltable.addItems(chunks);
				}

				@Override
				protected void done() {
					super.done();
					open(getResult());
					btnExport.setEnabled(tableCards.getRowCount() > 0);
				}
			};
			ThreadManager.getInstance().runInEdt(wk,"searching "+txtSearch.getText());

		});

		tableCards.getSelectionModel().addListSelectionListener(event -> {
			if (!event.getValueIsAdjusting()) {
				try {
					selectedCard = UITools.getTableSelection(tableCards, 0);
					selectedEdition = selectedCard.getCurrentSet();
					updateCards();
				} catch (Exception e) {
					logger.error(e);
				}
			}
		});

		tableCards.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent evt) {

				if(tableCards.getSelectedRow()==-1)
					return;

				if (SwingUtilities.isRightMouseButton(evt)) {
					Point point = evt.getPoint();
					popupMenu.show(tableCards, (int) point.getX(), (int) point.getY());
				} else {
					try {
						selectedCard = UITools.getTableSelection(tableCards, 0);
						selectedEdition = selectedCard.getCurrentSet();
						updateCards();
					} catch (Exception e) {
						logger.error(e);
					}

				}
			}
		});

		listEdition.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent mev) {
				selectedEdition = listEdition.getSelectedValue();

				SwingWorker<MagicCard, MagicCard> sw = new SwingWorker<>()
						{

							@Override
							protected void process(List<MagicCard> chunks) {
								detailCardPanel.setMagicCard(chunks.get(0));
								magicEditionDetailPanel.setMagicEdition(selectedEdition);
							}

							@Override
							protected MagicCard doInBackground() throws Exception {
								try {
									MagicCard mc = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByName( selectedCard.getName(), selectedEdition, false).get(0);
									publish(mc);
									return mc;
								} catch (Exception e) {
									logger.error(e);
									return null;
								}

							}
							@Override
							protected void done() {
								try {
									selectedCard = get();
									cardsPicPanel.showPhoto(selectedCard); // backcard
									historyChartPanel.init(selectedCard, selectedEdition, selectedCard.getName());
									priceTablePanel.init(selectedCard,selectedEdition);
								} catch (Exception e) {
									logger.error(e);
								}
							}

						};

				ThreadManager.getInstance().runInEdt(sw,"loading " + selectedCard);
			}
		});

		detailCardPanel.addObserver((Observable o, Object obj)->{
			MagicCardNames selLang = (MagicCardNames)obj;
			try {
					MagicEdition ed = (MagicEdition) BeanUtils.cloneBean(selectedEdition);
								 ed.setMultiverseid(String.valueOf(selLang.getGathererId()));

					logger.trace("change lang to " + selLang + " for " + ed);
					cardsPicPanel.showPhoto(selectedCard, ed);
			} catch (Exception e1) {
				logger.error(e1);
			}

		});

		btnExport.addActionListener(ae -> {
			JPopupMenu menu = new JPopupMenu();

			for (MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.EXPORT) {
					JMenuItem it = new JMenuItem(exp.getName(), exp.getIcon());
					it.addActionListener(exportEvent -> {
						int result = JFileChooser.CANCEL_OPTION;
						File f = null;
						if(exp.needFile())
						{
							JFileChooser jf = new JFileChooser(".");
							jf.setSelectedFile(new File("search" + exp.getFileExtension()));
							result = jf.showSaveDialog(null);
							f = jf.getSelectedFile();
						}
						else
						{
							result = JFileChooser.APPROVE_OPTION;
						}

						if (result == JFileChooser.APPROVE_OPTION)
						{
							List<MagicCard> export = UITools.getTableSelections(tableCards,0);

							if(export.isEmpty())
								export =  ((MagicCardTableModel) tableCards.getRowSorter().getModel()).getItems();

							lblLoading.start(export.size());
							ThreadManager.getInstance().runInEdt(new CardExportWorker(exp, export, lblLoading, f), "export search " + exp);
						}
					});

					menu.add(it);
				}

			}

			Component b = (Component) ae.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());
		});

		txtFilter.addActionListener(ae -> {
			String text = txtFilter.getText();
			if (text.length() == 0) {
				sorterCards.setRowFilter(null);
			} else {
				sorterCards.setRowFilter(RowFilter.regexFilter(text));
			}
		});

		thumbnailPanel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				DisplayableCard lab = (DisplayableCard) thumbnailPanel.getComponentAt(new Point(e.getX(), e.getY()));
				selectedCard = lab.getMagicCard();
				selectedEdition = lab.getMagicCard().getCurrentSet();
				cardsPicPanel.showPhoto(selectedCard);
				updateCards();
			}

		});

	}

	public void initGUI() {
		cardsModeltable = new MagicCardTableModel();
		JPanel panelResultsCards;
		JPanel panelFilters;
		JPanel panelmana;
		JPanel editionDetailPanel;
		JPanel panneauHaut;
		JPanel panneauCard;
		JPanel panneauStat;
		JTextField txtFilter;
		JComboBox<MagicEdition> cboEdition;
		JButton btnClear;
		JButton btnFilter;

		DefaultRowSorter<DefaultTableModel, Integer> sorterCards;
		sorterCards = new TableRowSorter<>(cardsModeltable);
		sorterCards.setComparator(7, (String num1, String num2) -> {
			try {
				num1 = num1.replaceAll("a", "").replaceAll("b", "").trim();
				num2 = num2.replaceAll("a", "").replaceAll("b", "").trim();
				if (Integer.parseInt(num1) > Integer.parseInt(num2))
					return 1;
				else
					return -1;
			} catch (NumberFormatException e) {
				return -1;
			}
		});

		List<MagicEdition> li = new ArrayList<>();
		try {
			li = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).loadEditions();
			Collections.sort(li);
		} catch (Exception e2) {
			logger.error("error no edition loaded", e2);
		}

		//////// INIT COMPONENTS

		JScrollPane scrollThumbnails = new JScrollPane();
		JSplitPane panneauCentral = new JSplitPane();
		panneauStat = new JPanel();
		panneauHaut = new JPanel();
		panneauCard = new JPanel();
		JTabbedPane tabbedCardsInfo = new JTabbedPane(JTabbedPane.TOP);
		editionDetailPanel = new JPanel();
		panelResultsCards = new JPanel();
		cmcChart = new CmcChartPanel();
		manaRepartitionPanel = new ManaRepartitionPanel();
		typeRepartitionPanel = new TypeRepartitionPanel();
		historyChartPanel = new HistoryPricesPanel(true);
		cardsPicPanel = new CardsPicPanel();
		priceTablePanel = new PricesTablePanel();
		rarityRepartitionPanel = new RarityRepartitionPanel();
		detailCardPanel = new MagicCardDetailPanel();
		panelmana = new JPanel();
		panelFilters = new JPanel();
		ManaPanel pan = new ManaPanel();
		panelJson = new ObjectViewerPanel();
		tabbedCardsView = new JTabbedPane(JTabbedPane.TOP);
		thumbnailPanel = new HandPanel();
		thumbnailPanel.setBackground(MTGConstants.THUMBNAIL_BACKGROUND_COLOR);
		btnExport = new JButton(MTGConstants.ICON_EXPORT);
		btnFilter = new JButton(MTGConstants.ICON_FILTER);
		btnClear = new JButton(MTGConstants.ICON_CLEAR);
		similarityPanel = new SimilarityCardPanel();
		cboQuereableItems = UITools.createCombobox(MTGControler.getInstance().getEnabled(MTGCardsProvider.class).getQueryableAttributs());
		cboCollections = UITools.createComboboxCollection();
		tableCards = new JXTable();
		lblLoading = AbstractBuzyIndicatorComponent.createProgressComponent();
		JLabel lblFilter = new JLabel();
		listEdition = new JList<>();

		txtSearch = UITools.createSearchField();

		txtRulesArea = new JTextArea();

		txtFilter = new JTextField();

		UITools.initTableFilter(tableCards);

		cboEdition = UITools.createComboboxEditions();

		deckPanel = new CardsDeckCheckerPanel();

		//////// MODELS
		listEdition.setModel(new DefaultListModel<MagicEdition>());
		tableCards.setModel(cardsModeltable);

		//////// RENDERER
		tableCards.getColumnModel().getColumn(2).setCellRenderer(new ManaCellRenderer());
		tableCards.getColumnModel().getColumn(6).setCellRenderer(new MagicEditionsJLabelRenderer());
		listEdition.setCellRenderer(new MagicEditionIconListRenderer());

		///////// CONFIGURE COMPONENTS
		txtRulesArea.setLineWrap(true);
		txtRulesArea.setWrapStyleWord(true);
		txtRulesArea.setEditable(false);
		btnFilter.setToolTipText(MTGControler.getInstance().getLangService().getCapitalize("FILTER"));
		btnExport.setToolTipText(MTGControler.getInstance().getLangService().getCapitalize("EXPORT_RESULTS"));
		btnExport.setEnabled(false);
		cboQuereableItems.addItem("collections");
		listEdition.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		thumbnailPanel.enableDragging(false);
		panneauCentral.setOrientation(JSplitPane.VERTICAL_SPLIT);
		panneauCentral.setRightComponent(tabbedCardsInfo);
		panneauCentral.setLeftComponent(tabbedCardsView);
		tableCards.setRowHeight(MTGConstants.TABLE_ROW_HEIGHT);
		tableCards.setRowSorter(sorterCards);
		tableCards.getColumnExt(cardsModeltable.getColumnName(8)).setVisible(false);
		tableCards.getColumnExt(cardsModeltable.getColumnName(9)).setVisible(false);
		panneauCentral.setDividerLocation(0.5);
		panneauCentral.setResizeWeight(0.5);

		/////// LAYOUT
		setLayout(new BorderLayout());
		panneauStat.setLayout(new GridLayout(2, 2, 0, 0));
		panneauCard.setLayout(new BorderLayout());
		editionDetailPanel.setLayout(new BorderLayout());
		panelResultsCards.setLayout(new BorderLayout(0, 0));
		panelmana.setLayout(new GridLayout(1, 0, 2, 2));

		FlowLayout flpanelFilters = (FlowLayout) panelFilters.getLayout();
		flpanelFilters.setAlignment(FlowLayout.LEFT);

		FlowLayout flowLayout = (FlowLayout) panneauHaut.getLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);

		/////// DIMENSION
		thumbnailPanel.setThumbnailSize(new Dimension(179, 240));
		tabbedCardsInfo.setPreferredSize(new Dimension(0, 350));
		historyChartPanel.setPreferredSize(new Dimension(400, 10));
		cardsPicPanel.setPreferredSize(new Dimension(500, 10));
		tabbedCardsInfo.setMinimumSize(new Dimension(23, 200));
		scrollThumbnails.getVerticalScrollBar().setUnitIncrement(10);
		txtFilter.setColumns(25);
		txtSearch.setColumns(50);

		/////// VISIBILITY
		tableCards.setColumnControlVisible(true);
		panelFilters.setVisible(false);
		lblLoading.setVisible(false);
		cboCollections.setVisible(false);
		tableCards.setShowVerticalLines(false);
		cboEdition.setVisible(false);

		////// ADD PANELS
		for (String s : new String[] { "W", "U", "B", "R", "G", "C", "1" }) {
			final JButton btnG = new JButton();
			btnG.setToolTipText(s);
			if (s.equals("1"))
				btnG.setToolTipText("[0-9]*");

			btnG.setIcon(new ImageIcon(pan.getManaSymbol(s).getScaledInstance(15, 15, Image.SCALE_SMOOTH)));
			btnG.setForeground(btnG.getBackground());
			btnG.addActionListener(e -> {
				txtFilter.setText("\\{" + btnG.getToolTipText() + "}");
				sorterCards.setRowFilter(RowFilter.regexFilter(txtFilter.getText()));
			});
			panelmana.add(btnG);

		}
		scrollThumbnails.setViewportView(thumbnailPanel);

		panneauHaut.add(cboQuereableItems);
		panneauHaut.add(cboCollections);
		panneauHaut.add(txtSearch);
		panneauHaut.add(cboEdition);
		panneauHaut.add(btnFilter);
		panneauHaut.add(btnExport);
		panneauHaut.add(lblLoading);
		panneauCard.add(new JScrollPane(listEdition), BorderLayout.SOUTH);
		panneauCard.add(cardsPicPanel, BorderLayout.CENTER);

		panelResultsCards.add(panelFilters, BorderLayout.NORTH);
		panelResultsCards.add(new JScrollPane(tableCards));
		magicEditionDetailPanel = new MagicEditionDetailPanel();

		editionDetailPanel.add(magicEditionDetailPanel, BorderLayout.CENTER);

		panelFilters.add(lblFilter);
		panelFilters.add(txtFilter);
		panelFilters.add(btnClear);
		panelFilters.add(panelmana);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("DETAILS"), MTGConstants.ICON_TAB_DETAILS,
				detailCardPanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("EDITION"), MTGConstants.ICON_BACK,
				editionDetailPanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("PRICES"), MTGConstants.ICON_TAB_PRICES,
				priceTablePanel, null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("RULES"), MTGConstants.ICON_TAB_RULES,
				new JScrollPane(txtRulesArea), null);
		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("PRICE_VARIATIONS"), MTGConstants.ICON_TAB_VARIATIONS,
				historyChartPanel, null);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("MORE_LIKE_THIS"), MTGConstants.ICON_TAB_SIMILARITY,similarityPanel, null);

		tabbedCardsInfo.addTab(MTGControler.getInstance().getLangService().getCapitalize("DECK_MODULE"), MTGConstants.ICON_TAB_DECK,deckPanel, null);

		if (MTGControler.getInstance().get("debug-json-panel").equalsIgnoreCase("true"))
			tabbedCardsInfo.addTab("Object", MTGConstants.ICON_TAB_JSON, panelJson, null);

		panneauStat.add(cmcChart);
		panneauStat.add(manaRepartitionPanel);
		panneauStat.add(typeRepartitionPanel);
		panneauStat.add(rarityRepartitionPanel);

		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("RESULTS"),  MTGConstants.ICON_TAB_RESULTS,panelResultsCards, null);
		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("THUMBNAIL"), MTGConstants.ICON_TAB_THUMBNAIL,scrollThumbnails, null);
		tabbedCardsView.addTab(MTGControler.getInstance().getLangService().getCapitalize("STATS"), MTGConstants.ICON_TAB_ANALYSE, panneauStat,null);

		add(panneauHaut, BorderLayout.NORTH);
		add(panneauCard, BorderLayout.EAST);
		add(panneauCentral, BorderLayout.CENTER);

		/////// Right click
		try {
			initPopupCollection();
		} catch (Exception e2) {
			logger.error(e2);
		}

		/////// Action listners
		addComponentListener(new ComponentAdapter() {
			@Override
		    public void componentShown(ComponentEvent componentEvent){
		        txtSearch.requestFocus();
				panneauCentral.setDividerLocation(.45);

				removeComponentListener(this);
		    }
		});

		similarityPanel.getTableSimilarity().addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent evt) {

				if(similarityPanel.getTableSimilarity().getSelectedRow()==-1)
					return;

				MagicCard mc = (MagicCard) similarityPanel.getTableSimilarity().getValueAt(similarityPanel.getTableSimilarity().getSelectedRow(), 0);
				cardsPicPanel.showPhoto(mc);
			}
		});

		cboEdition.addActionListener(ae -> {
				txtSearch.setText(((MagicEdition) cboEdition.getSelectedItem()).getId());
				txtSearch.postActionEvent();
				});

		cboCollections.addActionListener(ae -> {
			txtSearch.setText(((MagicCollection) cboCollections.getSelectedItem()).getName());
			txtSearch.postActionEvent();
		});

		btnClear.addActionListener(ae -> {
			txtFilter.setText("");
			sorterCards.setRowFilter(null);
		});

		btnFilter.addActionListener(ae -> panelFilters.setVisible(!panelFilters.isVisible()));

		cboQuereableItems.addActionListener(e -> {
			if (cboQuereableItems.getSelectedItem().toString().equalsIgnoreCase("set")) {
				txtSearch.setVisible(false);
				cboEdition.setVisible(true);
				cboCollections.setVisible(false);
			} else if (cboQuereableItems.getSelectedItem().toString().equalsIgnoreCase("collections")) {
				txtSearch.setVisible(false);
				cboEdition.setVisible(false);
				cboCollections.setVisible(true);
			} else {
				txtSearch.setVisible(true);
				cboEdition.setVisible(false);
				cboCollections.setVisible(false);
			}
		});

		txtSearch.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				txtSearch.setText("");
			}
		});

		txtSearch.addActionListener(ae -> {

			selectedEdition = null;
			if (txtSearch.getText().equals("") && !cboCollections.isVisible())
				return;

			lblLoading.start();
			lblLoading.setText(MTGControler.getInstance().getLangService().getCapitalize("SEARCHING"));

			MTGPlugin plug = (cboCollections.isVisible()) ? MTGControler.getInstance().getEnabled(MTGDao.class):MTGControler.getInstance().getEnabled(MTGCardsProvider.class);
			String searchName = txtSearch.getText().trim();
			cardsModeltable.clear();

			AbstractObservableWorker<List<MagicCard>, MagicCard, MTGPlugin> wk = new AbstractObservableWorker<List<MagicCard>, MagicCard, MTGPlugin>(lblLoading,plug) {
				@Override
				protected List<MagicCard> doInBackground() throws Exception {
					List<MagicCard> cards;

					if (cboCollections.isVisible()) {
						cards=((MTGDao)plug).listCardsFromCollection((MagicCollection) cboCollections.getSelectedItem());
					}
					else if(cboEdition.isVisible()) {
						cards=((MTGCardsProvider)plug).searchCardByEdition((MagicEdition)cboEdition.getSelectedItem());
					}
					else {
						cards=((MTGCardsProvider)plug).searchCardByCriteria(cboQuereableItems.getSelectedItem().toString(), searchName, null, false);
					}

					try {
						Collections.sort(cards, new CardsEditionSorter());
					}
					catch(IllegalArgumentException e)
					{
						logger.error("error sorting result "+e);
					}

					return cards;
				}

				@Override
				protected void process(List<MagicCard> chunks) {
					super.process(chunks);
					cardsModeltable.addItems(chunks);
				}

				@Override
				protected void done() {
					super.done();
					open(getResult());
					btnExport.setEnabled(tableCards.getRowCount() > 0);
				}
			};
			ThreadManager.getInstance().runInEdt(wk,"searching "+txtSearch.getText());

		});

		tableCards.getSelectionModel().addListSelectionListener(event -> {
			if (!event.getValueIsAdjusting()) {
				try {
					selectedCard = UITools.getTableSelection(tableCards, 0);
					selectedEdition = selectedCard.getCurrentSet();
					updateCards();
				} catch (Exception e) {
					logger.error(e);
				}
			}
		});

		tableCards.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent evt) {

				if(tableCards.getSelectedRow()==-1)
					return;

				if (SwingUtilities.isRightMouseButton(evt)) {
					Point point = evt.getPoint();
					popupMenu.show(tableCards, (int) point.getX(), (int) point.getY());
				} else {
					try {
						selectedCard = UITools.getTableSelection(tableCards, 0);
						selectedEdition = selectedCard.getCurrentSet();
						updateCards();
					} catch (Exception e) {
						logger.error(e);
					}

				}
			}
		});

		listEdition.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent mev) {
				selectedEdition = listEdition.getSelectedValue();

				SwingWorker<MagicCard, MagicCard> sw = new SwingWorker<MagicCard, MagicCard>()
						{

							@Override
							protected void process(List<MagicCard> chunks) {
								detailCardPanel.setMagicCard(chunks.get(0));
								magicEditionDetailPanel.setMagicEdition(selectedEdition);
							}

							@Override
							protected MagicCard doInBackground() throws Exception {
								try {
									MagicCard mc = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByName( selectedCard.getName(), selectedEdition, false).get(0);
									publish(mc);
									return mc;
								} catch (Exception e) {
									logger.error(e);
									return null;
								}

							}
							@Override
							protected void done() {
								try {
									selectedCard = get();
									cardsPicPanel.showPhoto(selectedCard); // backcard
									historyChartPanel.init(selectedCard, selectedEdition, selectedCard.getName());
									priceTablePanel.init(selectedCard,selectedEdition);
								} catch (Exception e) {
									logger.error(e);
								}
							}

						};

				ThreadManager.getInstance().runInEdt(sw,"loading " + selectedCard);
			}
		});

		detailCardPanel.addObserver((Observable o, Object obj)->{
			MagicCardNames selLang = (MagicCardNames)obj;
			try {
					MagicEdition ed = (MagicEdition) BeanUtils.cloneBean(selectedEdition);
								 ed.setMultiverseid(String.valueOf(selLang.getGathererId()));

					logger.trace("change lang to " + selLang + " for " + ed);
					cardsPicPanel.showPhoto(selectedCard, ed);
			} catch (Exception e1) {
				logger.error(e1);
			}

		});

		btnExport.addActionListener(ae -> {
			JPopupMenu menu = new JPopupMenu();

			for (MTGCardsExport exp : MTGControler.getInstance().listEnabled(MTGCardsExport.class)) {
				if (exp.getMods() == MODS.BOTH || exp.getMods() == MODS.EXPORT) {
					JMenuItem it = new JMenuItem(exp.getName(), exp.getIcon());
					it.addActionListener(exportEvent -> {
						int result = JFileChooser.CANCEL_OPTION;
						File f = null;
						if(exp.needFile())
						{
							JFileChooser jf = new JFileChooser(".");
							jf.setSelectedFile(new File("search" + exp.getFileExtension()));
							result = jf.showSaveDialog(null);
							f = jf.getSelectedFile();
						}
						else
						{
							result = JFileChooser.APPROVE_OPTION;
						}

						if (result == JFileChooser.APPROVE_OPTION)
						{
							List<MagicCard> export = UITools.getTableSelections(tableCards,0);

							if(export.isEmpty())
								export =  ((MagicCardTableModel) tableCards.getRowSorter().getModel()).getItems();

							lblLoading.start(export.size());
							ThreadManager.getInstance().runInEdt(new CardExportWorker(exp, export, lblLoading, f), "export search " + exp);
						}
					});

					menu.add(it);
				}

			}

			Component b = (Component) ae.getSource();
			Point p = b.getLocationOnScreen();
			menu.show(b, 0, 0);
			menu.setLocation(p.x, p.y + b.getHeight());
		});

		txtFilter.addActionListener(ae -> {
			String text = txtFilter.getText();
			if (text.length() == 0) {
				sorterCards.setRowFilter(null);
			} else {
				sorterCards.setRowFilter(RowFilter.regexFilter(text));
			}
		});

		thumbnailPanel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				DisplayableCard lab = (DisplayableCard) thumbnailPanel.getComponentAt(new Point(e.getX(), e.getY()));
				selectedCard = lab.getMagicCard();
				selectedEdition = lab.getMagicCard().getCurrentSet();
				cardsPicPanel.showPhoto(selectedCard);
				updateCards();
			}

		});

	}

Replace Generic With Diamond AbstractObservableWorker<List<MagicCard>,MagicCard,MTGPlugin> with AbstractObservableWorker<> in method public initGUI() : void from class org.magic.gui.components.CardSearchPanel


			@Override
			public void mouseClicked(MouseEvent mev) {
				selectedEdition = listEdition.getSelectedValue();

				SwingWorker<MagicCard, MagicCard> sw = new SwingWorker<>()
						{

							@Override
							protected void process(List<MagicCard> chunks) {
								detailCardPanel.setMagicCard(chunks.get(0));
								magicEditionDetailPanel.setMagicEdition(selectedEdition);
							}

							@Override
							protected MagicCard doInBackground() throws Exception {
								try {
									MagicCard mc = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByName( selectedCard.getName(), selectedEdition, false).get(0);
									publish(mc);
									return mc;
								} catch (Exception e) {
									logger.error(e);
									return null;
								}

							}
							@Override
							protected void done() {
								try {
									selectedCard = get();
									cardsPicPanel.showPhoto(selectedCard); // backcard
									historyChartPanel.init(selectedCard, selectedEdition, selectedCard.getName());
									priceTablePanel.init(selectedCard,selectedEdition);
								} catch (Exception e) {
									logger.error(e);
								}
							}

						};

				ThreadManager.getInstance().runInEdt(sw,"loading " + selectedCard);
			}

			@Override
			public void mouseClicked(MouseEvent mev) {
				selectedEdition = listEdition.getSelectedValue();

				SwingWorker<MagicCard, MagicCard> sw = new SwingWorker<MagicCard, MagicCard>()
						{

							@Override
							protected void process(List<MagicCard> chunks) {
								detailCardPanel.setMagicCard(chunks.get(0));
								magicEditionDetailPanel.setMagicEdition(selectedEdition);
							}

							@Override
							protected MagicCard doInBackground() throws Exception {
								try {
									MagicCard mc = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByName( selectedCard.getName(), selectedEdition, false).get(0);
									publish(mc);
									return mc;
								} catch (Exception e) {
									logger.error(e);
									return null;
								}

							}
							@Override
							protected void done() {
								try {
									selectedCard = get();
									cardsPicPanel.showPhoto(selectedCard); // backcard
									historyChartPanel.init(selectedCard, selectedEdition, selectedCard.getName());
									priceTablePanel.init(selectedCard,selectedEdition);
								} catch (Exception e) {
									logger.error(e);
								}
							}

						};

				ThreadManager.getInstance().runInEdt(sw,"loading " + selectedCard);
			}

Replace Generic With Diamond SwingWorker<MagicCard,MagicCard> with SwingWorker<> in method public mouseClicked(mev MouseEvent) : void from class org.magic.gui.components.CardSearchPanel.initGUI.addMouseListener.new MouseAdapter


	public CardsEditionTablePanel() {
		setLayout(new BorderLayout(0, 0));

		JPanel panneauHaut = new JPanel();
		model = new MagicCardTableModel();

		table = new JXTable(model);
		buzy=AbstractBuzyIndicatorComponent.createProgressComponent();

		table.getColumnModel().getColumn(2).setCellRenderer(new ManaCellRenderer());
		table.getColumnModel().getColumn(6).setCellRenderer(new MagicEditionsJLabelRenderer());
		table.setColumnControlVisible(true);
		table.getColumnExt(model.getColumnName(1)).setVisible(false);
		table.getColumnExt(model.getColumnName(6)).setVisible(false);
		table.getColumnExt(model.getColumnName(8)).setVisible(false);
		table.getColumnExt(model.getColumnName(9)).setVisible(false);
		UITools.initTableFilter(table);

		panneauHaut.add(buzy);
		add(new JScrollPane(table), BorderLayout.CENTER);
		add(panneauHaut,BorderLayout.NORTH);

		JPanel panneauBas = new JPanel();
		add(panneauBas, BorderLayout.SOUTH);

		cboCollection =  UITools.createComboboxCollection();
		panneauBas.add(cboCollection);

		btnImport = new JButton(MTGConstants.ICON_MASS_IMPORT_SMALL);
		btnImport.setEnabled(false);
		panneauBas.add(btnImport);

		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentShown(ComponentEvent componentEvent) {
				init(currentEdition);
			}

		});

		btnImport.addActionListener(ae->{
			List<MagicCard> list = getSelectedCards();

			int res = JOptionPane.showConfirmDialog(null,MTGControler.getInstance().getLangService().getCapitalize("COLLECTION_IMPORT") + " :" + list.size() + " cards in " + cboCollection.getSelectedItem());
			if(res==JOptionPane.YES_OPTION)
			{
				buzy.start(list.size());

				SwingWorker<Void, MagicCard> swImp = new SwingWorker<>()
				{
				@Override
					protected void done() {
						buzy.end();
					}

					@Override
					protected void process(List<MagicCard> chunks) {
						buzy.progressSmooth(chunks.size());
					}

					@Override
					protected Void doInBackground() throws Exception {
						for(MagicCard mc : list)
							try {
								MTGControler.getInstance().saveCard(mc, (MagicCollection)cboCollection.getSelectedItem(),null);
								publish(mc);
							} catch (SQLException e) {
								logger.error("couln't save " + mc,e);
							}
						return null;
						}

						};

				ThreadManager.getInstance().runInEdt(swImp, "import cards in "+cboCollection.getSelectedItem());
			}
		});
	}

	public CardsEditionTablePanel() {
		setLayout(new BorderLayout(0, 0));

		JPanel panneauHaut = new JPanel();
		model = new MagicCardTableModel();

		table = new JXTable(model);
		buzy=AbstractBuzyIndicatorComponent.createProgressComponent();

		table.getColumnModel().getColumn(2).setCellRenderer(new ManaCellRenderer());
		table.getColumnModel().getColumn(6).setCellRenderer(new MagicEditionsJLabelRenderer());
		table.setColumnControlVisible(true);
		table.getColumnExt(model.getColumnName(1)).setVisible(false);
		table.getColumnExt(model.getColumnName(6)).setVisible(false);
		table.getColumnExt(model.getColumnName(8)).setVisible(false);
		table.getColumnExt(model.getColumnName(9)).setVisible(false);
		UITools.initTableFilter(table);

		panneauHaut.add(buzy);
		add(new JScrollPane(table), BorderLayout.CENTER);
		add(panneauHaut,BorderLayout.NORTH);

		JPanel panneauBas = new JPanel();
		add(panneauBas, BorderLayout.SOUTH);

		cboCollection =  UITools.createComboboxCollection();
		panneauBas.add(cboCollection);

		btnImport = new JButton(MTGConstants.ICON_MASS_IMPORT_SMALL);
		btnImport.setEnabled(false);
		panneauBas.add(btnImport);

		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentShown(ComponentEvent componentEvent) {
				init(currentEdition);
			}

		});

		btnImport.addActionListener(ae->{
			List<MagicCard> list = getSelectedCards();

			int res = JOptionPane.showConfirmDialog(null,MTGControler.getInstance().getLangService().getCapitalize("COLLECTION_IMPORT") + " :" + list.size() + " cards in " + cboCollection.getSelectedItem());
			if(res==JOptionPane.YES_OPTION)
			{
				buzy.start(list.size());

				SwingWorker<Void, MagicCard> swImp = new SwingWorker<Void, MagicCard>()
				{
				@Override
					protected void done() {
						buzy.end();
					}

					@Override
					protected void process(List<MagicCard> chunks) {
						buzy.progressSmooth(chunks.size());
					}

					@Override
					protected Void doInBackground() throws Exception {
						for(MagicCard mc : list)
							try {
								MTGControler.getInstance().saveCard(mc, (MagicCollection)cboCollection.getSelectedItem(),null);
								publish(mc);
							} catch (SQLException e) {
								logger.error("couln't save " + mc,e);
							}
						return null;
						}

						};

				ThreadManager.getInstance().runInEdt(swImp, "import cards in "+cboCollection.getSelectedItem());
			}
		});
	}

Replace Generic With Diamond SwingWorker<Void,MagicCard> with SwingWorker<> in method public CardsEditionTablePanel() from class org.magic.gui.components.CardsEditionTablePanel


	private void refresh()
	{
		if(currentEdition==null)
			return;

		btnImport.setEnabled(false);

		if(sw!=null && !sw.isDone())
		{
			sw.cancel(true);
		}

		sw = new AbstractObservableWorker<>(buzy,MTGControler.getInstance().getEnabled(MTGCardsProvider.class),currentEdition.getCardCount()) {

			@Override
			protected List<MagicCard> doInBackground() {
				List<MagicCard> cards = new ArrayList<>();
				try {
					cards = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByEdition(currentEdition);
					Collections.sort(cards, new CardsEditionSorter() );
					return cards;
				} catch (IOException e) {
					logger.error(e);
					return cards;
				}

			}

			@Override
			protected void process(List<MagicCard> chunks) {
				super.process(chunks);
				model.addItems(chunks);
			}

			@Override
			protected void done() {
				super.done();
				try {
					model.init(get());
				} catch (Exception e) {
					logger.error(e);
				}
			}

		};

		ThreadManager.getInstance().runInEdt(sw, "loading edition "+currentEdition);
	}

	private void refresh()
	{
		if(currentEdition==null)
			return;

		btnImport.setEnabled(false);

		if(sw!=null && !sw.isDone())
		{
			sw.cancel(true);
		}

		sw = new AbstractObservableWorker<List<MagicCard>, MagicCard,MTGCardsProvider>(buzy,MTGControler.getInstance().getEnabled(MTGCardsProvider.class),currentEdition.getCardCount()) {

			@Override
			protected List<MagicCard> doInBackground() {
				List<MagicCard> cards = new ArrayList<>();
				try {
					cards = MTGControler.getInstance().getEnabled(MTGCardsProvider.class).searchCardByEdition(currentEdition);
					Collections.sort(cards, new CardsEditionSorter() );
					return cards;
				} catch (IOException e) {
					logger.error(e);
					return cards;
				}

			}

			@Override
			protected void process(List<MagicCard> chunks) {
				super.process(chunks);
				model.addItems(chunks);
			}

			@Override
			protected void done() {
				super.done();
				try {
					model.init(get());
				} catch (Exception e) {
					logger.error(e);
				}
			}

		};

		ThreadManager.getInstance().runInEdt(sw, "loading edition "+currentEdition);
	}

Replace Generic With Diamond AbstractObservableWorker<List<MagicCard>,MagicCard,MTGCardsProvider> with AbstractObservableWorker<> in method private refresh() : void from class org.magic.gui.components.CardsEditionTablePanel