X

Geertjan's Blog

  • December 18, 2012

Project Time Tracker

Geertjan Wielenga
Product Manager

Based on yesterday's blog entry, let's do something semi useful and display, in the project popup, which
is available when you right-click a project in the Projects window, the time since the last
change was made anywhere in the project, i.e., we can listen recursively
to any changes done within a project and then update the popup with the
newly acquired information, dynamically:

import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.AbstractAction;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionRegistration;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileRenameEvent;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners;
@ActionID(
category = "Demo",
id = "org.ptt.TrackProjectSelectionAction")
@ActionRegistration(
lazy = false,
displayName = "NOT-USED")
@ActionReference(
path = "Projects/Actions",
position = 0)
public final class TrackProjectSelectionAction extends AbstractAction
implements LookupListener, FileChangeListener {
private Lookup.Result<Project> projects;
private Project context;
private Long startTime;
private Long changedTime;
private DateFormat formatter;
private List<Project> timedProjects;
public TrackProjectSelectionAction() {
putValue("popupText", "Timer");
formatter = new SimpleDateFormat("HH:mm:ss");
timedProjects = new ArrayList<Project>();
projects = Utilities.actionsGlobalContext().lookupResult(Project.class);
projects.addLookupListener(
WeakListeners.create(LookupListener.class, this, projects));
resultChanged(new LookupEvent(projects));
}
@Override
public void resultChanged(LookupEvent le) {
Collection<? extends Project> allProjects = projects.allInstances();
if (allProjects.size() == 1) {
Project currentProject = allProjects.iterator().next();
if (!timedProjects.contains(currentProject)) {
String currentProjectName =
ProjectUtils.getInformation(currentProject).getDisplayName();
putValue("popupText", "Start Timer for Project: " + currentProjectName);
StatusDisplayer.getDefault().setStatusText(
"Current Project: " + currentProjectName);
timedProjects.add(currentProject);
context = currentProject;
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
refresh();
}
protected void refresh() {
startTime = System.currentTimeMillis();
String formattedStartTime = formatter.format(startTime);
putValue("popupText", "Timer started: " + formattedStartTime + " ("
+ ProjectUtils.getInformation(context).getDisplayName() + ")");
}
@Override
public void fileChanged(FileEvent fe) {
changedTime = System.currentTimeMillis();
formatter = new SimpleDateFormat("mm:ss");
String formattedLapse = formatter.format(changedTime - startTime);
putValue("popupText", "Time since last change: " + formattedLapse + " ("
+ ProjectUtils.getInformation(context).getDisplayName() + ")");
startTime = changedTime;
}
@Override
public void fileFolderCreated(FileEvent fe) {}
@Override
public void fileDataCreated(FileEvent fe) {}
@Override
public void fileDeleted(FileEvent fe) {}
@Override
public void fileRenamed(FileRenameEvent fre) {}
@Override
public void fileAttributeChanged(FileAttributeEvent fae) {}
}

Some more work needs to be done to complete the above, i.e., for each
project you somehow need to maintain the start time and last change and
redisplay that whenever the user right-clicks the project.

Join the discussion

Comments ( 1 )
  • Time Tracker Wednesday, July 17, 2013

    That is very helpful. It presented me a number of ideas and I’ll be placing them on my blog eventually. Thank you!


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.