001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 021 package org.sonar.api.utils; 022 023 import org.sonar.api.BatchComponent; 024 import org.sonar.api.CoreProperties; 025 import org.sonar.api.ServerComponent; 026 import org.sonar.api.config.Settings; 027 import org.sonar.api.i18n.I18n; 028 029 import javax.annotation.CheckForNull; 030 031 import java.util.Locale; 032 033 /** 034 * Used through ruby code <pre>Internal.durations</pre> 035 * 036 * @since 4.3 037 */ 038 public class Durations implements BatchComponent, ServerComponent { 039 040 public enum DurationFormat { 041 /** 042 * Display duration with only one or two members. 043 * For instance, Duration.decode("1d 1h 10min", 8) will return "1d 1h" and Duration.decode("12d 5h", 8) will return "12d" 044 */ 045 SHORT 046 } 047 048 private final Settings settings; 049 private final I18n i18n; 050 051 public Durations(Settings settings, I18n i18n) { 052 this.settings = settings; 053 this.i18n = i18n; 054 } 055 056 /** 057 * Create a Duration object from a number of minutes 058 */ 059 public Duration create(long minutes) { 060 return Duration.create(minutes); 061 } 062 063 /** 064 * Convert the text to a Duration 065 * <br> 066 * Example : decode("9d 10 h") -> Duration.encode("10d2h") (if sonar.technicalDebt.hoursInDay property is set to 8) 067 */ 068 public Duration decode(String duration) { 069 return Duration.decode(duration, hoursInDay()); 070 } 071 072 /** 073 * Return the string value of the Duration. 074 * <br> 075 * Example : encode(Duration.encode("9d 10h")) -> "10d2h" (if sonar.technicalDebt.hoursInDay property is set to 8) 076 */ 077 public String encode(Duration duration) { 078 return duration.encode(hoursInDay()); 079 } 080 081 /** 082 * Return the formatted work duration. 083 * <br> 084 * Example : format(Locale.FRENCH, Duration.encode("9d 10h"), DurationFormat.SHORT) -> 10j 2h (if sonar.technicalDebt.hoursInDay property is set to 8) 085 */ 086 public String format(Locale locale, Duration duration, DurationFormat format) { 087 Long durationInMinutes = duration.toMinutes(); 088 if (durationInMinutes == 0) { 089 return "0"; 090 } 091 boolean isNegative = durationInMinutes < 0; 092 Long absDuration = Math.abs(durationInMinutes); 093 094 int days = ((Double) ((double) absDuration / hoursInDay() / 60)).intValue(); 095 Long remainingDuration = absDuration - (days * hoursInDay() * 60); 096 int hours = ((Double) (remainingDuration.doubleValue() / 60)).intValue(); 097 remainingDuration = remainingDuration - (hours * 60); 098 int minutes = remainingDuration.intValue(); 099 100 return format(locale, days, hours, minutes, isNegative); 101 } 102 103 private String format(Locale locale, int days, int hours, int minutes, boolean isNegative){ 104 StringBuilder message = new StringBuilder(); 105 if (days > 0) { 106 message.append(message(locale, "work_duration.x_days", isNegative ? -1 * days : days)); 107 } 108 if (displayHours(days, hours)) { 109 addSpaceIfNeeded(message); 110 message.append(message(locale, "work_duration.x_hours", isNegative && message.length() == 0 ? -1 * hours : hours)); 111 } 112 if (displayMinutes(days, hours, minutes)) { 113 addSpaceIfNeeded(message); 114 message.append(message(locale, "work_duration.x_minutes", isNegative && message.length() == 0 ? -1 * minutes : minutes)); 115 } 116 return message.toString(); 117 } 118 119 private String message(Locale locale, String key, @CheckForNull Object parameter) { 120 return i18n.message(locale, key, null, parameter); 121 } 122 123 private boolean displayHours(int days, int hours) { 124 return hours > 0 && days < 10; 125 } 126 127 private boolean displayMinutes(int days, int hours, int minutes) { 128 return minutes > 0 && hours < 10 && days == 0; 129 } 130 131 private void addSpaceIfNeeded(StringBuilder message) { 132 if (message.length() > 0) { 133 message.append(" "); 134 } 135 } 136 137 private int hoursInDay() { 138 return settings.getInt(CoreProperties.HOURS_IN_DAY); 139 } 140 141 }