/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.cgmodule.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.GridLayout; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; import org.openflexo.FlexoCst; import org.openflexo.cgmodule.GeneratorCst; import org.openflexo.cgmodule.controller.GeneratorController; import org.openflexo.foundation.DataModification; import org.openflexo.foundation.FlexoEditor; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.FlexoObservable; import org.openflexo.foundation.FlexoObserver; import org.openflexo.foundation.ObjectDeleted; import org.openflexo.foundation.action.FlexoActionSource; import org.openflexo.foundation.cg.CGFile; import org.openflexo.foundation.cg.CGObject; import org.openflexo.foundation.cg.version.AbstractCGFileVersion; import org.openflexo.foundation.cg.version.CGFileReleaseVersion.BeforeFirstRelease; import org.openflexo.foundation.cg.version.action.RevertToHistoryVersion; import org.openflexo.foundation.cg.version.action.ShowDifferences; import org.openflexo.foundation.rm.cg.AbstractGeneratedFile; import org.openflexo.foundation.rm.cg.ContentSource; import org.openflexo.foundation.rm.cg.ContentSource.ContentSourceType; import org.openflexo.foundation.rm.cg.GenerationStatus; import org.openflexo.generator.ContentRegenerated; import org.openflexo.generator.exception.GenerationException; import org.openflexo.generator.rm.GenerationAvailableFileResource; import org.openflexo.icon.FilesIconLibrary; import org.openflexo.jedit.JEditTextArea.DisplayContext; import org.openflexo.localization.FlexoLocalization; import org.openflexo.logging.FlexoLogger; import org.openflexo.selection.SelectionListener; import org.openflexo.swing.VerticalLayout; import org.openflexo.view.ModuleView; import org.openflexo.view.controller.model.FlexoPerspective; import org.openflexo.view.listener.FlexoActionButton; /** * @author sylvain */ public class CGFileHistoryModuleView extends JPanel implements ModuleView<CGFile>, FlexoObserver, FlexoActionSource, SelectionListener { private final Logger logger = FlexoLogger.getLogger(CGFileHistoryModuleView.class.getPackage().getName()); private final CGFile _cgFile; private final GeneratorController _controller; private ContentSource _contentSource; private CGObject _displayedObject; public CGFileHistoryModuleView(CGFile cgFile, GeneratorController controller) { super(new BorderLayout()); _controller = controller; _cgFile = cgFile; _cgFile.addObserver(this); _contentSource = ContentSource.CONTENT_ON_DISK; _displayedObject = cgFile; controller.getSelectionManager().addToSelectionListeners(this); updateView(true); } public void refresh() { updateView(true); } private void updateView(boolean forceRebuild) { if (logger.isLoggable(Level.FINE)) { logger.fine("CGFileHistoryModuleView :" + _cgFile.getFileName() + " refresh view with " + _contentSource); } if (forceRebuild) { rebuildView(); revalidate(); repaint(); } else { if (_header != null) { _header.update(); } if (_codeDisplayer != null) { DisplayContext previousDisplayContext = _codeDisplayer.getDisplayContext(); if (logger.isLoggable(Level.FINE)) { logger.fine("Rebuild view, display context was: " + previousDisplayContext); } _codeDisplayer.setContentSource(_contentSource); _codeDisplayer.update(); _codeDisplayer.setDisplayContext(previousDisplayContext); } } } private CodeDisplayer _codeDisplayer; private FileHistoryBrowserView historyBrowserView; private ViewHeader _header; protected class ViewHeader extends JPanel { JLabel icon; JLabel title; JLabel subTitle; JPanel controlPanel; Vector<FlexoActionButton> actionButtons = new Vector<FlexoActionButton>(); protected ViewHeader() { super(new BorderLayout()); icon = new JLabel(FilesIconLibrary.mediumIconForFileFormat(_cgFile.getFileFormat())); icon.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); add(icon, BorderLayout.WEST); title = new JLabel(_cgFile.getFileName(), SwingConstants.LEFT); // title.setVerticalAlignment(JLabel.BOTTOM); title.setFont(GeneratorCst.HEADER_FONT); title.setForeground(Color.BLACK); title.setBorder(BorderFactory.createEmptyBorder(5, 10, 0, 10)); subTitle = new JLabel(subTitleForFile(), SwingConstants.LEFT); // title.setVerticalAlignment(JLabel.BOTTOM); subTitle.setFont(GeneratorCst.SUB_TITLE_FONT); subTitle.setForeground(Color.GRAY); subTitle.setBorder(BorderFactory.createEmptyBorder(0, 10, 5, 10)); JPanel labelsPanel = new JPanel(new GridLayout(2, 1)); labelsPanel.add(title); labelsPanel.add(subTitle); add(labelsPanel, BorderLayout.CENTER); controlPanel = new JPanel(new FlowLayout()); FlexoActionButton revertToVersionAction = new FlexoActionButton(RevertToHistoryVersion.actionType, "revert_to_version", CGFileHistoryModuleView.this, getController()); actionButtons.add(revertToVersionAction); controlPanel.add(revertToVersionAction); FlexoActionButton showDifferencesAction = new FlexoActionButton(ShowDifferences.actionType, "show_differences", CGFileHistoryModuleView.this, getController()); actionButtons.add(showDifferencesAction); controlPanel.add(showDifferencesAction); controlPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); add(controlPanel, BorderLayout.EAST); update(); } private String subTitleForFile() { String returned = _contentSource.getStringRepresentation(); if (_contentSource.getType() == ContentSourceType.HistoryVersion && _cgFile.getResource().getGeneratedResourceData() instanceof AbstractGeneratedFile) { AbstractCGFileVersion fileVersion = ((AbstractGeneratedFile) _cgFile.getResource().getGeneratedResourceData()).getHistory() .versionWithId(_contentSource.getVersion()); if (fileVersion != null) { returned += ", " + fileVersion.getDateAsString() + ", " + fileVersion.getUserIdentifier(); } } return returned; } protected void update() { title.setText(_cgFile.getFileName()); subTitle.setText(subTitleForFile()); for (FlexoActionButton button : actionButtons) { button.update(); } } } private void rebuildView() { DisplayContext previousDisplayContext = null; if (_codeDisplayer != null) { previousDisplayContext = _codeDisplayer.getDisplayContext(); if (logger.isLoggable(Level.FINE)) { logger.fine("Rebuild view, display context was: " + previousDisplayContext); } } removeAll(); _header = new ViewHeader(); add(_header, BorderLayout.NORTH); _codeDisplayer = null; if (_cgFile.getGenerationStatus() == GenerationStatus.CodeGenerationNotAvailable) { add(new JLabel(FlexoLocalization.localizedForKey("sorry_code_generator_not_available_in_this_version"), SwingConstants.CENTER), BorderLayout.CENTER); return; } else { if (_cgFile.hasVersionOnDisk()) { GenerationAvailableFileResource resource = (GenerationAvailableFileResource) _cgFile.getResource(); _codeDisplayer = new CodeDisplayer(resource, _contentSource, _controller); historyBrowserView = new FileHistoryBrowserView(getController(), _cgFile, 10); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, _codeDisplayer.getComponent(), historyBrowserView); add(splitPane, BorderLayout.CENTER); } else { JLabel l = new JLabel(); l.setText(FlexoLocalization.localizedForKey("no_history_yet", l)); l.setHorizontalAlignment(SwingConstants.CENTER); add(l, BorderLayout.CENTER); } } if (previousDisplayContext != null) { _codeDisplayer.setDisplayContext(previousDisplayContext); } } public GeneratorController getController() { return _controller; } @Override public void update(FlexoObservable observable, DataModification dataModification) { if (logger.isLoggable(Level.FINE)) { logger.fine("CGFileModuleView : RECEIVED " + dataModification + " for " + observable); } if (dataModification instanceof ObjectDeleted) { deleteModuleView(); } else if (dataModification instanceof ContentRegenerated) { updateView(true); } else { updateView(false); } } @Override public void deleteModuleView() { logger.info("CGFileModuleView view deleted"); getController().removeModuleView(this); _cgFile.deleteObserver(this); } @Override public FlexoPerspective getPerspective() { return _controller.CODE_GENERATOR_PERSPECTIVE; } @Override public CGFile getRepresentedObject() { return _cgFile; } @Override public void willHide() { // TODO Auto-generated method stub } @Override public void willShow() { // TODO Auto-generated method stub } protected class ExceptionPanel extends JPanel { protected ExceptionPanel(GenerationException exception) { super(new VerticalLayout()); // Top JLabel exceptionLabel = new JLabel(FlexoLocalization.localizedForKey("exception")); exceptionLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); JTextField exceptionTF = new JTextField(exception.getLocalizedMessage()); exceptionTF.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); JPanel topPanel = new JPanel(new BorderLayout()); topPanel.add(exceptionLabel, BorderLayout.WEST); topPanel.add(exceptionTF, BorderLayout.CENTER); add(topPanel); // Details JLabel detailsLabel = new JLabel(FlexoLocalization.localizedForKey("details"), SwingConstants.LEFT); detailsLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); JTextArea detailsTA = new JTextArea(exception.getDetails()); detailsTA.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); detailsTA.setFont(FlexoCst.MEDIUM_FONT); add(detailsLabel); add(detailsTA); // Stack trace JLabel stLabel = new JLabel(FlexoLocalization.localizedForKey("stacktrace"), SwingConstants.LEFT); stLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); String stackTrace = null; if (exception.getTargetException() != null) { StringWriter w = new StringWriter(); exception.getTargetException().printStackTrace(new PrintWriter(w)); stackTrace = w.toString(); } else { stackTrace = FlexoLocalization.localizedForKey("stack_trace_not_available"); } JTextArea stackTraceTA = new JTextArea(stackTrace); stackTraceTA.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); stackTraceTA.setFont(FlexoCst.CODE_FONT); stackTraceTA.setForeground(Color.DARK_GRAY); add(stLabel); add(stackTraceTA); // Cause stack trace if (exception.getTargetException() != null && exception.getTargetException().getCause() != null) { JLabel causeSTLabel = new JLabel(FlexoLocalization.localizedForKey("cause_stacktrace"), SwingConstants.LEFT); causeSTLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); String causeStackTrace = null; StringWriter w = new StringWriter(); exception.getTargetException().getCause().printStackTrace(new PrintWriter(w)); causeStackTrace = w.toString(); JTextArea causeStackTraceTA = new JTextArea(causeStackTrace); causeStackTraceTA.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); causeStackTraceTA.setFont(FlexoCst.CODE_FONT); causeStackTraceTA.setForeground(Color.DARK_GRAY); add(causeSTLabel); add(causeStackTraceTA); } validate(); } } /** * Returns flag indicating if this view is itself responsible for scroll management When not, Flexo will manage it's own scrollbar for * you * * @return */ @Override public boolean isAutoscrolled() { return true; } @Override public FlexoModelObject getFocusedObject() { return _displayedObject; } @Override public Vector getGlobalSelection() { return null; } @Override public void fireBeginMultipleSelection() { } @Override public void fireEndMultipleSelection() { } @Override public void fireObjectDeselected(FlexoModelObject object) { } @Override public void fireObjectSelected(FlexoModelObject object) { if (object == _cgFile) { _contentSource = ContentSource.CONTENT_ON_DISK; _displayedObject = _cgFile; updateView(false); } if (object instanceof AbstractCGFileVersion && !(object instanceof BeforeFirstRelease)) { if (((AbstractCGFileVersion) object).getCGFile() == _cgFile) { _contentSource = ContentSource.getContentSource(ContentSourceType.HistoryVersion, ((AbstractCGFileVersion) object).getVersionId()); _displayedObject = (AbstractCGFileVersion) object; updateView(false); } } } @Override public void fireResetSelection() { } @Override public FlexoEditor getEditor() { return _controller.getEditor(); } }