<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>app/views/timesheet/_calendar.rhtml</filename>
    </added>
    <added>
      <filename>app/views/timesheet/calendar.html.erb</filename>
    </added>
    <added>
      <filename>lib/time_entry_calendar.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -106,6 +106,39 @@ class TimesheetController &lt; ApplicationController
     end
   end
 
+  def calendar
+    if params &amp;&amp; params[:timesheet]
+      @timesheet = Timesheet.new( params[:timesheet] )
+    else
+      redirect_to :action =&gt; 'daily'
+      return
+    end
+
+    @timesheet.allowed_projects = allowed_projects
+
+    if @timesheet.allowed_projects.empty?
+      render :action =&gt; 'no_projects'
+      return
+    end
+
+    if !params[:timesheet][:projects].blank?
+      @timesheet.projects = @timesheet.allowed_projects.find_all { |project|
+        params[:timesheet][:projects].include?(project.id.to_s)
+      }
+    else
+      @timesheet.projects = @timesheet.allowed_projects
+    end
+
+    call_hook(:plugin_timesheet_controller_calendar_pre_fetch_time_entries, { :timesheet =&gt; @timesheet, :params =&gt; params })
+
+    save_filters_to_session(@timesheet)
+
+    @timesheet.fetch_calendar_time_entries
+
+    send_csv and return if 'csv' == params[:export]
+    render :action =&gt; 'details', :layout =&gt; false if request.xhr?
+  end
+
   private
   def get_list_size
     @list_size = Setting.plugin_timesheet_plugin['list_size'].to_i</diff>
      <filename>app/controllers/timesheet_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,4 +6,88 @@ module TimesheetCalendarHelper
                         value)
   end
 
