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

fr.vergne.translation.editor.MapContentPanel Maven / Gradle / Ivy

There is a newer version: 2.0
Show newest version
package fr.vergne.translation.editor;

import java.awt.CardLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.CancellationException;
import java.util.logging.Logger;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EtchedBorder;

import fr.vergne.collection.MultiMap;
import fr.vergne.collection.impl.HashMultiMap;
import fr.vergne.translation.TranslationEntry;
import fr.vergne.translation.TranslationEntry.TranslationListener;
import fr.vergne.translation.TranslationMap;
import fr.vergne.translation.TranslationMetadata;
import fr.vergne.translation.TranslationMetadata.Field;
import fr.vergne.translation.TranslationMetadata.FieldListener;
import fr.vergne.translation.editor.content.EntryComponentFactory.EntryComponent;
import fr.vergne.translation.editor.content.MapComponentFactory;
import fr.vergne.translation.editor.content.MapComponentFactory.MapComponent;
import fr.vergne.translation.editor.tool.ToolProvider;
import fr.vergne.translation.impl.EmptyMap;

@SuppressWarnings("serial")
public class MapContentPanel extends JPanel {

	public static final Logger logger = Logger.getLogger(MapContentPanel.class
			.getName());
	private final JPanel mapContentArea;
	private final JPanel mapLoadingArea;
	private final JScrollPane mapContentScroll;
	private final JLabel mapTitleField;
	private final LoadingManager loading;
	private final JLabel loadingLabel;
	private final MapComponentFactory mapFactory;
	private MapComponent mapComponent;
	private TranslationMap currentMap = new EmptyMap<>();
	private MapID currentMapId;
	private Collection> modifiedEntries = new HashSet<>();
	private MultiMap, Field> modifiedFields = new HashMultiMap, Field>() {
		public boolean remove(TranslationEntry key, Field value) {
			boolean changed = super.remove(key, value);
			if (get(key).isEmpty()) {
				remove(key);
			} else {
				// remaining stuff to remember
			}
			return changed;
		};
	};
	private int lastFocusedEntryIndex;
	private final Collection> updateListeners = new HashSet>();
	private ToolProvider toolProvider;

	public MapContentPanel(ToolProvider toolProvider,
			MapComponentFactory mapFactory) {
		this.mapFactory = mapFactory;
		this.toolProvider = toolProvider;

		setBorder(new EtchedBorder());

		final CardLayout contentSwitcher = new CardLayout();
		setLayout(contentSwitcher);
		loading = new LoadingManager() {

			@Override
			public void start() {
				contentSwitcher.last(MapContentPanel.this);
			}

			@Override
			public void stop() {
				contentSwitcher.first(MapContentPanel.this);
			}
		};

		JPanel contentWrapper = new JPanel();
		contentWrapper.setLayout(new GridBagLayout());
		GridBagConstraints constraints = new GridBagConstraints();

		constraints.gridx = 0;
		constraints.gridy = 0;
		constraints.anchor = GridBagConstraints.CENTER;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		constraints.weightx = 1;
		mapTitleField = new JLabel(" ", JLabel.CENTER);
		contentWrapper.add(mapTitleField, constraints);

		constraints.gridy = 1;
		constraints.fill = GridBagConstraints.BOTH;
		constraints.weightx = 1;
		constraints.weighty = 1;
		mapContentArea = new JPanel();
		mapContentArea.setLayout(new GridLayout(1, 1));
		mapContentScroll = new JScrollPane(mapContentArea);
		mapContentScroll.getVerticalScrollBar().setUnitIncrement(15);
		contentWrapper.add(mapContentScroll, constraints);
		add(contentWrapper);

		mapLoadingArea = new JPanel();
		mapLoadingArea.setLayout(new GridBagLayout());
		constraints = new GridBagConstraints();
		constraints.anchor = GridBagConstraints.CENTER;
		loadingLabel = new JLabel("Loading...");
		mapLoadingArea.add(loadingLabel, constraints);
		add(mapLoadingArea);
	}

	public int getCurrentEntryIndex() {
		return lastFocusedEntryIndex;
	}

