/*
GanttProject is an opensource project management tool.
Copyright (C) 2002-2011 Alexandre Thomas, Dmitry Barashev, 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;
import biz.ganttproject.core.calendar.GPCalendarCalc;
import biz.ganttproject.core.calendar.GPCalendarListener;
import biz.ganttproject.core.calendar.WeekendCalendarImpl;
import biz.ganttproject.core.option.ChangeValueEvent;
import biz.ganttproject.core.option.ChangeValueListener;
import biz.ganttproject.core.option.GPOptionGroup;
import biz.ganttproject.core.time.TimeUnitStack;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import net.sourceforge.ganttproject.action.*;
import net.sourceforge.ganttproject.action.edit.EditMenu;
import net.sourceforge.ganttproject.action.help.HelpMenu;
import net.sourceforge.ganttproject.action.project.ProjectMenu;
import net.sourceforge.ganttproject.action.resource.ResourceActionSet;
import net.sourceforge.ganttproject.action.view.ViewCycleAction;
import net.sourceforge.ganttproject.action.view.ViewMenu;
import net.sourceforge.ganttproject.action.zoom.ZoomActionSet;
import net.sourceforge.ganttproject.chart.Chart;
import net.sourceforge.ganttproject.chart.GanttChart;
import net.sourceforge.ganttproject.chart.TimelineChart;
import net.sourceforge.ganttproject.chart.overview.GPToolbar;
import net.sourceforge.ganttproject.chart.overview.ToolbarBuilder;
import net.sourceforge.ganttproject.document.Document;
import net.sourceforge.ganttproject.document.Document.DocumentException;
import net.sourceforge.ganttproject.document.DocumentCreator;
import net.sourceforge.ganttproject.export.CommandLineExportApplication;
import net.sourceforge.ganttproject.gui.*;
import net.sourceforge.ganttproject.gui.scrolling.ScrollingManager;
import net.sourceforge.ganttproject.importer.Importer;
import net.sourceforge.ganttproject.io.GPSaver;
import net.sourceforge.ganttproject.io.GanttXMLOpen;
import net.sourceforge.ganttproject.io.GanttXMLSaver;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.language.GanttLanguage.Event;
import net.sourceforge.ganttproject.parser.GPParser;
import net.sourceforge.ganttproject.parser.ParserFactory;
import net.sourceforge.ganttproject.plugins.PluginManager;
import net.sourceforge.ganttproject.print.PrintManager;
import net.sourceforge.ganttproject.resource.HumanResourceManager;
import net.sourceforge.ganttproject.resource.ResourceEvent;
import net.sourceforge.ganttproject.resource.ResourceView;
import net.sourceforge.ganttproject.roles.RoleManager;
import net.sourceforge.ganttproject.task.*;
import javax.annotation.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
/**
* Main frame of the project
*/
public class GanttProject extends GanttProjectBase implements ResourceView, GanttLanguage.Listener {
private static final ExecutorService ourExecutor = Executors.newSingleThreadExecutor();
/** The JTree part. */
private GanttTree2 tree;
/** GanttGraphicArea for the calendar with Gantt */
private GanttGraphicArea area;
/** GanttPeoplePanel to edit person that work on the project */
private GanttResourcePanel resp;
private final EditMenu myEditMenu;
private final ProjectMenu myProjectMenu;
/** The project filename */
public Document projectDocument = null;
/** Informations for the current project. */
public PrjInfos prjInfos = new PrjInfos();
/** Boolean to know if the file has been modify */
public boolean askForSave = false;
/** Is the application only for viewer. */
public boolean isOnlyViewer;
private final ResourceActionSet myResourceActions;
private final ZoomActionSet myZoomActions;
private final TaskManager myTaskManager;
private final FacadeInvalidator myFacadeInvalidator;
private UIConfiguration myUIConfiguration;
private final GanttOptions options;
private TaskContainmentHierarchyFacadeImpl myCachedFacade;
private ArrayList<GanttPreviousState> myPreviousStates = new ArrayList<GanttPreviousState>();
private MouseListener myStopEditingMouseListener = null;
private GanttChartTabContentPanel myGanttChartTabContent;
private ResourceChartTabContentPanel myResourceChartTabContent;
private List<RowHeightAligner> myRowHeightAligners = Lists.newArrayList();
private final WeekendCalendarImpl myCalendar = new WeekendCalendarImpl();
private ParserFactory myParserFactory;
private HumanResourceManager myHumanResourceManager;
private RoleManager myRoleManager;
private static Runnable ourQuitCallback;
public GanttProject(boolean isOnlyViewer) {
System.err.println("Creating main frame...");
ToolTipManager.sharedInstance().setInitialDelay(200);
ToolTipManager.sharedInstance().setDismissDelay(60000);
myCalendar.addListener(new GPCalendarListener() {
@Override
public void onCalendarChange() {
GanttProject.this.setModified();
}
});
Mediator.registerTaskSelectionManager(getTaskSelectionManager());
this.isOnlyViewer = isOnlyViewer;
if (!isOnlyViewer) {
setTitle(language.getText("appliTitle"));
} else {
setTitle("GanttViewer");
}
setFocusable(true);
System.err.println("1. loading look'n'feels");
options = new GanttOptions(getRoleManager(), getDocumentManager(), isOnlyViewer);
myUIConfiguration = options.getUIConfiguration();
myUIConfiguration.setChartFontOption(getUiFacadeImpl().getChartFontOption());
myUIConfiguration.setDpiOption(getUiFacadeImpl().getDpiOption());
class TaskManagerConfigImpl implements TaskManagerConfig {
@Override
public Color getDefaultColor() {
return getUIFacade().getGanttChart().getTaskDefaultColorOption().getValue();
}
@Override
public GPCalendarCalc getCalendar() {
return GanttProject.this.getActiveCalendar();
}
@Override
public TimeUnitStack getTimeUnitStack() {
return GanttProject.this.getTimeUnitStack();
}
@Override
public HumanResourceManager getResourceManager() {
return GanttProject.this.getHumanResourceManager();
}
@Override
public URL getProjectDocumentURL() {
try {
return getDocument().getURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
}
@Override
public NotificationManager getNotificationManager() {
return getUIFacade().getNotificationManager();
}
}
TaskManagerConfig taskConfig = new TaskManagerConfigImpl();
myTaskManager = TaskManager.Access.newInstance(new TaskContainmentHierarchyFacade.Factory() {
@Override
public TaskContainmentHierarchyFacade createFacade() {
return GanttProject.this.getTaskContainment();
}
}, taskConfig);
addProjectEventListener(myTaskManager.getProjectListener());
getActiveCalendar().addListener(myTaskManager.getCalendarListener());
ImageIcon icon = new ImageIcon(getClass().getResource("/icons/ganttproject.png"));
setIconImage(icon.getImage());
myFacadeInvalidator = new FacadeInvalidator(getTree().getModel(), myRowHeightAligners);
getProject().addProjectEventListener(myFacadeInvalidator);
area = new GanttGraphicArea(this, getTree(), getTaskManager(), getZoomManager(), getUndoManager());
getTree().init();
options.addOptionGroups(getUIFacade().getOptions());
options.addOptionGroups(getUIFacade().getGanttChart().getOptionGroups());
options.addOptionGroups(getUIFacade().getResourceChart().getOptionGroups());
options.addOptionGroups(getProjectUIFacade().getOptionGroups());
options.addOptionGroups(getDocumentManager().getNetworkOptionGroups());
options.addOptions(getRssFeedChecker().getOptions());
System.err.println("2. loading options");
initOptions();
// Not a joke. This takes value from the option and applies it to the UI.
getTree().setGraphicArea(area);
getUIFacade().setLookAndFeel(getUIFacade().getLookAndFeel());
myRowHeightAligners.add(getTree().getRowHeightAligner());
getUiFacadeImpl().getAppFontOption().addChangeValueListener(new ChangeValueListener() {
@Override
public void changeValue(ChangeValueEvent event) {
for (RowHeightAligner aligner : myRowHeightAligners) {
aligner.optionsChanged();
}
}
});
getZoomManager().addZoomListener(area.getZoomListener());
ScrollingManager scrollingManager = getScrollingManager();
scrollingManager.addScrollingListener(area.getViewState());
scrollingManager.addScrollingListener(getResourcePanel().area.getViewState());
System.err.println("3. creating menus...");
myResourceActions = getResourcePanel().getResourceActionSet();
myZoomActions = new ZoomActionSet(getZoomManager());
JMenuBar bar = new JMenuBar();
setJMenuBar(bar);
// Allocation of the menus
// Project menu related sub menus and items
ProjectMRUMenu mruMenu = new ProjectMRUMenu(this, getUIFacade(), getProjectUIFacade(), "lastOpen");
mruMenu.setIcon(new ImageIcon(getClass().getResource("/icons/recent_16.gif")));
getDocumentManager().addListener(mruMenu);
myProjectMenu = new ProjectMenu(this, mruMenu, "project");
bar.add(myProjectMenu);
myEditMenu = new EditMenu(getProject(), getUIFacade(), getViewManager(), getSearchUi(), "edit");
bar.add(myEditMenu);
ViewMenu viewMenu = new ViewMenu(getProject(), getViewManager(), getUiFacadeImpl().getDpiOption(), getUiFacadeImpl().getChartFontOption(), "view");
bar.add(viewMenu);
{
TaskTreeUIFacade taskTree = getUIFacade().getTaskTree();
JMenu mTask = UIUtil.createTooltiplessJMenu(GPAction.createVoidAction("task"));
mTask.add(taskTree.getNewAction());
mTask.add(taskTree.getPropertiesAction());
mTask.add(taskTree.getDeleteAction());
getResourcePanel().setTaskPropertiesAction(taskTree.getPropertiesAction());
bar.add(mTask);
}
JMenu mHuman = UIUtil.createTooltiplessJMenu(GPAction.createVoidAction("human"));
for (AbstractAction a : myResourceActions.getActions()) {
mHuman.add(a);
}
mHuman.add(myResourceActions.getResourceSendMailAction());
mHuman.add(myResourceActions.getResourceImportAction());
bar.add(mHuman);
HelpMenu helpMenu = new HelpMenu(getProject(), getUIFacade(), getProjectUIFacade());
bar.add(helpMenu.createMenu());
System.err.println("4. creating views...");
myGanttChartTabContent = new GanttChartTabContentPanel(getProject(), getUIFacade(), getTree(), area.getJComponent(),
getUIConfiguration());
getViewManager().createView(myGanttChartTabContent, new ImageIcon(getClass().getResource("/icons/tasks_16.gif")));
getViewManager().toggleVisible(myGanttChartTabContent);
myResourceChartTabContent = new ResourceChartTabContentPanel(getProject(), getUIFacade(), getResourcePanel(),
getResourcePanel().area);
getViewManager().createView(myResourceChartTabContent, new ImageIcon(getClass().getResource("/icons/res_16.gif")));
getViewManager().toggleVisible(myResourceChartTabContent);
addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getGanttChart().reset();
getResourceChart().reset();
// This will clear any modifications which might be caused by
// adjusting widths of table columns during initial layout process.
getProject().setModified(false);
}
});
}
});
System.err.println("5. calculating size and packing...");
final GPToolbar toolbar = createToolbar();
createContentPane(toolbar.getToolbar());
//final List<? extends JComponent> buttons = addButtons(getToolBar());
// Chart tabs
getTabs().setSelectedIndex(0);
System.err.println("6. changing language ...");
languageChanged(null);
// Add Listener after language update (to be sure that it is not updated
// twice)
language.addListener(this);
System.err.println("7. first attempt to restore bounds");
restoreBounds();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent windowEvent) {
quitApplication();
}
@Override
public void windowOpened(WindowEvent e) {
System.err.println("Resizing window...");
toolbar.updateButtons();
GPLogger.log(String.format("Bounds after opening: %s", GanttProject.this.getBounds()));
restoreBounds();
// It is important to run aligners after look and feel is set and font sizes
// in the UI manager updated.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (RowHeightAligner aligner : myRowHeightAligners) {
aligner.optionsChanged();
}
}
});
getUiFacadeImpl().getDpiOption().addChangeValueListener(new ChangeValueListener() {
@Override
public void changeValue(ChangeValueEvent event) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getContentPane().doLayout();
}
});
}
});
}
});
System.err.println("8. finalizing...");
// applyComponentOrientation(GanttLanguage.getInstance()
// .getComponentOrientation());
myTaskManager.addTaskListener(new TaskModelModificationListener(this, getUIFacade()));
addMouseListenerToAllContainer(this.getComponents());
// Add globally available actions/key strokes
GPAction viewCycleForwardAction = new ViewCycleAction(getViewManager(), true);
UIUtil.pushAction(getTabs(), true, viewCycleForwardAction.getKeyStroke(), viewCycleForwardAction);
GPAction viewCycleBackwardAction = new ViewCycleAction(getViewManager(), false);
UIUtil.pushAction(getTabs(), true, viewCycleBackwardAction.getKeyStroke(), viewCycleBackwardAction);
}
private void restoreBounds() {
if (options.isLoaded()) {
Rectangle bounds = new Rectangle(options.getX(), options.getY(), options.getWidth(), options.getHeight());
GPLogger.log(String.format("Bounds stored in the options: %s", bounds));
UIUtil.MultiscreenFitResult fit = UIUtil.multiscreenFit(bounds);
// If more than 1/4 of the rectangle is visible on screen devices then leave it where it is
if (fit.totalVisibleArea < 0.25 || Math.max(bounds.width, bounds.height) < 100) {
// Otherwise if it is visible on at least one device, try to fit it there
if (fit.argmaxVisibleArea != null) {
bounds = fitBounds(fit.argmaxVisibleArea, bounds);
} else {
UIUtil.MultiscreenFitResult currentFit = UIUtil.multiscreenFit(this.getBounds());
if (currentFit.argmaxVisibleArea != null) {
// If there are no devices where rectangle is visible, fit it on the current device
bounds = fitBounds(currentFit.argmaxVisibleArea, bounds);
} else {
GPLogger.log(String.format("We have not found the display corresponding to bounds %s. Leaving the window where it is", bounds));
return;
}
}
}
setBounds(bounds);
}
}
static private Rectangle fitBounds(GraphicsConfiguration display, Rectangle bounds) {
Rectangle displayBounds = display.getBounds();
Rectangle visibleBounds = bounds.intersection(displayBounds);
int fitX = visibleBounds.x;
if (fitX + bounds.width > displayBounds.x + displayBounds.width) {
fitX = Math.max(displayBounds.x, displayBounds.x + displayBounds.width - bounds.width);
}
int fitY = visibleBounds.y;
if (fitY + bounds.height > displayBounds.y + displayBounds.height) {
fitY = Math.max(displayBounds.y, displayBounds.y + displayBounds.height - bounds.height);
}
return new Rectangle(fitX, fitY, bounds.width, bounds.height);
}
@Override
public TaskContainmentHierarchyFacade getTaskContainment() {
if (myFacadeInvalidator == null) {
return TaskContainmentHierarchyFacade.STUB;
}
if (!myFacadeInvalidator.isValid() || myCachedFacade == null) {
myCachedFacade = new TaskContainmentHierarchyFacadeImpl(tree);
myFacadeInvalidator.reset();
}
return myCachedFacade;
}
private void initOptions() {
// Color color = GanttGraphicArea.taskDefaultColor;
// myApplicationConfig.register(options);
options.setUIConfiguration(myUIConfiguration);
options.load();
myUIConfiguration = options.getUIConfiguration();
}
private void addMouseListenerToAllContainer(Component[] containers) {
for (Component container : containers) {
container.addMouseListener(getStopEditingMouseListener());
if (container instanceof Container) {
addMouseListenerToAllContainer(((Container) container).getComponents());
}
}
}
/** @return A mouseListener that stop the edition in the ganttTreeTable. */
private MouseListener getStopEditingMouseListener() {
if (myStopEditingMouseListener == null)
myStopEditingMouseListener = new MouseAdapter() {
// @Override
// public void mouseClicked(MouseEvent e) {
// if (e.getSource() != bNew && e.getClickCount() == 1) {
// tree.stopEditing();
// }
// if (e.getButton() == MouseEvent.BUTTON1
// && !(e.getSource() instanceof JTable)
// && !(e.getSource() instanceof AbstractButton)) {
// Task taskUnderPointer =
// area.getChartImplementation().findTaskUnderPointer(e.getX(),
// e.getY());
// if (taskUnderPointer == null) {
// getTaskSelectionManager().clear();
// }
// }
// }
};
return myStopEditingMouseListener;
}
/** @return the options of ganttproject. */
public GanttOptions getGanttOptions() {
return options;
}
/** @return the options of the GanttChart */
public GPOptionGroup[] getGanttOptionsGroup() {
return area.getOptionGroups();
}
public void restoreOptions() {
options.initDefault();
myUIConfiguration = options.getUIConfiguration();
area.repaint();
}
// TODO Move language updating methods which do not belong to GanttProject to
// their own class with their own listener
/** Function to change language of the project */
@Override
public void languageChanged(Event event) {
applyComponentOrientation(language.getComponentOrientation());
area.repaint();
getResourcePanel().area.repaint();
CustomColumnsStorage.changeLanguage(language);
applyComponentOrientation(language.getComponentOrientation());
}
/** @return the ToolTip in HTML (with gray bgcolor) */
public static String getToolTip(String msg) {
return "<html><body bgcolor=#EAEAEA>" + msg + "</body></html>";
}
/** Create the button on toolbar */
private GPToolbar createToolbar() {
ToolbarBuilder builder = new ToolbarBuilder()
.withHeight(40)
.withDpiOption(getUiFacadeImpl().getDpiOption())
.withLafOption(getUiFacadeImpl().getLafOption(), new Function<String, Float>() {
@Override
public Float apply(@Nullable String s) {
return (s.indexOf("nimbus") >= 0) ? 1.5f : 1f;
}
})
.withSquareButtons()
.withBorder(BorderFactory.createEmptyBorder(3, 3, 5, 3));
builder.addButton(new TestGanttRolloverButton(myProjectMenu.getOpenProjectAction().asToolbarAction()))
.addButton(new TestGanttRolloverButton(myProjectMenu.getSaveProjectAction().asToolbarAction()))
.addWhitespace();
final ArtefactAction newAction;
{
final GPAction taskNewAction = getTaskTree().getNewAction().asToolbarAction();
final GPAction resourceNewAction = getResourceTree().getNewAction().asToolbarAction();
newAction = new ArtefactNewAction(new ActiveActionProvider() {
@Override
public AbstractAction getActiveAction() {
return getTabs().getSelectedIndex() == UIFacade.GANTT_INDEX ? taskNewAction : resourceNewAction;
}
}, new Action[] {taskNewAction, resourceNewAction});
final TestGanttRolloverButton bNewTask = new TestGanttRolloverButton(taskNewAction);
final TestGanttRolloverButton bnewResource = new TestGanttRolloverButton(resourceNewAction);
builder.addButton(bNewTask).addButton(bnewResource);
getTabs().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent changeEvent) {
switch (getTabs().getSelectedIndex()) {
case UIFacade.GANTT_INDEX:
bNewTask.setVisible(true);
bnewResource.setVisible(false);
return;
case UIFacade.RESOURCES_INDEX:
bNewTask.setVisible(false);
bnewResource.setVisible(true);
return;
}
}
});
}
final ArtefactAction deleteAction;
{
final GPAction taskDeleteAction = getTaskTree().getDeleteAction().asToolbarAction();
final GPAction resourceDeleteAction = getResourceTree().getDeleteAction().asToolbarAction();
deleteAction = new ArtefactDeleteAction(new ActiveActionProvider() {
@Override
public AbstractAction getActiveAction() {
return getTabs().getSelectedIndex() == UIFacade.GANTT_INDEX ? taskDeleteAction : resourceDeleteAction;
}
}, new Action[] { taskDeleteAction, resourceDeleteAction });
}
final ArtefactAction propertiesAction;
{
final GPAction taskPropertiesAction = getTaskTree().getPropertiesAction().asToolbarAction();
final GPAction resourcePropertiesAction = getResourceTree().getPropertiesAction().asToolbarAction();
propertiesAction = new ArtefactPropertiesAction(new ActiveActionProvider() {
@Override
public AbstractAction getActiveAction() {
return getTabs().getSelectedIndex() == UIFacade.GANTT_INDEX ? taskPropertiesAction : resourcePropertiesAction;
}
}, new Action[] { taskPropertiesAction, resourcePropertiesAction });
}
UIUtil.registerActions(getRootPane(), false, newAction, propertiesAction, deleteAction);
// UIUtil.registerActions(toolBar, false, newAction, propertiesAction,
// deleteAction);
UIUtil.registerActions(myGanttChartTabContent.getComponent(), true, newAction, propertiesAction, deleteAction);
UIUtil.registerActions(myResourceChartTabContent.getComponent(), true, newAction, propertiesAction, deleteAction);
getTabs().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
// Tell artefact actions that the active provider changed, so they
// are able to update their state according to the current delegate
newAction.actionStateChanged();
propertiesAction.actionStateChanged();
deleteAction.actionStateChanged();
getTabs().getSelectedComponent().requestFocus();
}
});
builder.addButton(new TestGanttRolloverButton(deleteAction))
.addWhitespace()
.addButton(new TestGanttRolloverButton(propertiesAction))
.addButton(new TestGanttRolloverButton(getCutAction().asToolbarAction()))
.addButton(new TestGanttRolloverButton(getCopyAction().asToolbarAction()))
.addButton(new TestGanttRolloverButton(getPasteAction().asToolbarAction()))
.addWhitespace()
.addButton(new TestGanttRolloverButton(myEditMenu.getUndoAction().asToolbarAction()))
.addButton(new TestGanttRolloverButton(myEditMenu.getRedoAction().asToolbarAction()));
JTextField searchBox = getSearchUi().getSearchField();
//searchBox.setMaximumSize(new Dimension(searchBox.getPreferredSize().width, buttons.get(0).getPreferredSize().height));
searchBox.setAlignmentY(CENTER_ALIGNMENT);
JPanel tailPanel = new JPanel(new BorderLayout());
//JPanel searchPanel = new JPanel();
//searchPanel.add(searchBox);
//searchPanel.setAlignmentY(CENTER_ALIGNMENT);
tailPanel.add(searchBox, BorderLayout.EAST);
//tailPanel.setAlignmentY(CENTER_ALIGNMENT);
tailPanel.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
builder.addPanel(tailPanel);
//return result;
final GPToolbar toolbar = builder.build();
getUiFacadeImpl().addOnUpdateComponentTreeUi(new Runnable() {
@Override
public void run() {
toolbar.resize();
}
});
return toolbar;
}
@Override
public List<GanttPreviousState> getBaselines() {
return myPreviousStates;
}
/** Refresh the information of the project on the status bar. */
public void refreshProjectInformation() {
if (getTaskManager().getTaskCount() == 0 && resp.nbPeople() == 0) {
getStatusBar().setSecondText("");
} else {
getStatusBar().setSecondText(
language.getCorrectedLabel("task") + " : " + getTaskManager().getTaskCount() + " "
+ language.getCorrectedLabel("resources") + " : " + resp.nbPeople());
}
}
/** Print the project */
public void printProject() {
Chart chart = getUIFacade().getActiveChart();
if (chart == null) {
getUIFacade().showErrorDialog(
"Failed to find active chart.\nPlease report this problem to GanttProject development team");
return;
}
try {
PrintManager.printChart(chart, options.getExportSettings());
} catch (OutOfMemoryError e) {
getUIFacade().showErrorDialog(GanttLanguage.getInstance().getText("printing.out_of_memory"));
}
}
/** Create a new project */
public void newProject() {
getProjectUIFacade().createProject(getProject());
fireProjectCreated();
}
@Override
public void open(Document document) throws IOException, DocumentException {
document.read();
getDocumentManager().addToRecentDocuments(document);
//myMRU.add(document.getPath(), true);
projectDocument = document;
setTitle(language.getText("appliTitle") + " [" + document.getFileName() + "]");
for (Chart chart : PluginManager.getCharts()) {
chart.reset();
}
// myDelayManager.fireDelayObservation(); // it is done in repaint2
addMouseListenerToAllContainer(this.getComponents());
fireProjectOpened();
}
public void openStartupDocument(String path) {
if (path != null) {
final Document document = getDocumentManager().getDocument(path);
// openStartupDocument(document);
getUndoManager().undoableEdit("OpenFile", new Runnable() {
@Override
public void run() {
try {
getProjectUIFacade().openProject(document, getProject());
} catch (DocumentException e) {
fireProjectCreated(); // this will create columns in the tables, which are removed by previous call to openProject()
if (!tryImportDocument(document)) {
getUIFacade().showErrorDialog(e);
}
} catch (IOException e) {
fireProjectCreated(); // this will create columns in the tables, which are removed by previous call to openProject()
if (!tryImportDocument(document)) {
getUIFacade().showErrorDialog(e);
}
}
}
});
}
}
private boolean tryImportDocument(Document document) {
boolean success = false;
List<Importer> importers = PluginManager.getExtensions(Importer.EXTENSION_POINT_ID, Importer.class);
for (Importer importer : importers) {
if (Pattern.matches(".*(" + importer.getFileNamePattern() + ")$", document.getFilePath())) {
try {
((TaskManagerImpl)getTaskManager()).setEventsEnabled(false);
importer.setContext(getProject(), getUIFacade(), getGanttOptions().getPluginPreferences());
importer.setFile(new File(document.getFilePath()));
importer.run();
success = true;
break;
} catch (Throwable e) {
if (!GPLogger.log(e)) {
e.printStackTrace(System.err);
}
} finally {
((TaskManagerImpl)getTaskManager()).setEventsEnabled(true);
}
}
}
return success;
}
/** Save the project as (with a dialog file chooser) */
public boolean saveAsProject() {
getProjectUIFacade().saveProjectAs(getProject());
return true;
}
/** Save the project on a file */
public void saveProject() {
getProjectUIFacade().saveProject(getProject());
}
public void changeWorkingDirectory(String newWorkDir) {
if (null != newWorkDir) {
options.setWorkingDirectory(newWorkDir);
}
}
/** @return the UIConfiguration. */
@Override
public UIConfiguration getUIConfiguration() {
return myUIConfiguration;
}
private boolean myQuitEntered = false;
/** Quit the application */
public boolean quitApplication() {
if (myQuitEntered) {
return false;
}
myQuitEntered = true;
try {
options.setWindowPosition(getX(), getY());
options.setWindowSize(getWidth(), getHeight());
options.setUIConfiguration(myUIConfiguration);
options.save();
if (getProjectUIFacade().ensureProjectSaved(getProject())) {
getProject().close();
setVisible(false);
dispose();
if (ourQuitCallback != null) {
ourQuitCallback.run();
}
return true;
} else {
setVisible(true);
return false;
}
} finally {
myQuitEntered = false;
}
}
public void setAskForSave(boolean afs) {
if (isOnlyViewer) {
return;
}
fireProjectModified(afs);
String title = getTitle();
askForSave = afs;
try {
if (System.getProperty("mrj.version") != null) {
rootPane.putClientProperty("windowModified", Boolean.valueOf(afs));
// see http://developer.apple.com/qa/qa2001/qa1146.html
} else {
if (askForSave) {
if (!title.endsWith(" *")) {
setTitle(title + " *");
}
}
}
} catch (AccessControlException e) {
// This can happen when running in a sandbox (Java WebStart)
System.err.println(e + ": " + e.getMessage());
}
}
public GanttResourcePanel getResourcePanel() {
if (this.resp == null) {
this.resp = new GanttResourcePanel(this, getUIFacade());
this.resp.init();
myRowHeightAligners.add(this.resp.getRowHeightAligner());
getHumanResourceManager().addView(this.resp);
}
return this.resp;
}
public GanttGraphicArea getArea() {
return this.area;
}
public GanttTree2 getTree() {
if (tree == null) {
tree = new GanttTree2(this, getTaskManager(), getTaskSelectionManager(), getUIFacade());
}
return tree;
}
public GPAction getCopyAction() {
return getViewManager().getCopyAction();
}
public GPAction getCutAction() {
return getViewManager().getCutAction();
}
public GPAction getPasteAction() {
return getViewManager().getPasteAction();
}
@Override
public ZoomActionSet getZoomActionSet() {
return myZoomActions;
}
public static class Args {
@Parameter(names = "-log", description = "Enable logging", arity = 1)
public boolean log = true;
@Parameter(names = "-log_file", description = "Log file name")
public String logFile = "auto";
@Parameter(names = { "-h", "-help" }, description = "Print usage")
public boolean help = false;
@Parameter(description = "Input file name")
public List<String> file = null;
}
/** The main */
public static boolean main(String[] arg) {
URL logConfig = GanttProject.class.getResource("/logging.properties");
if (logConfig != null) {
try {
GPLogger.readConfiguration(logConfig);
} catch (IOException e) {
System.err.println("Failed to setup logging: " + e.getMessage());
e.printStackTrace();
}
}
CommandLineExportApplication cmdlineApplication = new CommandLineExportApplication();
final Args mainArgs = new Args();
try {
JCommander cmdLineParser = new JCommander(new Object[] { mainArgs, cmdlineApplication.getArguments() }, arg);
if (mainArgs.help) {
cmdLineParser.usage();
System.exit(0);
}
} catch (Throwable e) {
e.printStackTrace();
return false;
}
if (mainArgs.log && "auto".equals(mainArgs.logFile)) {
mainArgs.logFile = System.getProperty("user.home") + File.separator + "ganttproject.log";
}
if (mainArgs.log && !mainArgs.logFile.trim().isEmpty()) {
try {
GPLogger.setLogFile(mainArgs.logFile);
File logFile = new File(mainArgs.logFile);
System.setErr(new PrintStream(new FileOutputStream(logFile)));
System.out.println("Writing log to " + logFile.getAbsolutePath());
} catch (IOException e) {
System.err.println("Failed to write log to file: " + e.getMessage());
e.printStackTrace();
}
}
GPLogger.logSystemInformation();
// Check if an export was requested from the command line
if (cmdlineApplication.export(mainArgs)) {
// Export succeeded so exit application
return false;
}
Runnable autosaveCleanup = DocumentCreator.createAutosaveCleanup();
final AtomicReference<GanttSplash> splash = new AtomicReference<>(null);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
splash.set(new GanttSplash());
splash.get().setVisible(true);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
GPLogger.log(e1);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
final GanttProject ganttFrame = new GanttProject(false);
System.err.println("Main frame created");
ganttFrame.fireProjectCreated();
if (mainArgs.file != null && !mainArgs.file.isEmpty()) {
ganttFrame.openStartupDocument(mainArgs.file.get(0));
}
ganttFrame.setVisible(true);
GPLogger.log(String.format("Bounds after setVisible: %s", ganttFrame.getBounds()));
if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) {
OSXAdapter.registerMacOSXApplication(ganttFrame);
}
ganttFrame.getActiveChart().reset();
ganttFrame.getRssFeedChecker().setOptionsVersion(ganttFrame.getGanttOptions().getVersion());
ganttFrame.getRssFeedChecker().run();
ganttFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
} catch (Throwable e) {
e.printStackTrace();
} finally {
splash.get().close();
System.err.println("Splash closed");
Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
GPLogger.log(e);
}
});
}
}
});
if (autosaveCleanup != null) {
ourExecutor.submit(autosaveCleanup);
}
return true;
}
// ///////////////////////////////////////////////////////
// IGanttProject implementation
@Override
public String getProjectName() {
return prjInfos.getName();
}
@Override
public void setProjectName(String projectName) {
prjInfos.setName(projectName);
setAskForSave(true);
}
@Override
public String getDescription() {
return prjInfos.getDescription();
}
@Override
public void setDescription(String description) {
prjInfos.setDescription(description);
setAskForSave(true);
}
@Override
public String getOrganization() {
return prjInfos.getOrganization();
}
@Override
public void setOrganization(String organization) {
prjInfos.setOrganization(organization);
setAskForSave(true);
}
@Override
public String getWebLink() {
return prjInfos.getWebLink();
}
@Override
public void setWebLink(String webLink) {
prjInfos.setWebLink(webLink);
setAskForSave(true);
}
@Override
public HumanResourceManager getHumanResourceManager() {
if (myHumanResourceManager == null) {
myHumanResourceManager = new HumanResourceManager(getRoleManager().getDefaultRole(),
getResourceCustomPropertyManager());
myHumanResourceManager.addView(this);
}
return myHumanResourceManager;
}
@Override
public TaskManager getTaskManager() {
return myTaskManager;
}
@Override
public RoleManager getRoleManager() {
if (myRoleManager == null) {
myRoleManager = RoleManager.Access.getInstance();
}
return myRoleManager;
}
@Override
public Document getDocument() {
return projectDocument;
}
@Override
public void setDocument(Document document) {
projectDocument = document;
}
@Override
public GPCalendarCalc getActiveCalendar() {
return myCalendar;
}
@Override
public void setModified() {
setAskForSave(true);
}
@Override
public void setModified(boolean modified) {
setAskForSave(modified);
String title = getTitle();
if (modified == false && title.endsWith(" *")) {
// Remove * from title
setTitle(title.substring(0, title.length() - 2));
}
}
@Override
public boolean isModified() {
return askForSave;
}
@Override
public void close() {
fireProjectClosed();
prjInfos = new PrjInfos();
RoleManager.Access.getInstance().clear();
projectDocument = null;
getTaskCustomColumnManager().reset();
getResourceCustomPropertyManager().reset();
for (int i = 0; i < myPreviousStates.size(); i++) {
myPreviousStates.get(i).remove();
}
myPreviousStates = new ArrayList<GanttPreviousState>();
myCalendar.reset();
myFacadeInvalidator.projectClosed();
}
@Override
protected ParserFactory getParserFactory() {
if (myParserFactory == null) {
myParserFactory = new ParserFactoryImpl();
}
return myParserFactory;
}
// ///////////////////////////////////////////////////////////////
// ResourceView implementation
@Override
public void resourceAdded(ResourceEvent event) {
if (getStatusBar() != null) {
// tabpane.setSelectedIndex(1);
String description = language.getCorrectedLabel("resource.new.description");
if (description == null) {
description = language.getCorrectedLabel("resource.new");
}
getUIFacade().setStatusText(description);
setAskForSave(true);
refreshProjectInformation();
}
}
@Override
public void resourcesRemoved(ResourceEvent event) {
refreshProjectInformation();
setAskForSave(true);
}
@Override
public void resourceChanged(ResourceEvent e) {
setAskForSave(true);
}
@Override
public void resourceAssignmentsChanged(ResourceEvent e) {
setAskForSave(true);
}
// ///////////////////////////////////////////////////////////////
// UIFacade
@Override
public GanttChart getGanttChart() {
return getArea();
}
@Override
public TimelineChart getResourceChart() {
return getResourcePanel().area;
}
@Override
public int getGanttDividerLocation() {
return myGanttChartTabContent.getDividerLocation();
}
@Override
public void setGanttDividerLocation(int location) {
myGanttChartTabContent.setDividerLocation(location);
}
@Override
public int getResourceDividerLocation() {
return myResourceChartTabContent.getDividerLocation();
}
@Override
public void setResourceDividerLocation(int location) {
myResourceChartTabContent.setDividerLocation(location);
}
@Override
public TaskTreeUIFacade getTaskTree() {
return getTree();
}
@Override
public ResourceTreeUIFacade getResourceTree() {
return getResourcePanel();
}
private class ParserFactoryImpl implements ParserFactory {
@Override
public GPParser newParser() {
return new GanttXMLOpen(prjInfos, getUIConfiguration(), getTaskManager(), getUIFacade());
}
@Override
public GPSaver newSaver() {
return new GanttXMLSaver(GanttProject.this, getTree(), getResourcePanel(), getArea(), getUIFacade());
}
}
public void setRowHeight(int value) {
tree.getTreeTable().getTable().setRowHeight(value);
}
public void repaint2() {
getResourcePanel().getResourceTreeTableModel().updateResources();
getResourcePanel().getResourceTreeTable().setRowHeight(20);
super.repaint();
}
@Override
public int getViewIndex() {
if (getTabs() == null) {
return -1;
}
return getTabs().getSelectedIndex();
}
@Override
public void setViewIndex(int viewIndex) {
if (getTabs().getTabCount() > viewIndex) {
getTabs().setSelectedIndex(viewIndex);
}
}
public static void setApplicationQuitCallback(Runnable callback) {
ourQuitCallback = callback;
}
@Override
public void refresh() {
getTaskManager().processCriticalPath(getTaskManager().getRootTask());
getResourcePanel().getResourceTreeTableModel().updateResources();
getResourcePanel().getResourceTreeTable().setRowHeight(20);
for (Chart chart : PluginManager.getCharts()) {
chart.reset();
}
super.repaint();
}
}