+  def permalink_to_calendar_timesheet(timesheet)
+    link_to(l(:timesheet_permalink),
+            :controller =&gt; 'timesheet',
+            :action =&gt; 'calendar',
+            :timesheet =&gt; timesheet.to_param
+           )
+  end
+
+  def calendar_navigator(timesheet)
+    month = timesheet.month
+    year = timesheet.year
+    prev_params = timesheet.to_param.merge({:year =&gt; (month==1 ? year-1 : year),
+                                       :month =&gt;(month==1 ? 12 : month-1),
+                                       :period_type =&gt; Timesheet::ValidPeriodType[:calendar]})
+    prev_month = link_to( '&amp;#171; ' + (month==1 ? &quot;#{month_name(12)} #{year-1}&quot; : &quot;#{month_name(month-1)}&quot;),
+      :controller =&gt; 'timesheet', :action =&gt; 'calendar', :timesheet =&gt; prev_params )
+    next_params = timesheet.to_param.merge({:year =&gt; (month==12 ? year+1 : year),
+                                       :month =&gt;(month==12 ? 1 : month+1),
+                                       :period_type =&gt; Timesheet::ValidPeriodType[:calendar]})
+    next_month = link_to( (month==12 ? &quot;#{month_name(1)} #{year+1}&quot; : &quot;#{month_name(month+1)}&quot;) + ' &amp;#187;',
+      :controller =&gt; 'timesheet', :action =&gt; 'calendar', :timesheet =&gt; next_params )
+    return prev_month + ' | ' + next_month
+  end
+
+  def rounded_box_for_number(css_class=nil)
+    concat &quot;&lt;div class='rounded_box #{css_class}'&gt;&lt;div&gt;&lt;div&gt;&quot;
+    yield
+    concat &quot;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&quot;
+  end
+
+  def css_class_for_timesheet_event(key)
+    array_entry = @timesheet.time_entries.assoc(key)
+    index = array_entry.nil? ? 0 : @timesheet.time_entries.index(array_entry)
+    &quot;hours#{index &gt; 11 ? 0 : index+1}&quot;
+  end
+
+  def rounded_box_for_total(key, reference, &amp;block)
+    if reference.instance_of?(Project)
+      css_class = css_class_for_timesheet_event(key)
+    elsif reference.instance_of?(Issue)
+      css_class = css_class_for_timesheet_event(key)
+    elsif reference.instance_of?(User)
+      css_class = css_class_for_timesheet_event(key)
+    else
+      css_class = ''
+    end
+    rounded_box_for_number(css_class, &amp;block)
+  end
+
+  # TODO sistemare css class in calendario
+  def rounded_box_for(entry, &amp;block)
+#    puts &quot;fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff&quot;
+#    p entry
+#    p @timesheet.time_entries
+#        array_entry = @timesheet.time_entries.assoc(entry)
+#    p array_entry
+#        rarray_entry = @timesheet.time_entries.rassoc(entry)
+#    p rarray_entry
+#    puts &quot;fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff&quot;
+#    if entry[:obj_ref].instance_of?(Project)
+#      css_class = css_class_for_timesheet_event(entry)
+#    elsif entry[:obj_ref].instance_of?(Issue)
+#      css_class = css_class_for_timesheet_event(entry)
+#    elsif entry[:obj_ref].instance_of?(User)
+#      css_class = css_class_for_timesheet_event(entry)
+#    else
+      css_class = ''
+#    end
+    rounded_box_for_number(css_class, &amp;block)
+  end
+
+  def link_to_entry(key, reference)
+    title = h(key)
+    if reference.instance_of?(Project)
+      link_to title, {:controller=&gt;'projects', :action=&gt;'show', :id=&gt;reference}, :title=&gt;h(reference.description)
+    elsif reference.instance_of?(Issue)
+      subject = h(reference.subject)
+      link_to(&quot;##{reference.id}&quot;, {:controller=&gt;'issues', :action=&gt;'show', :id=&gt;reference}, :title=&gt;subject) + &quot;: #{subject}&quot;
+    elsif reference.instance_of?(User)
+      link_to title, {:controller=&gt;'account', :action=&gt;'show', :id=&gt;reference}, :title=&gt;title
+    else
+      title
+    end
+  end
 end</diff>
      <filename>app/helpers/timesheet_calendar_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 class Timesheet
   attr_accessor :date_from, :date_to, :projects, :activities, :users, :allowed_projects, :period, :period_type,
-    :year, :month
+    :year, :month, :grand_total
 
   # Time entries on the Timesheet in the form of:
   #   project.name =&gt; {:logs =&gt; [time entries], :users =&gt; [users shown in logs] }
@@ -49,16 +49,6 @@ class Timesheet
       self.sort = :project
     end
     
-    self.date_from = options[:date_from] || Date.today.to_s
-    self.date_to = options[:date_to] || Date.today.to_s
-
-    if options[:period_type] &amp;&amp; ValidPeriodType.values.include?(options[:period_type].to_i)
-      self.period_type = options[:period_type].to_i
-    else
-      self.period_type = ValidPeriodType[:free_period]
-    end
-    self.period = options[:period] || nil
-
     if options[:year] and options[:year].to_i &gt; 1900
       self.year = options[:year].to_i
       if options[:month] and options[:month].to_i &gt; 0 and options[:month].to_i &lt; 13
@@ -69,6 +59,18 @@ class Timesheet
     today = Date.today
     self.month ||= today.month
     self.year ||= today.year
+
+    self.date_from = options[:date_from] || today.to_s
+    self.date_to = options[:date_to] || today.to_s
+
+    if options[:period_type] &amp;&amp; ValidPeriodType.values.include?(options[:period_type].to_i)
+      self.period_type = options[:period_type].to_i
+    else
+      self.period_type = ValidPeriodType[:free_period]
+    end
+    self.period = options[:period] || nil
+
+    self.grand_total = 0.0
   end
 
   # Gets all the time_entries for all the projects
@@ -87,7 +89,8 @@ class Timesheet
   end
 
   def period=(period)
-    return if self.period_type == Timesheet::ValidPeriodType[:free_period]
+    case self.period_type
+    when ValidPeriodType[:default]
     # Stolen from the TimelogController
     case period.to_s
     when 'today'
@@ -118,9 +121,50 @@ class Timesheet
     when 'all'
       self.date_from = self.date_to = nil
     end
+      if self.date_from
+        df = self.date_from.to_date
+        self.year = df.year
+        self.month = df.month
+      end
+    when ValidPeriodType[:calendar]
+      self.date_from = Date.civil(self.year, self.month, 1)
+      self.date_to = (self.date_from &gt;&gt; 1) - 1
+    else # default to ValidPeriodType[:free_period]
+      return
+    end
     self
   end
   
+  def fetch_calendar_time_entries
+    self.time_entries = { }
+    case self.sort
+    when :user
+      fetch_time_entries_by_user { |user, data| compute_totals(user, data) }
+    when :issue
+      fetch_time_entries_by_issue { |issue, data| compute_totals(issue, data) }
+    when :project
+      fetch_time_entries_by_project { |project, data| compute_totals(project, data) }
+    else
+      fetch_time_entries_by_project { |project, data| compute_totals(project, data) }
+    end
+    order_time_entries_by_total_hours
+  end
+
+  def to_param
+    params = { }
+    params[:date_from] = self.date_from.to_s unless self.date_from.blank?
+    params[:date_to] = self.date_to.to_s unless self.date_to.blank?
+    params[:projects] = self.projects.collect(&amp;:id) unless self.projects.blank?
+    params[:activities] = self.activities unless self.activities.blank?
+    params[:users] = self.users unless self.users.blank?
+    params[:sort] = self.sort.to_s unless self.sort.blank?
+    params[:period] = self.period.to_s unless self.period.blank?
+    params[:period_type] = self.period_type.to_s unless self.period_type.blank?
+    params[:year] = self.year.to_s unless self.year.blank?
+    params[:month] = self.month.to_s unless self.month.blank?
+    params
+  end
+
   protected
 
   def conditions(users)
@@ -282,4 +326,14 @@ class Timesheet
     end
   end
   
+  def compute_totals(reference, data)
+    ref_total = 0.0
+    data[:logs].each { |log| ref_total += log.hours } unless data[:logs].blank?
+    self.grand_total += ref_total
+    data.merge!({:total_hours=&gt;ref_total, :obj_ref=&gt;reference})
+  end
+
+  def order_time_entries_by_total_hours
+    self.time_entries = self.time_entries.sort_by{|obj| obj[1][:total_hours]}.reverse
+  end
 end</diff>
      <filename>app/models/timesheet.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,31 @@
 &lt;h3&gt;&lt;%= l(:timesheet_views) %&gt;&lt;/h3&gt;
 
 &lt;%= link_to l(:timesheet_calendar_view), { :controller =&gt; 'timesheet', :action =&gt; 'daily'} %&gt;&lt;br /&gt;
-&lt;%= link_to l(:timesheet_activity_view), { :controller =&gt; 'timesheet', :action =&gt; 'index'} %&gt;&lt;br /&gt;
\ No newline at end of file
+&lt;%= link_to l(:timesheet_activity_view), { :controller =&gt; 'timesheet', :action =&gt; 'index'} %&gt;&lt;br /&gt;
+
+&lt;% unless @timesheet.grand_total == 0 %&gt;
+  &lt;% unless @timesheet.time_entries.blank? %&gt;
+    &lt;h3&gt;&lt;%= l(:label_project_plural) %&gt;&lt;/h3&gt;
+    &lt;table class=&quot;total_table&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
+      &lt;tbody&gt;
+        &lt;% @timesheet.time_entries.each do |key, entry| -%&gt;
+          &lt;tr&gt;
+            &lt;td&gt;
+              &lt;% rounded_box_for_total key, entry[:obj_ref] do %&gt;
+                &lt;%= '%.1f' % entry[:total_hours] %&gt;
+              &lt;% end -%&gt;
+            &lt;/td&gt;
+            &lt;td class=&quot;group_total&quot;&gt;
+              &lt;%= link_to_entry(key, entry[:obj_ref]) %&gt;
+            &lt;/td&gt;
+          &lt;/tr&gt;
+        &lt;% end -%&gt;
+      &lt;/tbody&gt;
+    &lt;/table&gt;
+  &lt;% end -%&gt;
+
+  &lt;h3&gt;&lt;%= l(:label_spent_time) %&gt;&lt;/h3&gt;
+  &lt;% rounded_box_for_number('grand_total') do %&gt;
+    &lt;%= '%.1f' % @timesheet.grand_total %&gt;&amp;nbsp;&lt;%= l(:field_hours) %&gt;
+  &lt;% end -%&gt;
+&lt;% end -%&gt;
\ No newline at end of file</diff>
      <filename>app/views/timesheet/_sidebar.rhtml</filename>
    </modified>
    <modified>
      <diff>@@ -3,3 +3,114 @@
 div#timesheet-form p { padding:0px 10px; float:left; }
 div#timesheet-form p.buttons { clear:left; }
 div#timesheet-projects { margin-top: 15px; clear:left; }
+
+div#calendar-navigator {
+    text-align: right;
+    padding:10px;
+    margin: 0;
+}
+
+.hours12 { border-color: RGB(204,0,0); color: RGB(204,0,0); background-color: RGB(255,227,227); }
+.hours1 { border-color: RGB(236,112,0); color: RGB(236,112,0); background-color: RGB(255,240,225); }
+.hours2 { border-color: RGB(179,109,0); color: RGB(179,109,0); background-color: RGB(250,220,179); }
+.hours3 { border-color: RGB(171,139,0); color: RGB(171,139,0); background-color: RGB(243,231,179); }
+.hours4 { border-color: RGB(99,99,48); color: RGB(99,99,48); background-color: RGB(255,255,212); }
+.hours5 { border-color: RGB(100,153,44); color: RGB(100,153,44); background-color: RGB(249,255,239); }
+.hours6 { border-color: RGB(0,102,51); color: RGB(0,102,51); background-color: RGB(241,245,236); }
+.hours7 { border-color: RGB(90,105,134); color: RGB(90,105,134); background-color: RGB(222,229,242); }
+.hours8 { border-color: RGB(32,108,255); color: RGB(32,108,255); background-color: RGB(224,236,255); }
+.hours9 { border-color: RGB(0,0,204); color: RGB(0,0,204); background-color: RGB(223,226,255); }
+.hours10 { border-color: RGB(82,41,163); color: RGB(82,41,163); background-color: RGB(224,213,259); }
+.hours11 { border-color: RGB(133,79,97); color: RGB(133,79,97); background-color: RGB(253,233,222); }
+.hours0 { border-color: #666666; color: #666666; background-color: #e4e4e4; }
+.grand_total { border-color: black; color: black; background-color: white;}
+
+.rounded_box {
+    display:inline-block;
+    border-style:solid;
+    border-width:0 1px;
+}
+
+.rounded_box div {
+    position:relative;
+    top: -1px;
+    left: 0;
+    border-style:solid;
+    border-width:1px 0 0;
+}
+
+.rounded_box div div, table.total_table td.group_total {
+    text-align:center;
+    font-size:10px;
+    font-style:normal;
+    font-variant:normal;
+    font-weight:normal;
+    height:14px;
+    padding:2px 3px;
+}
+
+.rounded_box div div {
+    top: 2px;
+    border-style:solid;
+    border-width:0 0 1px;
+    min-width:16px;
+}
+
+table.total_table td.group_total {
+    overflow:visible;
+    text-align:left;
+    padding-left:5px;
+    width: 100%;
+}
+
+table.total_table {
+    padding:0;
+    margin:0;
+    width:100%;
+    padding-bottom:4px;
+}
+
+table.total_table td {
+    vertical-align: middle;
+}
+
+table.total_table .rounded_box {
+    display:block;
+}
+
+#sidebar .rounded_box div div {
+    padding-left:5px;
+    padding-right:5px;
+}
+
+table.cal .rounded_box {
+    margin:6px 2px 2px 0;
+    float: left;
+    font-size:10px;
+}
+
+table.cal table.progress {
+    margin-top:10px;
+    padding:0 4px;
+}
+
+table.cal table.progress tr {
+    height:1.2em;
+}
+
+table.cal p.pourcent {
+    display:block;
+    width:100%;
+    position:relative;
+    z-index:2;
+    top:-1.4em;
+    text-align: center;
+    font-size:0.85em;
+}
+
+div#timesheet-projects h3 .rounded_box {
+    display:inline-block;
+    margin-right:10px;
+    width:2.75em;
+}
+</diff>
      <filename>assets/stylesheets/timesheet.css</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>abe2b2d88d70cdd5fcbe7363bbd59b78de675030</id>
    </parent>
  </parents>
  <author>
    <name>Michele Franzin</name>
    <email>michele.franzin@gmail.com</email>
  </author>
  <url>http://github.com/michelefranzin/redmine-timesheet-plugin/commit/79588f19635da56e45e765549f1a368a0be07993</url>
  <id>79588f19635da56e45e765549f1a368a0be07993</id>
  <committed-date>2009-07-13T05:53:24-07:00</committed-date>
  <authored-date>2009-07-13T05:53:24-07:00</authored-date>
  <message>added calendar view with totals</message>
  <tree>f66371532ec0b0e11ac5816a7a9dc12d0c0ab5a9</tree>
  <committer>
    <name>Michele Franzin</name>
    <email>michele.franzin@gmail.com</email>
  </committer>
</commit>