	public void goToEntry(final int entryIndex) {
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				final int index = Math.min(Math.max(entryIndex, 0),
						currentMap.size() - 1);
				if (index == 0) {
					mapContentScroll.getVerticalScrollBar().setValue(0);
				} else {
					Rectangle visible = mapContentArea.getVisibleRect();
					Component target = (Component) mapComponent
							.getEntryComponent(index);
					visible.y = 0;
					while (target != mapContentArea) {
						visible.y += target.getBounds().y;
						target = target.getParent();
					}
					mapContentArea.scrollRectToVisible(visible);
				}
				SwingUtilities.invokeLater(new Runnable() {

					@Override
					public void run() {
						mapComponent.getEntryComponent(index)
								.getTranslationComponent()
								.requestFocusInWindow();
					}
				});
			}
		});
	}

	public void setMap(final MapID mapId, final int entryIndex) {
		if (this.currentMapId != null && this.currentMapId.equals(mapId)) {
			goToEntry(entryIndex);
		} else {
			alignStoredAndCurrentValues();

			loadingLabel.setText("Loading map " + mapId + "...");
			loading.start();
			SwingUtilities.invokeLater(new Runnable() {

				@Override
				public void run() {
					synchronized (currentMap) {
						TranslationMap newMap = toolProvider.getProject()
								.getMap(mapId);
						for (final TranslationEntry entry : newMap) {
							entry.addTranslationListener(new TranslationListener() {

								@Override
								public void translationUpdated(
										String newTranslation) {
									if (entry.getStoredTranslation().equals(
											newTranslation)) {
										modifiedEntries.remove(entry);
									} else {
										modifiedEntries.add(entry);
									}
									notifyUpdateListeners();
								}

								@Override
								public void translationStored() {
									modifiedEntries.remove(entry);
									notifyUpdateListeners();
								}
							});
							final TranslationMetadata metadata = entry
									.getMetadata();
							metadata.addFieldListener(new FieldListener() {

								@Override
								public  void fieldUpdated(Field field,
										T newValue) {
									if (metadata.getStored(field).equals(
											newValue)) {
										modifiedFields.remove(entry, field);
									} else {
										modifiedFields.add(entry, field);
									}
									notifyUpdateListeners();
								}

								@Override
								public  void fieldStored(Field field) {
									modifiedFields.remove(entry, field);
									notifyUpdateListeners();
								}
							});
						}
						MapContentPanel.this.currentMap = newMap;
						MapContentPanel.this.currentMapId = mapId;

						String name = toolProvider.getProject().getMapName(
								mapId);
						mapTitleField.setText("
" + mapId + "
" + name + "
"); mapComponent = mapFactory.createMapComponent(newMap); for (int index = 0; index < newMap.size(); index++) { EntryComponent entryComponent = mapComponent .getEntryComponent(index); final int entryIndex = index; entryComponent.getTranslationComponent() .addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { // nothing to do } @Override public void focusGained(FocusEvent e) { lastFocusedEntryIndex = entryIndex; } }); } mapContentArea.removeAll(); mapContentArea.add((Component) mapComponent); goToEntry(entryIndex); } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { loading.stop(); } }); } }); } } public void alignStoredAndCurrentValues() throws CancellationException { if (isMapModified()) { int answer = JOptionPane.showOptionDialog(MapContentPanel.this, "The map has been modified. Would you like to save it?", "Save the Current Map?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] { "Yes", "No", "Cancel" }, "Cancel"); if (answer == JOptionPane.YES_OPTION) { save(); } else if (answer == JOptionPane.NO_OPTION) { reset(true); } else if (answer == JOptionPane.CANCEL_OPTION) { throw new CancellationException("Alignment cancelled"); } else { throw new IllegalStateException("Unmanaged answer: " + answer); } } else { // nothing modified, go ahead } } public TranslationMap getMap() { return currentMap; } public boolean isMapModified() { return !(modifiedEntries.isEmpty() && modifiedFields.isEmpty()); } public void save() { logger.info("Saving map " + currentMap + "..."); currentMap.saveAll(); deleteSavingInfo(); logger.info("Map saved."); } private void deleteSavingInfo() { modifiedEntries.clear(); modifiedFields.clear(); notifyUpdateListeners(); } private void notifyUpdateListeners() { boolean isModified = isMapModified(); for (MapUpdateListener listener : updateListeners) { listener.mapModified(currentMapId, isModified); } } public void reset() { reset(null); } public void reset(Boolean autoAnswer) { if (currentMap == null || !isMapModified() || (autoAnswer != null && autoAnswer == false) || (autoAnswer == null && JOptionPane .showConfirmDialog( this, "Are you sure you want to cancel *ALL* the modifications that you have not saved?", "Cancel Modifications", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION)) { return; } else { logger.info("Resetting map " + currentMap + "..."); currentMap.resetAll(); deleteSavingInfo(); logger.info("Map reset."); } } public void addUpdateListener(MapUpdateListener listener) { updateListeners.add(listener); } public void removeUpdateListener(MapUpdateListener listener) { updateListeners.remove(listener); } public static interface MapUpdateListener { void mapModified(MapID id, boolean isDifferentFromStore); } private static interface LoadingManager { public void start(); public void stop(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy