r3027 - in branches/ng-jtimer/src/main: java/org/chorem/jtimer java/org/chorem/jtimer/config java/org/chorem/jtimer/entities java/org/chorem/jtimer/io java/org/chorem/jtimer/io/resources java/org/chorem/jtimer/storage java/org/chorem/jtimer/web resources webapp/css webapp/js webapp/partials
Author: obruce Date: 2014-08-08 17:02:24 +0200 (Fri, 08 Aug 2014) New Revision: 3027 Url: http://forge.chorem.org/projects/jtimer/repository/revisions/3027 Log: Suppression des taches avec condition Masquage des taches Debut de l'import Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/DataHandler.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/GTimerDataLoader.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/DailySortedMap.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/GTimerTimeUtil.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerAlert.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerProject.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerTask.java branches/ng-jtimer/src/main/webapp/partials/dialogModal.html Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfig.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfigOption.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerAlarm.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerTask.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/storage/Storage.java branches/ng-jtimer/src/main/java/org/chorem/jtimer/web/RestApplication.java branches/ng-jtimer/src/main/resources/jtimer-default.properties branches/ng-jtimer/src/main/webapp/css/app.css branches/ng-jtimer/src/main/webapp/js/app.js branches/ng-jtimer/src/main/webapp/js/controllers.js branches/ng-jtimer/src/main/webapp/js/entities.js branches/ng-jtimer/src/main/webapp/partials/reportModal.html branches/ng-jtimer/src/main/webapp/partials/tasks.html Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfig.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfig.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfig.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -209,6 +209,13 @@ return appConfig.getOption(JtimerConfigOption.JTIMER_STORAGE_UPDATE_TASK_WITHID.getKey()); } + /***/ + public String getStorageQueryUpdateTimeID(){ + return appConfig.getOption(JtimerConfigOption.JTIMER_STORAGE_UPDATE_TIME_CHANGEID.getKey()); + } + public String getStorageQueryUpdateTimeIDWithDate(){ + return appConfig.getOption(JtimerConfigOption.JTIMER_STORAGE_UPDATE_TIME_CHANGEIDWITHDATE.getKey()); + } public String getStorageQueryUpdateTaskPath(){ return appConfig.getOption(JtimerConfigOption.JTIMER_STORAGE_UPDATE_TASK_PATH.getKey()); } Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfigOption.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfigOption.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/config/JtimerConfigOption.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -250,7 +250,18 @@ "", String.class ), - + JTIMER_STORAGE_UPDATE_TIME_CHANGEID( + "jtimer.storage.update.time.changeid", + "méthode qui va faire l'update de l'id d'une tâche", + "", + String.class + ), + JTIMER_STORAGE_UPDATE_TIME_CHANGEIDWITHDATE( + "jtimer.storage.update.time.changeid.whithdate", + "méthode qui va faire l'update de l'id d'une tâche", + "", + String.class + ), JTIMER_STORAGE_UPDATE_TASK_WITHID( "jtimer.storage.update.task.withid", "requête de mise à jour d'une taches avec un identifiant", Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerAlarm.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerAlarm.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerAlarm.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -1,6 +1,7 @@ package org.chorem.jtimer.entities; import java.util.Date; +import java.util.UUID; /** * Created by olivia on 02/07/14. @@ -29,31 +30,34 @@ /**ModificationDate*/ protected Date modificationDate; - /** limit time in hour to spend on the task */ - protected int limitHour; + /** total duration */ + long duration; - /** limit time in min to spend on the task */ - protected int limitMin; + /** remaining time */ + long remainingTime; - /** passed time in hour to spend on the task */ - protected int remainingMin; - /** passed time in min to spend on the task */ - protected int remainingHour; - /** date if alarm is removed */ protected long removed; - public TimerAlarm(String taskId, String alarmId, String name, String type, Date modificationDate, int limitHour, int limitMin) { + public TimerAlarm(String taskId, String name, String type, long limit) { this.taskId = taskId; + this.alarmId = UUID.randomUUID().toString(); + this.name = name; + this.type = type; + this.modificationDate = new Date(); + duration = limit; + remainingTime = limit; + } + + public TimerAlarm(String taskId, String alarmId, String name, String type, Date modificationDate, long limit) { + this.taskId = taskId; this.alarmId = alarmId; this.name = name; this.type = type; this.modificationDate = modificationDate; - this.limitHour = limitHour; - this.limitMin = limitMin; - this.remainingHour = limitHour; - this.remainingMin =limitMin; + duration = limit; + remainingTime = limit; } public TimerAlarm() { @@ -108,39 +112,22 @@ this.modificationDate = modificationDate; } - public int getLimitHour() { - return limitHour; + public long getDuration() { + return duration; } - public void setLimitHour(int limitHour) { - this.limitHour = limitHour; + public void setDuration(long duration) { + this.duration = duration; } - public int getLimitMin() { - return limitMin; + public long getRemainingTime() { + return remainingTime; } - public void setLimitMin(int limitMin) { - this.limitMin = limitMin; + public void setRemainingTime(long remainingTime) { + this.remainingTime = remainingTime; } - public int getRemainingMin() { - return remainingMin; - } - - public void setRemainingMin(int remainingMin) { - this.remainingMin = remainingMin; - } - - public int getRemainingHour() { - return remainingHour; - } - - public void setRemainingHour(int remainingHour) { - this.remainingHour = remainingHour; - } - - @Override public String toString() { return "TimerAlarm{" + @@ -149,10 +136,8 @@ ", name='" + name + '\'' + ", type='" + type + '\'' + ", modificationDate=" + modificationDate + - ", limitHour=" + limitHour + - ", limitMin=" + limitMin + - ", remainingMin=" + remainingMin + - ", remainingHour=" + remainingHour + + ", limit=" + duration + + ", remaining=" + remainingTime + ", removed=" + removed + '}'; } Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerTask.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerTask.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/entities/TimerTask.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -25,6 +25,8 @@ package org.chorem.jtimer.entities; +import org.chorem.jtimer.io.resources.OldTimerTask; + import java.io.Serializable; import java.util.Date; import java.util.UUID; @@ -105,8 +107,44 @@ this.tags = null; } + /** + * Constructor with name. + * + * @param name task name + */ + public TimerTask( String name, String parent, String description) { + this(); + this.name = name; + this.taskId = UUID.randomUUID().toString(); + this.parent = parent; + this.description=description; + this.creationDate = new Date(); + this.modificationDate = new Date(); + this.removed = 0; + this.path = null; + this.tags = null; + } /** + * Constructor with name. + * + * @param other an imported element + */ + public TimerTask( OldTimerTask other, String parent) { + this(); + this.name = other.getName(); + this.taskId = other.getUuid(); + this.parent = parent; + this.description=""; + this.creationDate = other.getCreationDate(); + this.modificationDate = new Date(); + this.removed = other.isClosed()? 1 : 0 ; + this.path = null; + this.tags = null; + } + + + /** * Set task uuid * * @param taskuuid task uuid Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/DataHandler.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/DataHandler.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/DataHandler.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,123 @@ +package org.chorem.jtimer.io; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.entities.TimerAlarm; +import org.chorem.jtimer.entities.TimerTask; +import org.chorem.jtimer.entities.TimerTime; +import org.chorem.jtimer.io.resources.OldTimerAlert; +import org.chorem.jtimer.io.resources.OldTimerTask; +import org.chorem.jtimer.storage.Storage; + +import java.io.File; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; + +/** + * This class will handle the migration of gtimer data to webtimer data + * + * Created by olivia on 07/08/14. + * <p/> + * Project name : jtimer + * <p/> + * Package name : org.chorem.jtimer.io + */ +public class DataHandler { + + private static Log log = LogFactory.getLog(DataHandler.class); + + /** Loader to load old data **/ + GTimerDataLoader loader; + + /** Le directory to save */ + protected String saveDirectory = System.getProperty("user.home") + + File.separator + ".gtimer"; + + + /** Old data path */ + private String DATA_PATH = saveDirectory + File.separator +"backups" + File.separator +"backup-20140807100651.zip"; + + protected Storage storage; + + public DataHandler(Storage storage){ + this.loader = new GTimerDataLoader(); + this.storage = storage; + } + + public void migrateData(){ + Collection oldData; + Collection res = new HashSet(); + + //On recupere les data du loader sous forme collection de sous tache + oldData = loader.extractOldData(DATA_PATH,"zip"); + + Iterator iter = oldData.iterator(); + + // On parcours les parents + while(iter.hasNext()){ + + OldTimerTask old = (OldTimerTask)iter.next(); + reccursiveMigrate(old,""); + + log.info(old.toString()); + } + } + + protected void reccursiveMigrate( OldTimerTask old, String father){ + + // On reconstruit ce qu'on peut de notre objet + TimerTask task = new TimerTask(old,father); + //Persist la task + storage.addTask(task); + + //On recree temps, alarme et annotation + //Les temps + Iterator iter = old.getAllDaysAndTimes().keySet().iterator(); + while(iter.hasNext()) { + Date key = (Date) iter.next(); + long time = old.getAllDaysAndTimes().get(key); + + TimerTime newTime = new TimerTime(task.getTaskId(), time, key ); + storage.addTaskTime(newTime); + } + + //Les alarmes + Iterator iter2 = old.getAlerts().iterator(); + int index =1; + while(iter2.hasNext()) { + + OldTimerAlert oldAlert = (OldTimerAlert)iter2.next(); + + + TimerAlarm alarm = new TimerAlarm(task.getTaskId(), task.getName()+index, oldAlert.getType().toString(), oldAlert.getDuration()); + storage.addTaskAlarm(alarm); + + index++; + } + + // Les annotations de la v1 sont transformées en sous tache avec des temps + Iterator iter3 = old.getAllDaysAnnotations().keySet().iterator(); + while(iter3.hasNext()) { + Date key = (Date) iter3.next(); + if(old.getAllDaysAndTimes().containsKey(key)){ + // On cree une sous tache pour la tache representant old et on ajoute une descritpion + String annot = old.getAllDaysAnnotations().get(key); + TimerTask newTask = new TimerTask(annot, old.getUuid() ,"AnnotationV1"); + + //Persist la task + storage.addTask(newTask); + + // On change la tache a qui appartient le temps pour le jour de old + storage.updateTimeId(newTask.getTaskId(), old.getUuid(), key); + } + + } + + // On parcours les enfants pour les migrer + for(OldTimerTask child : old.getSubTasks()) { + reccursiveMigrate(child, old.getUuid()); + } + } +} Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/GTimerDataLoader.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/GTimerDataLoader.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/GTimerDataLoader.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,639 @@ +package org.chorem.jtimer.io; + + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.chorem.jtimer.io.resources.GTimerTimeUtil; +import org.chorem.jtimer.io.resources.OldTimerAlert; +import org.chorem.jtimer.io.resources.OldTimerProject; +import org.chorem.jtimer.io.resources.OldTimerTask; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * Created by olivia on 07/08/14. + * Code interne repris de svn.chorem.org/jtimer/trunk/src/main/java/org/chorem/jtimer/io/GTimerIncrementalSaver.java + * <p/> + * Project name : jtimer + * <p/> + * Package name : org.chorem.jtimer.io + */ +public class GTimerDataLoader { + + private static Log log = LogFactory.getLog(GTimerDataLoader.class); + + /** + * Separateur pour les sous taches. + * + * Utilise pour assurer une compatibilite avec gTimer, qui ne permet pas de + * stocker des sous taches. + */ + protected static final String GTIMER_SUBTASK_SEPARATOR = "/"; + + /** Version du format de fichier. */ + protected static final String GTIMER_FILE_VERSION = "1.2"; + + /** Extension project. */ + protected static final String GTIMER_PROJECT_EXTENSION = "project"; + + /** Extension task. */ + protected static final String GTIMER_TASK_EXTENSION = "task"; + + /** Extension annotation. */ + protected static final String GTIMER_ANNOTATION_EXTENSION = "ann"; + + /** Extension alert. */ + protected static final String GTIMER_ALERT_EXTENSION = "alert"; + + + /** Empty gtimer project name. */ + protected static final String GTIMER_EMPTY_PROJECT_NAME = "No project"; + + /** + * Save directory. Init with $user.home/.gtimer + */ + protected String saveDirectory = System.getProperty("user.home") + + File.separator + ".gtimer"; + + public GTimerDataLoader(){ + + } + + public Collection extractOldData(String oldDataPath, String type){ + + Collection res = null; + + if(type.equals("zip")){ + + String path = saveDirectory + File.separator + "zipHelper"; + //unzip + unzip(oldDataPath, path); + res = gTimerLoad(path); + //delete created folder + deleteFolder( path); + + }else{ + res = gTimerLoad(saveDirectory); + } + + return res; + } + + /** + * Load from gtimer file format. + * + * @return projects loaded + */ + protected Collection<OldTimerProject> gTimerLoad(String folder) { + + // map number => project + Map<String, OldTimerProject> mapNumberProject = new HashMap<>(); + + // probleme : il faut d'abord lire les "project" avant les task + // pour pouvoir fair l'association + // donc deux boucles + + File gTimerFileDir = new File(folder); + + // loop 1 , reading projects + // project file "0.project" + Pattern pPatronNommage = Pattern.compile("^(\\d+)\\." + + GTIMER_PROJECT_EXTENSION + "$"); + for (File f : gTimerFileDir.listFiles()) { + if (f.isFile() && f.canRead()) { + Matcher m = pPatronNommage.matcher(f.getName()); + if (m.find()) { + String number = m.group(1); // 1 = le chiffre + + try { + int projectNumber = Integer.parseInt(number); + + OldTimerProject p = getProjectFromFile(f); + if (p != null) { + p.setNumber(projectNumber); + mapNumberProject.put(number, p); + } + } catch (NumberFormatException e) { + if (log.isWarnEnabled()) { + log.warn("Can't parse " + f.getName() + + " as gtimer file", e); + } + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Can't read file", e); + } + } + } + } + } + + // loop 2 , reading tasks + // task file "0.task" + pPatronNommage = Pattern.compile("^(\\d+)\\." + GTIMER_TASK_EXTENSION + + "$"); + + // map to remember tasks to manage after load + // sorted on / number in their name + SortedMap<OldTimerTask, OldTimerProject> taskToPostManaged = new TreeMap<>( + new Comparator<OldTimerTask>() { + @Override + public int compare(OldTimerTask t1, OldTimerTask t2) { + + int numberOfSeparatorInT1 = t1.getName().split( + GTIMER_SUBTASK_SEPARATOR).length; + int numberOfSeparatorInT2 = t2.getName().split( + GTIMER_SUBTASK_SEPARATOR).length; + + int compare = numberOfSeparatorInT1 + - numberOfSeparatorInT2; + + // seems to delete when return 0 ??? + if (compare == 0) { + compare = -1; + } + return compare; + } + }); + + // now process each file + for (File f : gTimerFileDir.listFiles()) { + if (f.isFile() && f.canRead()) { + Matcher m = pPatronNommage.matcher(f.getName()); + if (m.find()) { + + // oui, annotations sur un numero de tache + String number = m.group(1); + + try { + int taskNumber = Integer.parseInt(number); + + OldTimerTask task = parseTaskFromFile(mapNumberProject, f, + taskToPostManaged); + + if (task != null) { + task.setNumber(taskNumber); + + parseAnnotations(task); + parseAlerts(task); + } + } catch (NumberFormatException e) { + if (log.isWarnEnabled()) { + log.warn("Can't parse " + f.getName() + + " as gtimer file", e); + } + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Can't parse task file", e); + } + } + } + } + } + + // post process tasks + parseTaskFromSavedMap(taskToPostManaged); + + // collection to return + return mapNumberProject.values(); + } + + /** + * Load a project in his file. + * + * @param projectFile project file + * @return a project + * @throws IOException if ioexception occurs + */ + protected OldTimerProject getProjectFromFile(File projectFile) + throws IOException { + + Properties prop = new Properties(); + prop.load(new BufferedInputStream(new FileInputStream(projectFile))); + + // log + if (log.isDebugEnabled()) { + log.debug("Load project (" + projectFile.getName() + ") : " + + prop.getProperty("Name")); + } + + OldTimerProject p = null; + if (GTIMER_FILE_VERSION.equals(prop.get("Format"))) { + p = new OldTimerProject(); + p.setName(prop.getProperty("Name")); + + // manage creation timestamp (conversion to long) + try { + String creationTimeStamp = prop.getProperty("Created"); + long timestampinms = Long.parseLong(creationTimeStamp) * 1000; + p.setCreationDate(new Date(timestampinms)); + } catch (NumberFormatException e) { + if (log.isWarnEnabled()) { + log.warn("Invalid 'Created' timestamp", e); + } + p.setCreationDate(new Date(0)); + } + + p.setClosed(prop.getProperty("Options").equals("1")); + } else { + if (log.isWarnEnabled()) { + log.warn("Invalid file format. Excepted " + GTIMER_FILE_VERSION + + ", found " + prop.get("Format")); + } + } + return p; + } + + /** + * Parse task file. + * + * @param mapNumberProject map entre les projets reels et leur numero gtimer + * @param taskFile gtimer task file + * @param taskToManage sorted map to remember task to post process + * @return parsed task + * @throws IOException if ioexception occurs + */ + protected OldTimerTask parseTaskFromFile( + Map<String, OldTimerProject> mapNumberProject, File taskFile, + SortedMap<OldTimerTask, OldTimerProject> taskToManage) throws IOException { + + OldTimerTask t = null; + + Pattern dataPattern = Pattern.compile("(\\d{4})(\\d{2})(\\d{2})"); + + Properties prop = new Properties(); + prop.load(new BufferedInputStream(new FileInputStream(taskFile))); + + if (GTIMER_FILE_VERSION.equals(prop.get("Format"))) { + t = new OldTimerTask(); + + // manage creation timestamp (convertion to long) + try { + String creationTimeStamp = prop.getProperty("Created"); + long timestampinms = Long.parseLong(creationTimeStamp) * 1000; + t.setCreationDate(new Date(timestampinms)); + } catch (NumberFormatException e) { + if (log.isWarnEnabled()) { + log.warn("Invalid 'Created' timestamp for " + taskFile, e); + } + t.setCreationDate(new Date(0)); + } + + t.setClosed(prop.getProperty("Options").equals("1")); + + // name = task + // name = task/subtask1 + // name = task/subtask1/subsubtask1 + String gtimerTaskName = prop.getProperty("Name"); + t.setName(gtimerTaskName); + // yes put all names + // will be corrected later + + // log + if (log.isDebugEnabled()) { + log.debug("Load task (" + taskFile.getName() + ") : " + + gtimerTaskName); + } + + // analyse des donnees (temps) + for (Object key : prop.keySet()) { + String sKey = (String) key; + + // test if key format match + Matcher m = dataPattern.matcher(sKey); + if (m.find()) { + try { + Date keyDate = GTimerTimeUtil.yyyyMMdd2Date(sKey); + String timeString = (String) prop.get(sKey); + t.setTime(keyDate, Long.valueOf(timeString) * 1000); + } catch (NumberFormatException e) { + if (log.isErrorEnabled()) { + log.error("Can't convert " + prop.get(sKey) + + " into long"); + } + } + } + // else not data entry + } + + // find associated project instance with number + String taskProjectNumber = (String) prop.get("Project"); + OldTimerProject associatedProject = mapNumberProject + .get(taskProjectNumber); + + // fix bug case task has no associated project + // can do that in gtimer + if (associatedProject == null && taskProjectNumber.equals("-1")) { + associatedProject = new OldTimerProject(); + associatedProject.setName(GTIMER_EMPTY_PROJECT_NAME); + mapNumberProject.put(taskProjectNumber, associatedProject); + } + + if (associatedProject != null) { + // used to correct bug #1636 : [jTimer] Bug du rechargement des + // sous taches + taskToManage.put(t, associatedProject); + + if (log.isDebugEnabled()) { + log.debug("Put " + t.getName() + ", " + + associatedProject.getName()); + } + } else { + if (log.isWarnEnabled()) { + log.warn("task " + t.getName() + + " is associated with a wrong project number " + + prop.get("Project")); + } + } + + } else { + if (log.isWarnEnabled()) { + log.warn("Invalid file format. Excepted " + GTIMER_FILE_VERSION + + ", found " + prop.get("Format")); + } + } + + return t; + } + + /** + * Try to find and load annotations from task. + * + * @param task task to load annotations + * @throws IOException if can't read ann file + */ + protected void parseAnnotations(OldTimerTask task) throws IOException { + int taskNumber = task.getNumber(); + + File annotationsTaskFile = new File(saveDirectory + File.separator + + taskNumber + "." + GTIMER_ANNOTATION_EXTENSION); + + if (annotationsTaskFile.exists()) { + if (log.isDebugEnabled()) { + log.debug("Annotations found for task " + task.getName()); + } + + Properties prop = new Properties(); + prop.load(new BufferedInputStream(new FileInputStream( + annotationsTaskFile))); + + // analyse des donnees (temps) + for (Object key : prop.keySet()) { + String sKey = (String) key; + + // test if key format match + try { + + // key of annotation is in seconds + long timestamp = Long.parseLong(sKey); + Date dateTS = new Date(timestamp * 1000); + + String annoText = (String) prop.get(sKey); + + task.addAnnotation(dateTS, annoText); + } catch (NumberFormatException e) { + if (log.isErrorEnabled()) { + log.error("Can't convert " + sKey + " into long"); + } + } + } + } + } + + /** + * Find task alert and load it. + * + * This file can't be loaded by {@code Properties#load(java.io.InputStream)}. + * Constains duplicated keys. + * + * @param task task to load alert + * @throws IOException if can't read ann file + */ + protected void parseAlerts(OldTimerTask task) throws IOException { + int taskNumber = task.getNumber(); + + File alertTaskFile = new File(saveDirectory + File.separator + + taskNumber + "." + GTIMER_ALERT_EXTENSION); + + if (alertTaskFile.exists()) { + if (log.isDebugEnabled()) { + log.debug("Alert found for task " + task.getName()); + } + + BufferedReader alertIn = new BufferedReader(new FileReader( + alertTaskFile)); + + // skip first line : "format: 1.2" + String line; + while ((line = alertIn.readLine()) != null) { + + line = line.trim(); + if (!line.isEmpty()) { + String alertType = line.substring(0, line.indexOf(' ')); + String alertDuration = line.substring( + line.indexOf(' ') + 1, line.length()); + + try { + if ("reachtotaltime".equals(alertType)) { + Long duration = Long.parseLong(alertDuration) * 1000; + OldTimerAlert alert = new OldTimerAlert( + OldTimerAlert.Type.REACH_TOTAL_TIME, duration); + task.addAlert(alert); + } else if ("reachdailytime".equals(alertType)) { + Long duration = Long.parseLong(alertDuration) * 1000; + OldTimerAlert alert = new OldTimerAlert( + OldTimerAlert.Type.REACH_DAILY_TIME, duration); + task.addAlert(alert); + } else { + if (log.isWarnEnabled()) { + log.warn("Unknow alert type " + alertType); + } + } + } catch (NumberFormatException e) { + if (log.isErrorEnabled()) { + log.error("Can't convert " + alertDuration + + " into long"); + } + } + } + } + + alertIn.close(); + } + } + + /** + * Post process task to manage subtask loaded before parent task. + * + * @param taskToManage sorted map of those task + */ + protected void parseTaskFromSavedMap( + SortedMap<OldTimerTask, OldTimerProject> taskToManage) { + + // process each task + for (Map.Entry<OldTimerTask, OldTimerProject> entry : taskToManage.entrySet()) { + OldTimerTask currentTask = entry.getKey(); + OldTimerProject associatedProject = entry.getValue(); + + if (log.isDebugEnabled()) { + log.debug("Post process task " + currentTask.getName()); + } + + // process task name + String gTimerTaskname = currentTask.getName(); + String[] tabTaskNames = gTimerTaskname + .split(GTIMER_SUBTASK_SEPARATOR); + + // associated to project + if (tabTaskNames.length == 1) { + associatedProject.addTask(currentTask); + + } else { + // tabTaskNames.length != 1 + // sub task : add task to corresponding task + + // correct task name + String realTaskName = tabTaskNames[tabTaskNames.length - 1]; + currentTask.setName(realTaskName); + + if (log.isDebugEnabled()) { + log.debug("Converting task " + gTimerTaskname + + " in sub tasks"); + } + + OldTimerTask task = findTask(associatedProject, Arrays + .copyOfRange(tabTaskNames, 0, tabTaskNames.length - 1)); + if (task != null) { + task.addTask(currentTask); + } else { + if (log.isDebugEnabled()) { + log.debug("task " + Arrays.toString(tabTaskNames) + + " cannot be found, add task to project"); + } + + // add task to project, to not loose it + currentTask.setName(gTimerTaskname); + associatedProject.addTask(currentTask); + } + } + } + } + + /** + * Find a task in task's subtask + * + * @param parentTask task + * @param taskNames names + * @return a task or <tt>null</tt> + */ + protected OldTimerTask findTask(OldTimerTask parentTask, String[] taskNames) { + + OldTimerTask result = null; + + if (taskNames.length > 0) { + for (OldTimerTask task : parentTask.getSubTasks()) { + if (task.getName().equals(taskNames[0])) { + result = findTask(task, Arrays.copyOfRange(taskNames, 1, + taskNames.length)); + } + } + } else { + result = parentTask; + } + + return result; + } + + /** + * Method that will unzip a specific zipFile in a folder + * + * @param zipFile the file to unzip + * @param outputFolder the path to the wanted folder + */ + protected void unzip(String zipFile, String outputFolder){ + + try { + /** Buffer to read */ + byte[] buffer = new byte[1024]; + + // Our folder to output to + File folder = new File(outputFolder); + if(!folder.exists()){ + folder.mkdir(); + } + + // We get zip's content + ZipInputStream zip = new ZipInputStream(new FileInputStream(zipFile)); + + // We retrieve the zip's list + ZipEntry ze = zip.getNextEntry(); + + while(ze != null){ + + String fileName = ze.getName(); + File newFile = new File(outputFolder + File.separator + fileName); + + //create non existent parent folders + new File(newFile.getParent()).mkdirs(); + + FileOutputStream fos = new FileOutputStream(newFile); + + int len; + while ((len = zip.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + + fos.close(); + ze = zip.getNextEntry(); + + if(log.isDebugEnabled()){ + log.debug("unziped file: "+ newFile.getAbsoluteFile()); + } + } + + zip.closeEntry(); + zip.close(); + + if(log.isDebugEnabled()){ + log.debug("Unzip done!"); + } + + }catch(IOException e){ + log.error(e); + } + } + + /** + * Delete the specified folder + * + * @param folderPath the path to the folder + */ + protected void deleteFolder(String folderPath){ + + try { + FileUtils.deleteDirectory(new File(folderPath)); + } catch (IOException e) { + log.error("Couldn't manage folder : \n " + e); + } + + } +} Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/DailySortedMap.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/DailySortedMap.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/DailySortedMap.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,284 @@ +package org.chorem.jtimer.io.resources; + +import java.util.Calendar; +import java.util.Comparator; +import java.util.Date; +import java.util.Map; +import java.util.NavigableMap; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * SortedMap that return a unique value for all date for a day. + * + * @see java.util.SortedMap + * @param <T> values type + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class DailySortedMap<T> extends TreeMap<Date, T> { + + /** serialVersionUID */ + private static final long serialVersionUID = 5736472379626976185L; + + /** + * Constructs a new, empty tree map, using the natural ordering + * of its keys. + */ + public DailySortedMap() { + } + + /** + * Constructs a new, empty tree map, ordered according to + * the given comparator. + * + * @param comparator comparator + */ + public DailySortedMap(Comparator<? super Date> comparator) { + super(comparator); + } + + /** + * Constructs a new tree map containing the same mappings + * as the given map, ordered according to the natural ordering of its keys. + * + * @param m init map + */ + public DailySortedMap(Map<? extends Date, ? extends T> m) { + super(m); + } + + /** + * Constructs a new tree map containing the same mappings and + * using the same ordering as the specified sorted map. + * + * @param m init map + */ + public DailySortedMap(SortedMap<Date, ? extends T> m) { + super(m); + } + + /** + * {@inheritDoc} + */ + @Override + public Map.Entry<Date, T> ceilingEntry(Date key) { + Date dayKey = getDayDate(key); + Map.Entry<Date, T> result = super.ceilingEntry(dayKey); + return result; + + } + + /** + * {@inheritDoc} + */ + @Override + public Date ceilingKey(Date key) { + Date dayKey = getDayDate(key); + Date result = super.ceilingKey(dayKey); + return result; + + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsKey(Object key) { + boolean result = false; + + if (key instanceof Date) { + Date lDate = getDayDate((Date) key); + result = super.containsKey(lDate); + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Map.Entry<Date, T> floorEntry(Date key) { + Date dayKey = getDayDate(key); + Map.Entry<Date, T> result = super.floorEntry(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Date floorKey(Date key) { + Date dayKey = getDayDate(key); + Date result = super.floorKey(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public T get(Object key) { + T result = null; + + if (key instanceof Date) { + Date lDate = getDayDate((Date) key); + result = super.get(lDate); + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public NavigableMap<Date, T> headMap(Date toKey, boolean inclusive) { + Date dayKey = getDayDate(toKey); + NavigableMap<Date, T> result = super.headMap(dayKey, inclusive); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public SortedMap<Date, T> headMap(Date toKey) { + Date dayKey = getDayDate(toKey); + SortedMap<Date, T> result = super.headMap(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Map.Entry<Date, T> higherEntry(Date key) { + Date dayKey = getDayDate(key); + Map.Entry<Date, T> result = super.higherEntry(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Date higherKey(Date key) { + Date dayKey = getDayDate(key); + Date result = super.higherKey(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Map.Entry<Date, T> lowerEntry(Date key) { + Date dayKey = getDayDate(key); + Map.Entry<Date, T> result = super.lowerEntry(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Date lowerKey(Date key) { + Date dayKey = getDayDate(key); + Date result = super.lowerKey(dayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public T put(Date key, T value) { + Date lDate = getDayDate(key); + T result = super.put(lDate, value); + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void putAll(Map<? extends Date, ? extends T> map) { + for (Map.Entry<? extends Date, ? extends T> entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public NavigableMap<Date, T> subMap(Date fromKey, boolean fromInclusive, + Date toKey, boolean toInclusive) { + Date fromDayKey = getDayDate(fromKey); + Date toDayKey = getDayDate(toKey); + NavigableMap<Date, T> result = super.subMap(fromDayKey, fromInclusive, + toDayKey, toInclusive); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public SortedMap<Date, T> subMap(Date fromKey, Date toKey) { + Date fromDayKey = getDayDate(fromKey); + Date toDayKey = getDayDate(toKey); + SortedMap<Date, T> result = super.subMap(fromDayKey, toDayKey); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public NavigableMap<Date, T> tailMap(Date fromKey, boolean inclusive) { + Date fromDayKey = getDayDate(fromKey); + NavigableMap<Date, T> result = super.tailMap(fromDayKey, inclusive); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public SortedMap<Date, T> tailMap(Date fromKey) { + Date fromDayKey = getDayDate(fromKey); + SortedMap<Date, T> result = super.tailMap(fromDayKey); + return result; + } + + /** + * Get date at 0h00:00.000. + * + * @param date date to convert + * @return day date + */ + protected Date getDayDate(Date date) { + Date ldate = (Date) date.clone(); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(ldate); + + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + + Date result = calendar.getTime(); + + return result; + } +} + Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/GTimerTimeUtil.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/GTimerTimeUtil.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/GTimerTimeUtil.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,87 @@ +package org.chorem.jtimer.io.resources; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * Util class to manipulate gTimer date format. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ By : $Author$ + */ +public class GTimerTimeUtil { + + /** Class log */ + private static Log log = LogFactory.getLog(GTimerTimeUtil.class); + + /** gtimer day string date format */ + protected static final DateFormat GTIMERDATEFORMAT = new SimpleDateFormat( + "yyyyMMdd"); + + /** + * Protected constructor. + */ + protected GTimerTimeUtil() { + + } + + /** + * Convert a yyyyMMdd date string to Calendar. + * + * @param dateAsString yyyyMMdd sting to convert + * @return {@link Date} + * @throws IllegalArgumentException + */ + public static Date yyyyMMdd2Date(String dateAsString) { + + int year, mouth, day; + Date date = null; + + try { + String syear = dateAsString.substring(0, 4); + String smonth = dateAsString.substring(4, 6); + String sday = dateAsString.substring(6, 8); + + year = Integer.parseInt(syear); + mouth = Integer.parseInt(smonth); + day = Integer.parseInt(sday); + + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, mouth - 1); + calendar.set(Calendar.DAY_OF_MONTH, day); + + date = calendar.getTime(); + } catch (NumberFormatException e) { + if (log.isWarnEnabled()) { + log.warn("Can't parse string " + dateAsString + " in yyyyMMdd format", + e); + } + throw new IllegalArgumentException("Can't parse string " + dateAsString + + " in yyyyMMdd format", e); + } + + return date; + } + + /** + * Convert a calendar to yyyyMMdd date string. + * + * @param date date to convert + * @return a string yyyyMMdd date + * @throws IllegalArgumentException + */ + public static String date2yyyyMMdd(Date date) { + + String dateAsString = GTIMERDATEFORMAT.format(date); + + return dateAsString; + } +} Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerAlert.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerAlert.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerAlert.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,133 @@ +package org.chorem.jtimer.io.resources; + +import java.io.Serializable; + +/** + * Alert. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class OldTimerAlert implements Serializable, Cloneable { + + /** serialVersionUID. */ + private static final long serialVersionUID = 584921087501157113L; + + /** + * Alert type. + */ + public enum Type { + REACH_DAILY_TIME, + REACH_TOTAL_TIME + } + + /** Alert type. */ + protected Type type; + + /** Alert duration. (in ms) */ + protected long duration; + + /** + * Constructor. + */ + public OldTimerAlert() { + + } + + /** + * Constructor. + * + * @param type type + * @param duration duration (ms) + */ + public OldTimerAlert(Type type, long duration) { + this(); + this.type = type; + this.duration = duration; + } + + /** + * Get alert type. + * + * @return the type + */ + public Type getType() { + return type; + } + + /** + * Set alert type. + * + * @param type the type to set + */ + public void setType(Type type) { + this.type = type; + } + + /** + * Get duration. + * + * @return the duration in seconds + */ + public long getDuration() { + return duration; + } + + /** + * Set duration. + * + * @param duration the duration to set (in seconds) + */ + public void setDuration(long duration) { + this.duration = duration; + } + + /* + * @see java.lang.Object#clone() + */ + @Override + public OldTimerAlert clone() { + OldTimerAlert clone = null; + try { + clone = (OldTimerAlert)super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Can't clone", e); + } + return clone; + } + + /* + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (int) (duration ^ (duration >>> 32)); + result = 31 * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + /* + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + boolean result = false; + + if (obj instanceof OldTimerAlert) { + OldTimerAlert other = (OldTimerAlert) obj; + + result = duration == other.duration; + if (type != null) { + result &= type.equals(other.type); + } + else { + result &= other.type == null; + } + } + return result; + } +} Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerProject.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerProject.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerProject.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,66 @@ +package org.chorem.jtimer.io.resources; + +/** + * Represent a project. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class OldTimerProject extends OldTimerTask { + + /** serialVersionUID. */ + private static final long serialVersionUID = -8953488997256237790L; + + /** Synchronized project name prefix. */ + public static final String SYNCHRONIZED_PROJECT_NAME_PREFIX = "#"; + + /** + * Constructor. + */ + public OldTimerProject() { + } + + /** + * Constructor with name. + * + * @param name project name + */ + public OldTimerProject(String name) { + super(name); + } + + /** + * Is synchronized. + * + * @return the synchronize + */ + public boolean isSynchronized() { + + boolean sync = false; + + if (name != null && name.startsWith(SYNCHRONIZED_PROJECT_NAME_PREFIX)) { + sync = true; + } + + return sync; + } + + /** + * Clone project. + * + * @return project copy + */ + @Override + public OldTimerProject clone() { + + // Can't use clone() from super class + // Result object have to be + OldTimerProject newProject = (OldTimerProject) super.clone(); + + return newProject; + } +} + Added: branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerTask.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerTask.java (rev 0) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/io/resources/OldTimerTask.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,383 @@ +package org.chorem.jtimer.io.resources; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.UUID; + + + +/** + * Represents a task. + * + * @author chatellier + * @version $Revision$ + * + * Last update : $Date$ + * By : $Author$ + */ +public class OldTimerTask implements Cloneable, + Comparable<OldTimerTask>, Serializable { + + /** serialVersionUID */ + private static final long serialVersionUID = -7590755569706702695L; + + /** Task uuid used to managed task equality. */ + protected String uuid = UUID.randomUUID().toString(); + + /** Task number. */ + protected int number; + + /** Task name. */ + protected String name; + + /** Creation date. */ + protected Date creationDate; + + /** Closed task. */ + protected boolean closed; + + /** + * Parent Task. + * More convenient + */ + protected OldTimerTask parent; + + /** + * Map calendar of day -> time (ms). (ordered on keys) + */ + protected SortedMap<Date, Long> allDaysTimes; + + /** + * Map date -> annotation text. + */ + protected SortedMap<Date, String> allDaysAnnotations; + + /** + * Sub tasks. + */ + protected List<OldTimerTask> subTasks; + + /** + * Task alerts. + */ + protected List<OldTimerAlert> alerts; + + /** + * Constructor. + */ + public OldTimerTask() { + allDaysTimes = new DailySortedMap<Long>(); + // les annoation sont a la seconde pres + allDaysAnnotations = new TreeMap<Date, String>(); + subTasks = new ArrayList<OldTimerTask>(); + alerts = new ArrayList<OldTimerAlert>(); + + // wrong value to detect bug + number = -1; + } + + /** + * Constructor with name. + * + * @param name task name + */ + public OldTimerTask(String name) { + this(); + this.name = name; + } + + /** + * Get task number. + * + * @return the number + */ + public int getNumber() { + return number; + } + + /** + * Set task number. + * + * @param number the number to set + */ + public void setNumber(int number) { + this.number = number; + } + + /** + * Get task name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Set task name. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get task creation date. + * + * @return task creation date + */ + public Date getCreationDate() { + return creationDate; + } + + /** + * Set task creation date. + * + * @param creationDate creation date + */ + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + /** + * Returns + * + * @return + */ + public String getUuid() { + return uuid; + } + + /** + * Get closed task state. + * + * @return <tt>true</tt> if task is closed + */ + public boolean isClosed() { + return closed; + } + + /** + * Set closed. + * + * @param closed closed + */ + public void setClosed(boolean closed) { + this.closed = closed; + } + + /** + * Get parent. + * + * Can be null if there is no parent. + * + * @return the parent + */ + public OldTimerTask getParent() { + return parent; + } + + /** + * Set parent. + * + * @param parent the parent to set + */ + protected void setParent(OldTimerTask parent) { + // will cause an infinite loop + if (parent == this) { + throw new IllegalArgumentException("Parent can't be current task"); + } + this.parent = parent; + + } + + /** + * Get task's subtasks. + * + * @return the subTasks + */ + public List<OldTimerTask> getSubTasks() { + return subTasks; + } + + /** + * Add task's subtask. + * + * Also add parent reference. + * + * @param t the task to add + * @return success flag + */ + public boolean addTask(OldTimerTask t) { + + // set parent + t.setParent(this); + boolean result = subTasks.add(t); + return result; + } + + /** + * Add time. + * + * @param date date + * @param time time in ms + */ + public void setTime(Date date, Long time) { + allDaysTimes.put(date, time); + } + + /** + * Get time at date. + * + * @param date date + * @return time at specified date in ms + */ + public long getTime(Date date) { + long result = 0; + + Long t = allDaysTimes.get(date); + if (t != null) { + result = t.longValue(); + } + + return result; + } + + /** + * Return all data. Sorted on date. + * + * @return total duration of all projects + */ + public SortedMap<Date, Long> getAllDaysAndTimes() { + return allDaysTimes; + } + + /** + * Add annotation. + * + * @param date date + * @param note note text + */ + public void addAnnotation(Date date, String note) { + allDaysAnnotations.put(date, note); + } + + /** + * Return all annotation, sorted on date. + * + * @return annotations + */ + public SortedMap<Date, String> getAllDaysAnnotations() { + return allDaysAnnotations; + } + + /** + * Add alert. + * + * @param alert + */ + public void addAlert(OldTimerAlert alert) { + alerts.add(alert); + } + + /** + * Get alert list. + * + * @return alerts + */ + public List<OldTimerAlert> getAlerts() { + return alerts; + } + + /** + * Set alert. + * + * @param alerts new alerts list + */ + public void setAlert(List<OldTimerAlert> alerts) { + this.alerts = alerts; + } + + /* + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return name + subTasks.toString(); + } + + /* + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + int result = uuid.hashCode(); + return result; + } + + /* + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + + if (!(o instanceof OldTimerTask)) { + return false; + } + + return uuid.equals(((OldTimerTask)o).uuid); + } + + /** + * Clone task. + * + * @return task copy + */ + @Override + public OldTimerTask clone() { + + OldTimerTask task; + + try { + task = (OldTimerTask) super.clone(); + + // copy date + task.creationDate = creationDate == null ? null + : (Date) creationDate.clone(); + + // make new list instance + task.allDaysTimes = new DailySortedMap<Long>(allDaysTimes); + task.allDaysAnnotations = new TreeMap<Date, String>(allDaysAnnotations); + task.subTasks = new ArrayList<OldTimerTask>(subTasks); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Can't clone", e); + } + + return task; + } + + /* + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(OldTimerTask o) { + + int result; + + if (getName() == null) { + result = -1; + } else if (o.getName() == null) { + result = 1; + } else { + // sort on name + result = getName().compareTo(o.getName()); + } + + return result; + } +} Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/storage/Storage.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/storage/Storage.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/storage/Storage.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -184,19 +184,6 @@ } - public static boolean containsOneTheGood(Object[] array1, Object[] array2){ - boolean result = ArrayUtils.isEmpty(array1) && ArrayUtils.isEmpty(array2); - if (array1 != null && array2 != null) { - //TODO 31/07/2014 obruce optimiser la methode regarder la taille du plus petit tableau - for (Object o : array1) { - result = ArrayUtils.contains(array2, o); - if (result) { - break; - } - } - } - return result; - } public static boolean containsOne(Object[] array1, Object[] array2){ boolean result = ArrayUtils.isEmpty(array1) && ArrayUtils.isEmpty(array2); if (array1 != null && array2 != null) { @@ -211,21 +198,6 @@ return result; } - public static boolean containsOneHack2(Object[] array1, Object[] array2){ - boolean result = ArrayUtils.isEmpty(array1) && ArrayUtils.isEmpty(array2); - if (array1 != null && array2 != null) { - //TODO 31/07/2014 obruce optimiser la methode regarder la taille du plus petit tableau - for (Object o : array1) { - result = ArrayUtils.contains(array2, o); - if (result) { - break; - } - } - } - System.out.println("###"+ArrayUtils.toString(array1)+"#######"+ArrayUtils.toString(array2)+"######## true ?" + result); - return result; - } - /** Query **/ /** @@ -379,12 +351,10 @@ statement.setString(2, alarm.getAlarmId()); statement.setString(3, alarm.getName()); statement.setString(4, alarm.getType()); - statement.setInt(5, alarm.getLimitHour()); - statement.setInt(6, alarm.getLimitMin()); - statement.setInt(7, alarm.getRemainingHour()); - statement.setInt(8, alarm.getRemainingMin()); - statement.setObject(9, alarm.getModificationDate()); - statement.setLong(10, alarm.getRemoved()); + statement.setLong(5, alarm.getDuration()); + statement.setLong(6, alarm.getRemainingTime()); + statement.setObject(7, alarm.getModificationDate()); + statement.setLong(8, alarm.getRemoved()); statement.executeUpdate(); } catch (SQLException ex) { @@ -543,10 +513,10 @@ alarm.setAlarmId(rs.getString("alarmId")); alarm.setName(rs.getString("name")); alarm.setType(rs.getString("type")); - alarm.setLimitHour(rs.getInt("limitHour")); + /* alarm.setLimitHour(rs.getInt("limitHour")); alarm.setLimitMin(rs.getInt("limitMin")); alarm.setRemainingHour(rs.getInt("remainingHour")); - alarm.setRemainingMin(rs.getInt("remainingMin")); + alarm.setRemainingMin(rs.getInt("remainingMin"));*/ alarm.setModificationDate(new Date(rs.getTimestamp("modificationDate").getTime())); alarm.setRemoved(rs.getLong("removed")); @@ -578,10 +548,8 @@ alarm.setAlarmId(rs.getString("alarmId")); alarm.setName(rs.getString("name")); alarm.setType(rs.getString("type")); - alarm.setLimitHour(rs.getInt("limitHour")); - alarm.setLimitMin(rs.getInt("limitMin")); - alarm.setRemainingHour(rs.getInt("remainingHour")); - alarm.setRemainingMin(rs.getInt("remainingMin")); + alarm.setRemainingTime(rs.getLong("remainingTime")); + alarm.setDuration(rs.getLong("duration")); alarm.setModificationDate(new Date(rs.getLong("modificationDate"))); alarm.setRemoved(rs.getLong("removed")); @@ -875,8 +843,8 @@ try { statement = getConnection().prepareStatement(config.getStorageQueryUpdateAlarm()); - statement.setLong(1, t.getRemainingHour()); - statement.setLong(2, t.getRemainingMin()); + /* statement.setLong(1, t.getRemainingHour()); + statement.setLong(2, t.getRemainingMin());*/ statement.setLong(3, t.getRemoved()); statement.executeUpdate(); @@ -890,9 +858,9 @@ /** * Methoque qui met à jour le path d'une tache + * * @param taskId l'identifiant de la tache * @param path l'array representant la tache et ses parents dans l'ordre parent -> enfant - * */ public void updateTaskPath(String taskId, String[] path){ PreparedStatement statement = null; @@ -910,7 +878,30 @@ } + /** + * Methode qui va changer l'id d'un temps à une date + * @param newId the new taskid + * @param oldId the old taskid + * @param date the date + */ + public void updateTimeId(String newId,String oldId, Date date ){ + PreparedStatement statement = null; + try { + //On update celui du fils + statement = getConnection().prepareStatement(config.getStorageQueryUpdateTimeIDWithDate()); + statement.setString(1, newId); + statement.setString(2, oldId); + statement.setObject(3, date); + statement.executeUpdate(); + }catch (SQLException ex) { + throw new StorageException("Can't modify alarm", ex); + } finally { + closeStatement(statement); + } + } + + /** Suppression de tuple **/ /** Modified: branches/ng-jtimer/src/main/java/org/chorem/jtimer/web/RestApplication.java =================================================================== --- branches/ng-jtimer/src/main/java/org/chorem/jtimer/web/RestApplication.java 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/java/org/chorem/jtimer/web/RestApplication.java 2014-08-08 15:02:24 UTC (rev 3027) @@ -5,6 +5,7 @@ import org.apache.commons.logging.LogFactory; import org.chorem.jtimer.config.JtimerConfig; import org.chorem.jtimer.entities.TodoList; +import org.chorem.jtimer.io.DataHandler; import org.chorem.jtimer.storage.Storage; import org.restlet.Application; import org.restlet.Context; @@ -76,9 +77,12 @@ //Initialisation du storage Storage storage = new Storage(jtimerConf); - context.getAttributes().put(Storage.class.getName(), storage); + DataHandler g = new DataHandler(storage); + g.migrateData(); + + //initialisation de la todoList todoList = TodoList.getInstance(); Modified: branches/ng-jtimer/src/main/resources/jtimer-default.properties =================================================================== --- branches/ng-jtimer/src/main/resources/jtimer-default.properties 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/resources/jtimer-default.properties 2014-08-08 15:02:24 UTC (rev 3027) @@ -2,7 +2,7 @@ # jTimer default properties ### # jTimer storage path -jtimer.storage.path=/home/olivia/Bureau/jtimer/jtimer/BDDDevReu +jtimer.storage.path=/home/olivia/Bureau/jtimer/jtimer/BDDImport2 ### # SQL properties ### @@ -42,10 +42,8 @@ alarmId VARCHAR(255) NOT NULL, \ name VARCHAR(255) NOT NULL, \ type VARCHAR(255) NOT NULL, \ - limitHour INTEGER, \ - limitMin INTEGER, \ - remainingMin INTEGER, \ - remainingHour INTEGER, \ + duration LONG, \ + remainingTime LONG, \ modificationDate Timestamp, \ removed LONG, \ PRIMARY KEY (taskId, alarmId), \ @@ -62,8 +60,8 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?) jtimer.storage.insert.time=INSERT INTO tasktime (taskid, creationDate, uuid, duration, modificationDate, removed) \ VALUES (?, ?, ?, ?, ?, ?) -jtimer.storage.insert.alarm=INSERT INTO taskalarm (taskid, alarmId, name, type, limitHour, \ - limitMin, remainingHour, remainingMin, modificationDate, removed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +jtimer.storage.insert.alarm=INSERT INTO taskalarm (taskid, alarmId, name, type, duration, \ + remainingTime, modificationDate, removed) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ### #SELECT jtimer.storage.select.table.name=SELECT table_name FROM information_schema.tables; @@ -115,9 +113,8 @@ AND TA.removed = 0 \ GROUP BY TA.taskId jtimer.storage.select.report.byYear=SELECT YEAR(TI.creationDate) as year, TA.*, sum(TI.duration) AS totalduration \ - FROM task TA, tasktime TI \ + FROM task TA,(Select * FROM tasktime WHERE creationDate BETWEEN ? AND ?) TI \ WHERE TA.taskId = TI.taskid \ - AND TI.creationDate BETWEEN ? AND ? \ AND ARRAY_CONTAINS(TA.path, TA.taskid) \ AND ARRAY_CONTAINS(?, TA.taskid) \ AND TA.removed = 0 \ @@ -206,6 +203,12 @@ jtimer.storage.update.task.path=UPDATE task \ SET path=? \ WHERE taskId = ? +jtimer.storage.update.time.changeid=UPDATE tasktime \ + SET taskId=? \ + WHERE taskId = ? +jtimer.storage.update.time.changeid.whithdate=UPDATE tasktime \ + SET taskId=? \ + WHERE taskId = ? AND creationDate =? jtimer.storage.update.task.withid=UPDATE task SET name=?, parent=?, hidden=?, description=?, modificationDate=?, tags=?, removed=? \ WHERE taskId = ? jtimer.storage.update.time.withid=UPDATE tasktime SET creationDate=?, duration=?, modificationDate=?, removed = ? \ Modified: branches/ng-jtimer/src/main/webapp/css/app.css =================================================================== --- branches/ng-jtimer/src/main/webapp/css/app.css 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/css/app.css 2014-08-08 15:02:24 UTC (rev 3027) @@ -36,6 +36,17 @@ margin-bottom: 0; } +.taskBar{ + position:absolute; + bottom:20px; + left:0; + width:100%; + height:30px; + z-index: 1000; + + background:gray; +} + div#footer{ position:absolute; bottom:0; Modified: branches/ng-jtimer/src/main/webapp/js/app.js =================================================================== --- branches/ng-jtimer/src/main/webapp/js/app.js 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/js/app.js 2014-08-08 15:02:24 UTC (rev 3027) @@ -369,10 +369,10 @@ restrict: 'A', link: function(scope, element, attrs) { element.bind('click', function() { - var message = attrs.ngReallyMessage; - if (message && confirm(message)) { - scope.$apply(attrs.ngReallyClick); - } + var message = attrs.ngReallyMessage; + if (message && confirm(message)) { + scope.$apply(attrs.ngReallyClick); + } }); } } Modified: branches/ng-jtimer/src/main/webapp/js/controllers.js =================================================================== --- branches/ng-jtimer/src/main/webapp/js/controllers.js 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/js/controllers.js 2014-08-08 15:02:24 UTC (rev 3027) @@ -44,6 +44,8 @@ $scope.showGlobal = true; // {boolean} boolean qui indique si la colonne TAGS doit etre affichee $scope.showTags = true; + // {boolean} boolean qui indique si les taches masquees doivent etre affichees + $scope.showHidden = false; // {boolean} etat du client local (le serveur websocket) $scope.webSocketClientOnline = false; @@ -73,11 +75,12 @@ var notification = new Notification( "Notification", { body: msg, - icon: "http://www.gizmodo.fr/wp-content/uploads/2013/05/Coin-coin.png" + icon: "" }); }else if (Notification.permission !== 'denied') { + // On demande la permission Notification.requestPermission(function (permission) { if(!('permission' in Notification)) { Notification.permission = "granted"; @@ -87,7 +90,7 @@ var notification = new Notification( "Notification", { body: msg, - icon: "http://www.gizmodo.fr/wp-content/uploads/2013/05/Coin-coin.png" + icon: "" }); } }); @@ -687,13 +690,44 @@ node.addChild($scope.createTreeNode(newTask)); }; + /** + * methode pour faire le masquage reccursivement recursivement + * en gardant le temps de la tache et de ses parents dans le parent de la tache + */ + $scope.hideTaskRecurse = function(tasks,bool) { + + angular.forEach(tasks, function(task) { + if(bool){ + task.hide(); + }else{ + task.reveal(); + } + + serverTaskAccess.update({dispatch:true}, angular.toJson(task) ,function(){ + console.log("update success" + task.taskId); + }, + function(){ + console.log("fail"); + $scope.todo.stockedEditedTasks.push(node.task); + }); + + var children = $scope.getChildren(task); + $scope.hideTaskRecurse(children); + save(); + }); + }; + /** * Supprime une tache (et ces sous taches recursivement) * @param {type} task */ - $scope.removeTask = function(node) { - // methode pour faire la suppression recursivement - var removeRecurse = function(tasks) { + $scope.removeTask = function(node, method) { + + /** + * methode pour faire la suppression recursivement + */ + var removeRecurse = function(tasks) { + angular.forEach(tasks, function(task) { task.remove(); @@ -716,10 +750,62 @@ removeRecurse(children); save(); }); + }; + /** + * methode pour faire la suppression recursivement + * en gardant le temps de la tache et de ses parents dans le parent de la tache + */ + var removeTaskRecurseKeepTime = function(tasks, father) { + + console.log("coucou1"); + + angular.forEach(tasks, function(task) { + + var children = $scope.getChildren(task); + removeTaskRecurseKeepTime(children,father); + + task.remove(); + + delete $scope.data.tasks[task.taskId]; + + if($scope.data.times[task.taskId]){ + if(!$scope.data.times[father]){ + $scope.data.times[father]=[]; + } + + // On attache les temps à la tache principal + $scope.data.times[father]=$scope.data.times[father].concat($scope.data.times[task.taskId]); + + //TODO persistance + } + + // On supprime les temps associes à la tache + $scope.data.times[task.taskId] = []; + + console.log("coucou2"); + + serverTaskAccess.deleteTask({taskId: task.taskId, dispatch:true}, function(){ + console.log("delete success" + task.taskId); + }, + function(){ + console.log("fail"); + $scope.todo.stockedDeletedTasks.push(task.taskId); + + }); + + node.remove(); + save(); + }); }; - // mark all task as removed - removeRecurse([node.task]); + + if(method = 1){ + // mark all task as removed + removeRecurse([node.task]); + }else{ + removeTaskRecurseKeepTime([node.task], node.task.taskId); + } + // remove node in tree node.remove(); save(); @@ -796,8 +882,8 @@ * @returns {result} */ $scope.getRootTask = function () { - var result = []; - angular.forEach($scope.data.tasks, function (t) { + var result = []; + angular.forEach($scope.data.tasks, function (t) { if (t.isRoot() && !t.isRemoved()) { result.push(t); } @@ -1067,8 +1153,33 @@ } }); - } + }; + $scope.dialogPopup = function(node){ + + var modalInstance = $modal.open({ + templateUrl: 'partials/dialogModal.html', + controller: DialogModalCtrl, + resolve: {} + }); + + modalInstance.result.then( + function(elem) { + + if(elem == 1){ + // Suppression temps et tache + $scope.removeTask(node, 1); + }else if(elem == 2){ + // Suppression taches mais temps reportees au parent + $scope.removeTask(node,2); + }else{ + // Masque de la tache + $scope.hideTaskRecurse([node.task],true); + } + } + ); + }; + $scope.reportPopup = function (){ var modalInstance = $modal.open({ @@ -1081,7 +1192,7 @@ } } }); - } + }; /** *Méthode qui lance les actions à faires sur le serveur @@ -1108,9 +1219,28 @@ } +/** + * Controller pour le dialog de demande de suppression + * + * @param $scope + * @param $modalInstance + */ +function DialogModalCtrl($scope, $modalInstance){ + $scope.supressTaskAndTime = function() { + $modalInstance.close(1); + }; + $scope.supressTask = function() { + $modalInstance.close(2); + }; + $scope.hideTask = function() { + $modalInstance.close(3); + }; +} + + /** * Controller de pour la modal d'option de tache. * @@ -1316,7 +1446,7 @@ */ function ReportModalInstanceCtrl($scope, $modalInstance,$http, $sce, serverReportAccess, tree){ - $scope.modal={radioModel: "Year", showTime : true, tags : false}; + $scope.modal={radioModel: "Year", showTime : true, tags : false, showHidden : false}; $scope.tree = tree; $scope.tag = { array : [] }; Modified: branches/ng-jtimer/src/main/webapp/js/entities.js =================================================================== --- branches/ng-jtimer/src/main/webapp/js/entities.js 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/js/entities.js 2014-08-08 15:02:24 UTC (rev 3027) @@ -406,8 +406,7 @@ */ var Task = function (name,taskId, parentTaskId, parentTags,description) { - if(taskId == undefined) - { + if(taskId == undefined){ this.taskId =generateUUID(); }else{ this.taskId = taskId; @@ -416,8 +415,7 @@ this.modificationDate = Date.now(); this.removed = 0; - if(parentTaskId == undefined) - { + if(parentTaskId == undefined){ this.parent = ""; }else{ this.parent = parentTaskId; @@ -426,6 +424,7 @@ this.name = name; this.description = description; this.isReported = true; + this.hidden = false; this.alarms=[]; this.tags = parentTags; this.syncOptions = {}; @@ -440,6 +439,22 @@ }; /** + * Marque la tache comme cachee + * @returns {undefined} + */ +Task.prototype.hide = function() { + this.hidden = true; +}; + +/** + * Marque la tache comme non cachee + * @returns {undefined} + */ +Task.prototype.reveal = function() { + this.hidden = false; +}; + +/** * return vrai si la tache est supprimee * @returns {boolean} */ Added: branches/ng-jtimer/src/main/webapp/partials/dialogModal.html =================================================================== --- branches/ng-jtimer/src/main/webapp/partials/dialogModal.html (rev 0) +++ branches/ng-jtimer/src/main/webapp/partials/dialogModal.html 2014-08-08 15:02:24 UTC (rev 3027) @@ -0,0 +1,7 @@ +<h4>Supress options : </h4> + +<hr/> + +<button class="btn btn-default" ng-click="supressTaskAndTime()">Suppress task(and subtasks) and times</button> +<button class="btn btn-default" ng-click="supressTask()">Suppess only the task (and subtasks)</button> +<button class="btn btn-default" ng-click="hideTask()">Hide task</button> Modified: branches/ng-jtimer/src/main/webapp/partials/reportModal.html =================================================================== --- branches/ng-jtimer/src/main/webapp/partials/reportModal.html 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/partials/reportModal.html 2014-08-08 15:02:24 UTC (rev 3027) @@ -65,6 +65,10 @@ <input type="checkbox" ng-model="modal.showTime" /> </div> <div> + <span>Show hidden tasks </span> + <input type="checkbox" ng-model="modal.showHidden" /> + </div> + <div> <span>Add tags </span> <input type="checkbox" ng-model="modal.tags" ng-change="removeTags()"/> </div> @@ -93,7 +97,7 @@ <div class="tr" ng-class="{'current-row' : ($node.task === currentTask), 'selected-row' : ($node.task === selectedTask)}"> - <div class="td"> + <div class="td" ng-show=" !$node.task.hidden || modal.showHidden"> <span class="spacer level{{$level}}"></span> <!--Task state icon--> @@ -103,7 +107,8 @@ <!--Project name--> <input type="checkbox" ng-model="$node.task.isReported" ng-change="setChildrenCheckbox($node)"> - <span>{{$node.task.name}} </span> + <span ng-show=" !$node.task.hidden ">{{$node.task.name}} </span> + <span ng-show=" $node.task.hidden "><i>*{{$node.task.name}}* </i></span> </div> </div> Modified: branches/ng-jtimer/src/main/webapp/partials/tasks.html =================================================================== --- branches/ng-jtimer/src/main/webapp/partials/tasks.html 2014-08-04 15:41:37 UTC (rev 3026) +++ branches/ng-jtimer/src/main/webapp/partials/tasks.html 2014-08-08 15:02:24 UTC (rev 3027) @@ -20,6 +20,7 @@ <li>Today <input type='checkbox' ng-model='showToday'/></li> <li>Total <input type='checkbox' ng-model='showGlobal'/></li> <li>Tags <input type='checkbox' ng-model='showTags'/></li> + <li>Hidden Tasks <input type='checkbox' ng-model='showHidden'/></li> </ul> <i class="glyphicon glyphicon-cloud" ng-class="{online: online, offline: !online}"></i> </span> @@ -37,14 +38,12 @@ </div> - - <!-- Footer --> <div id="footer"> <span class="left">{{currentDate()}}</span> - <span class="center"><i class="fa fa-html5"></i> <a>WebTimer</a></span> - <!--<span class="right">{{tree.getTime().today |time}} | {{tree.getTime().global | time}}</span>--> - <span class="right">jTimer</span> + <span class="center"><i class="fa fa-html5 color_red"></i> <a>WebTimer</a></span> + + <span class="right">{{tree.getTime().today |time}} | {{tree.getTime().global | time}}</span> </div> @@ -69,14 +68,14 @@ ng-click="setSelectedTask($node.task)" ng-keydown="keyPressed($event)"><!--ng-dblclick="timeTask($node.task)"--> - <div class="td" ng-show="showName"> + <div class="td" ng-show="showName && (!$node.task.hidden || showHidden)"> <span class="spacer level{{$level}}"></span> <!--Task state icon--> - <span> - <i class="glyphicon glyphicon-ban-circle" ng-show="$state=='empty'"></i> - <i class="glyphicon glyphicon-plus-sign" ng-click="$toggleState()" ng-show="$state=='close'"></i> - <i class="glyphicon glyphicon-minus-sign" ng-click="$toggleState()" ng-show="$state=='open'"></i> + <span > + <i style="font-size:10px" class="glyphicon glyphicon-ban-circle" ng-show="$state=='empty'"></i> + <i style="font-size:10px" class="glyphicon glyphicon-chevron-right" ng-click="$toggleState()" ng-show="$state=='close'"></i> + <i style="font-size:10px" class="glyphicon glyphicon-chevron-down" ng-click="$toggleState()" ng-show="$state=='open'"></i> <img src="partials/loading_timer.gif" height="20" width="20" ng-show="currentTask == $node.task"> </span> @@ -85,7 +84,8 @@ <form ng-submit="saveTask($node)" ng-show="$node.edit == 'name'" ng-blur="$node.edit == ''"> <input ng-model="$node.task.name" ng-blur="$node.edit == ''" > </form> - <span ng-click="editTask($node, 'name')" ng-show="$node.edit != 'name'">{{$node.task.name}} </span> + <span ng-click="editTask($node, 'name')" ng-show="$node.edit != 'name' && !$node.task.hidden ">{{$node.task.name}} </span> + <span ng-click="editTask($node, 'name')" ng-show="$node.edit != 'name' && $node.task.hidden "><i>*{{$node.task.name}}* </i></span> <!-- Action button, add,remove activate task --> @@ -95,16 +95,19 @@ </a> <a class="btn btn-default btn-xs" ng-click="addSubTask($node)"><i class="glyphicon glyphicon-plus"></i></a> <a class="btn btn-default btn-xs" - ng-really-message="La suppression de cette tâche nécessite une confirmation. " - ng-really-click="removeTask($node)" ng-show="$node.task != currentTask"> + ng-click="dialogPopup($node)" ng-show="$node.task != currentTask"> <i class="glyphicon glyphicon-minus"></i> </a> <a class="btn btn-default btn-xs" - ng-really-message="Voulez vous masquer cette tâche?" - ng-really-click="" ng-show="$node.task != currentTask"> + ng-really-message="Do you want to hide this task (and subtasks)?" + ng-really-click="hideTaskRecurse([$node.task],true)" ng-show="$node.task != currentTask && !$node.task.hidden"> <i class="glyphicon glyphicon-eye-close"></i> </a> + <a class="btn btn-default btn-xs" + ng-click="hideTaskRecurse([$node.task],false)" ng-show="$node.task != currentTask && $node.task.hidden"> + <i class="glyphicon glyphicon-eye-open"></i> + </a> <a class="btn btn-default btn-xs" ng-click="optionPopup($node, $node.task.isRoot())"> <i class="glyphicon glyphicon-pencil" ></i> @@ -113,17 +116,17 @@ </div> <!-- Today time of the task --> - <div class="td today" ng-show="showToday"> + <div class="td today" ng-show="showToday && (!$node.task.hidden || showHidden)"> {{$node.getTime().today | time}} </div> <!-- Global time of the task --> - <div class="td global" ng-show="showGlobal"> + <div class="td global" ng-show="showGlobal && (!$node.task.hidden || showHidden)"> {{$node.getTime().global | time}} </div> <!-- Tag of the task --> - <div class="td tags" ng-show="showTags" ng-click="editTask($node, 'tags')"> + <div class="td tags" ng-show="showTags && (!$node.task.hidden || showHidden)" ng-click="editTask($node, 'tags')"> <form ng-submit="saveTask($node)" ng-show="$node.edit == 'tags'"> <input class="form-control input-sm" ng-model="$node.task.tags" ng-list> </form> @@ -148,7 +151,7 @@ <h3 class="modal-title">Inactivité détectée</h3> </div> <div class="modal-body"> - Vous êtes inactif depuis 42 minutes. + Vous êtes inactif depuis à définir minutes. Choisissez une option pour reprendre ou arrêter la tâche. </div> <div class="modal-footer">
participants (1)
-
obruce@users.chorem.org