/* GanttProject is an opensource project management tool. License: GPL3 Copyright (C) 2005-2011 GanttProject Team This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.sourceforge.ganttproject.document; import biz.ganttproject.core.calendar.GPCalendarCalc; import biz.ganttproject.core.option.ListOption; import biz.ganttproject.core.table.ColumnList; import com.google.common.collect.ImmutableSet; import net.sourceforge.ganttproject.IGanttProject; import net.sourceforge.ganttproject.gui.GPColorChooser; import net.sourceforge.ganttproject.gui.UIFacade; import net.sourceforge.ganttproject.io.GPSaver; import net.sourceforge.ganttproject.language.GanttLanguage; import net.sourceforge.ganttproject.parser.AbstractTagHandler; import net.sourceforge.ganttproject.parser.AllocationTagHandler; import net.sourceforge.ganttproject.parser.CustomPropertiesTagHandler; import net.sourceforge.ganttproject.parser.DefaultWeekTagHandler; import net.sourceforge.ganttproject.parser.DependencyTagHandler; import net.sourceforge.ganttproject.parser.FileFormatException; import net.sourceforge.ganttproject.parser.GPParser; import net.sourceforge.ganttproject.parser.HolidayTagHandler; import net.sourceforge.ganttproject.parser.OptionTagHandler; import net.sourceforge.ganttproject.parser.ParserFactory; import net.sourceforge.ganttproject.parser.ParsingListener; import net.sourceforge.ganttproject.parser.PreviousStateTasksTagHandler; import net.sourceforge.ganttproject.parser.ResourceTagHandler; import net.sourceforge.ganttproject.parser.RoleTagHandler; import net.sourceforge.ganttproject.parser.TaskDisplayColumnsTagHandler; import net.sourceforge.ganttproject.parser.TaskPropertiesTagHandler; import net.sourceforge.ganttproject.parser.TaskTagHandler; import net.sourceforge.ganttproject.parser.VacationTagHandler; import net.sourceforge.ganttproject.parser.ViewTagHandler; import net.sourceforge.ganttproject.resource.HumanResourceManager; import net.sourceforge.ganttproject.roles.RoleManager; import net.sourceforge.ganttproject.task.TaskManager; import net.sourceforge.ganttproject.task.TaskManagerImpl; import org.eclipse.core.runtime.IStatus; import org.xml.sax.Attributes; import java.awt.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.util.Set; /** * @author bard */ class ProxyDocument implements Document { private final Document myPhysicalDocument; private IGanttProject myProject; private UIFacade myUIFacade; private final ParserFactory myParserFactory; private final DocumentCreator myCreator; private PortfolioImpl myPortfolio; private final ColumnList myTaskVisibleFields; private final ColumnList myResourceVisibleFields; ProxyDocument(DocumentCreator creator, Document physicalDocument, IGanttProject project, UIFacade uiFacade, ColumnList taskVisibleFields, ColumnList resourceVisibleFields, ParserFactory parserFactory) { myPhysicalDocument = physicalDocument; myProject = project; myUIFacade = uiFacade; myParserFactory = parserFactory; myCreator = creator; myTaskVisibleFields = taskVisibleFields; myResourceVisibleFields = resourceVisibleFields; } @Override public String getFileName() { return myPhysicalDocument.getFileName(); } @Override public boolean canRead() { return myPhysicalDocument.canRead(); } @Override public IStatus canWrite() { return myPhysicalDocument.canWrite(); } @Override public boolean isValidForMRU() { return myPhysicalDocument.isValidForMRU(); } @Override public boolean acquireLock() { return myPhysicalDocument.acquireLock(); } @Override public void releaseLock() { myPhysicalDocument.releaseLock(); } @Override public InputStream getInputStream() throws IOException { return myPhysicalDocument.getInputStream(); } @Override public OutputStream getOutputStream() throws IOException { return myPhysicalDocument.getOutputStream(); } @Override public String getPath() { return myPhysicalDocument.getPath(); } @Override public String getFilePath() { String result = myPhysicalDocument.getFilePath(); if (result == null) { try { result = myCreator.createTemporaryFile(); } catch (IOException e) { myUIFacade.showErrorDialog(e); } } return result; } @Override public String getUsername() { return myPhysicalDocument.getUsername(); } @Override public String getPassword() { return myPhysicalDocument.getPassword(); } @Override public String getLastError() { return myPhysicalDocument.getLastError(); } @Override public void read() throws IOException, DocumentException { FailureState failure = new FailureState(); SuccessState success = new SuccessState(); ParsingState parsing = new ParsingState(success, failure); // OpenCopyConfirmationState confirmation = new OpenCopyConfirmationState( // parsing, failure); // AcquireLockState lock = new AcquireLockState(parsing, confirmation); try { getTaskManager().setEventsEnabled(false); parsing.enter(); } finally { getTaskManager().setEventsEnabled(true); } // lock.enter(); } @Override public void write() throws IOException { GPSaver saver = myParserFactory.newSaver(); byte[] buffer; try { ByteArrayOutputStream bufferStream = new ByteArrayOutputStream(); saver.save(bufferStream); bufferStream.flush(); buffer = bufferStream.toByteArray(); } catch (IOException e) { getUIFacade().showErrorDialog(e); return; } OutputStream output = getOutputStream(); try { output.write(buffer); output.flush(); } finally { output.close(); } } private TaskManagerImpl getTaskManager() { return (TaskManagerImpl) myProject.getTaskManager(); } private RoleManager getRoleManager() { return myProject.getRoleManager(); } private HumanResourceManager getHumanResourceManager() { return myProject.getHumanResourceManager(); } private GPCalendarCalc getActiveCalendar() { return myProject.getActiveCalendar(); } private UIFacade getUIFacade() { return myUIFacade; } // class AcquireLockState { // OpenCopyConfirmationState myConfirmationState; // // ParsingState myParsingState; // // public AcquireLockState(ParsingState parsing, // OpenCopyConfirmationState confirmation) { // myParsingState = parsing; // myConfirmationState = confirmation; // } // // void enter() throws IOException, DocumentException { // boolean locked = acquireLock(); // if (!locked) { // myConfirmationState.enter(); // } else { // myParsingState.enter(); // } // } // } // // class OpenCopyConfirmationState { // private final ParsingState myParsingState; // // private final FailureState myExitState; // // public OpenCopyConfirmationState(ParsingState parsing, // FailureState failure) { // myParsingState = parsing; // myExitState = failure; // } // // void enter() throws IOException, DocumentException { // String message = GanttLanguage.getInstance().getText("msg13"); // String title = GanttLanguage.getInstance().getText("warning"); // if (UIFacade.Choice.YES==getUIFacade().showConfirmationDialog(message, // title)) { // myParsingState.enter(); // } else { // myExitState.enter(); // } // } // } class ParsingState { private final FailureState myFailureState; private final SuccessState mySuccessState; public ParsingState(SuccessState success, FailureState failure) { mySuccessState = success; myFailureState = failure; } void enter() throws IOException, DocumentException { GPParser opener = myParserFactory.newParser(); HumanResourceManager hrManager = getHumanResourceManager(); RoleManager roleManager = getRoleManager(); TaskManager taskManager = getTaskManager(); ResourceTagHandler resourceHandler = new ResourceTagHandler(hrManager, roleManager, myProject.getResourceCustomPropertyManager()); DependencyTagHandler dependencyHandler = new DependencyTagHandler(opener.getContext(), taskManager, getUIFacade()); AllocationTagHandler allocationHandler = new AllocationTagHandler(hrManager, getTaskManager(), getRoleManager()); VacationTagHandler vacationHandler = new VacationTagHandler(hrManager); PreviousStateTasksTagHandler previousStateHandler = new PreviousStateTasksTagHandler(myProject.getBaselines()); RoleTagHandler rolesHandler = new RoleTagHandler(roleManager); TaskTagHandler taskHandler = new TaskTagHandler(taskManager, opener.getContext(), myUIFacade.getTaskTree()); DefaultWeekTagHandler weekHandler = new DefaultWeekTagHandler(getActiveCalendar()); OnlyShowWeekendsTagHandler onlyShowWeekendsHandler = new OnlyShowWeekendsTagHandler(getActiveCalendar()); TaskPropertiesTagHandler taskPropHandler = new TaskPropertiesTagHandler(myProject.getTaskCustomColumnManager()); opener.addTagHandler(taskPropHandler); CustomPropertiesTagHandler customPropHandler = new CustomPropertiesTagHandler(opener.getContext(), getTaskManager()); opener.addTagHandler(customPropHandler); TaskDisplayColumnsTagHandler pilsenTaskDisplayHandler = TaskDisplayColumnsTagHandler.createPilsenHandler(); TaskDisplayColumnsTagHandler legacyTaskDisplayHandler = TaskDisplayColumnsTagHandler.createLegacyHandler(); opener.addTagHandler(pilsenTaskDisplayHandler); opener.addTagHandler(legacyTaskDisplayHandler); opener.addParsingListener(TaskDisplayColumnsTagHandler.createTaskDisplayColumnsWrapper(myTaskVisibleFields, pilsenTaskDisplayHandler, legacyTaskDisplayHandler)); opener.addTagHandler(new ViewTagHandler("gantt-chart", getUIFacade(), pilsenTaskDisplayHandler)); TaskDisplayColumnsTagHandler resourceFieldsHandler = new TaskDisplayColumnsTagHandler( "field", "id", "order", "width", "visible"); opener.addTagHandler(resourceFieldsHandler); opener.addParsingListener(TaskDisplayColumnsTagHandler.createTaskDisplayColumnsWrapper(myResourceVisibleFields, resourceFieldsHandler)); opener.addTagHandler(new ViewTagHandler("resource-table", getUIFacade(), resourceFieldsHandler)); opener.addTagHandler(taskHandler); opener.addParsingListener(taskHandler); opener.addParsingListener(customPropHandler); opener.addTagHandler(opener.getDefaultTagHandler()); opener.addTagHandler(opener.getTimelineTagHandler()); opener.addParsingListener((ParsingListener)opener.getTimelineTagHandler()); opener.addTagHandler(resourceHandler); opener.addTagHandler(dependencyHandler); opener.addTagHandler(allocationHandler); opener.addParsingListener(allocationHandler); opener.addTagHandler(vacationHandler); opener.addTagHandler(previousStateHandler); opener.addTagHandler(rolesHandler); opener.addTagHandler(weekHandler); opener.addTagHandler(onlyShowWeekendsHandler); opener.addTagHandler(new OptionTagHandler<ListOption<Color>>(GPColorChooser.getRecentColorsOption())); opener.addParsingListener(dependencyHandler); opener.addParsingListener(resourceHandler); HolidayTagHandler holidayHandler = new HolidayTagHandler(myProject.getActiveCalendar()); opener.addTagHandler(new AbstractTagHandler("calendars") { @Override protected boolean onStartElement(Attributes attrs) { myProject.getActiveCalendar().setBaseCalendarID(attrs.getValue("base-id")); return true; } }); opener.addTagHandler(holidayHandler); PortfolioTagHandler portfolioHandler = new PortfolioTagHandler(); opener.addTagHandler(portfolioHandler); InputStream is; try { is = getInputStream(); } catch (IOException e) { myFailureState.enter(); throw new DocumentException(GanttLanguage.getInstance().getText("msg8") + ": " + e.getLocalizedMessage(), e); } if (opener.load(is)) { mySuccessState.enter(); } else { myFailureState.enter(); } } } class SuccessState { void enter() { } } class FailureState { void enter() { } } @Override public URI getURI() { return myPhysicalDocument.getURI(); } @Override public boolean isLocal() { return myPhysicalDocument.isLocal(); } @Override public boolean equals(Object doc) { if (false == doc instanceof ProxyDocument) { return false; } return getPath().equals(((Document) doc).getPath()); } @Override public Portfolio getPortfolio() { return myPortfolio; } private PortfolioImpl getPortfolioImpl() { if (myPortfolio == null) { myPortfolio = new PortfolioImpl(); } return myPortfolio; } private class PortfolioImpl implements Portfolio { private Document myDefaultDocument; @Override public Document getDefaultDocument() { return myDefaultDocument; } void setDefaultDocument(Document document) { if (myDefaultDocument != null) { throw new IllegalStateException("Don't set default document twice"); } myDefaultDocument = document; } } private class PortfolioTagHandler extends AbstractTagHandler { private static final String PORTFOLIO_TAG = "portfolio"; private static final String PROJECT_TAG = "project"; private final Set<String> TAGS = ImmutableSet.of(PORTFOLIO_TAG, PROJECT_TAG); private static final String LOCATION_ATTR = "location"; private boolean isReadingPortfolio = false; public PortfolioTagHandler() { super(null, false); } @Override public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) throws FileFormatException { if (!TAGS.contains(qName)) { return; } setTagStarted(true); if (PORTFOLIO_TAG.equals(qName)) { isReadingPortfolio = true; return; } if (PROJECT_TAG.equals(qName) && isReadingPortfolio) { String locationAsString = attrs.getValue(LOCATION_ATTR); if (locationAsString != null) { Document document = myCreator.getDocument(locationAsString); getPortfolioImpl().setDefaultDocument(document); } } } @Override public void endElement(String namespaceURI, String sName, String qName) { if (!TAGS.contains(qName)) { return; } if (PORTFOLIO_TAG.equals(qName)) { isReadingPortfolio = false; } setTagStarted(false); } } private static class OnlyShowWeekendsTagHandler extends AbstractTagHandler { private final GPCalendarCalc calendar; public OnlyShowWeekendsTagHandler(GPCalendarCalc calendar) { super("only-show-weekends"); this.calendar = calendar; } @Override protected boolean onStartElement(Attributes attrs) { calendar.setOnlyShowWeekends(Boolean.parseBoolean(attrs.getValue("value"))); return true; } } }