class Gantt
this file is part of manqod manqod is distributed under the CDDL licence the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
Constants
- Connecting
- Moving
- None
- Resolution
seconds/pixel,scale point distance,
time_format
, day0_format, name- Scrolling
Attributes
cursor_id[R]
day0[R]
dur_column[R]
gantt_holder[R]
group_color_column[R]
group_column[R]
max_coo[R]
max_time[R]
min_coo[R]
min_time[R]
partial_column[R]
percentage_column[R]
points[R]
rectangles[R]
res_idx[R]
scaler_format[R]
start_column[R]
start_editable[R]
successors_column[R]
successors_editable[R]
time_format[R]
widget[R]
Public Class Methods
new(gantt_holder)
click to toggle source
Calls superclass method
# File lib/ListHolder/GanttHolder/Gantt.rb, line 25 def initialize(gantt_holder) @gantt_holder=gantt_holder #hold start and end points here for which Scaler will need to draw header @points=Array.new @rectangles=Hash.new #time interval/pixel @min_time=nil @res_idx=(list.gtk_attribute("gantt_res_idx") || '2').to_i @day0=(list.gtk_attribute("gantt_day0") || 'false') == 'true' @scaler_format=if @day0 then list.gtk_attribute("gantt_day0_header_format") || "%d %b\n%H:%M" else list.gtk_attribute("gantt_header_format") || "%d %b\n%H:%M" end @time_format=list.gtk_attribute("gantt_time_format") || "%H:%M" super(Gtk::Adjustment.new(0,0,0,0,0,0),list.holder.list_scroller.vadjustment) set_resize_mode(Gtk::RESIZE_PARENT) add(Gtk::EventBox.new.add(@widget=Gtk::Fixed.new)) child.signal_connect("scroll-event"){|me,ev| zoom_in if ev.direction == Gdk::EventScroll::UP && ev.state.control_mask? zoom_out if ev.direction == Gdk::EventScroll::DOWN && ev.state.control_mask? } child.signal_connect("button-press-event"){|me,ev| case ev.button #right button dragging: editing successors/predecessors when 3 then unless (@successors_column && successors_editable) ewarn("no editable successors_column specified?") else if @start=rectangle?(ev.x,ev.y) #double # if ev.event_type == Gdk::Event::BUTTON2_PRESS # @start.set_new_successors(nil) # else @state = Connecting window.set_cursor(Gdk::Cursor.new(Gdk::Cursor::CROSS)) # end end end #left click: moving when 1 then @start=rectangle?(ev.x,ev.y) if start_editable && !@start.nil? && !@start.has_child? @state = Moving @move_shift=ev.x-@start.x1 window.set_cursor(Gdk::Cursor.new(Gdk::Cursor::HAND2)) end #middle click: panning when 2 then @state = Scrolling @scroll_x=ev.x @scroll_y=ev.y window.set_cursor(Gdk::Cursor.new(Gdk::Cursor::HAND1)) end clear # gantt_holder.scaler.clear false } child.signal_connect("button-release-event"){|me,ev| case @state when Connecting @motion=nil @end=rectangle?(ev.x,ev.y) @start.toggle_successor(@end) when Moving #moving finished @start.move_to(hadjustment.value+self.pointer[0]-@move_shift,true) @motion=nil when Scrolling end window.set_cursor(nil) @state = None clear false } child.signal_connect("motion-notify-event"){|me,ev| case @state when Connecting then @motion=[ev.x,ev.y] clear when Moving then @start.move_to(hadjustment.value+self.pointer[0]-@move_shift) @motion=[ev.x,ev.y] clear when Scrolling then px=@scroll_x - self.pointer[0] py=@scroll_y - self.pointer[1] px=hadjustment.lower if px < hadjustment.lower py=vadjustment.lower if py < hadjustment.lower px=hadjustment.upper - hadjustment.page_size if px > hadjustment.upper - hadjustment.page_size py=vadjustment.upper - vadjustment.page_size if py > vadjustment.upper - vadjustment.page_size hadjustment.value=px vadjustment.value=py clear end } #set footer height list.holder.signal_connect("size-allocate"){|me,alloc| h=list.holder.buttonholder.holder.allocation.height h+=list.holder.list_panel.allocation.height if list.holder.list_panel.visibility gantt_holder.footer.set_height_request(h) unless gantt_holder.footer.destroyed? false } #set gantt height list.holder.list_scroller.vadjustment.signal_connect("changed"){|vad| @widget.set_height_request(vad.upper) unless @widget.destroyed? false } @widget.signal_connect("expose-event"){|me,ev| cr=me.window.create_cairo_context.set_line_cap(Cairo::LineCap::ROUND) @rectangles.each{|rid,r| #draw rectangles, hilight the hovered on connecting r.draw(cr,(@start == r) || (@end == r) || (@motion && r.in_area?(@motion[0],@motion[1]))) } #draw arrows,verticals @rectangles.each{|rid,r| r.draw_arrow(cr).draw_verticals(cr) r.draw_hilight(cr) if @cursor_id == rid } #printing percentages @rectangles.each{|rid,r| r.print_percentage(cr) } if percentage_column #draw connecting line if @start && @state == Connecting && @motion cr.set_line_width(3).set_source_rgba(148.0/255,88.0/255,116.0/255,0.5).set_dash(100000) cr.move_to(@start.x,@start.y) cr.line_to(@motion[0],@motion[1]) cr.stroke end } signal_connect("destroy"){|me| list.delete_observer(self) } end
Public Instance Methods
clear()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 280 def clear @widget.queue_draw_area(0, 0, @widget.allocation.width, @widget.allocation.height) end
collisions(pr)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 265 def collisions(pr) cs=Array.new @rectangles.each_value{|r| #by goup items' maximum if group_column && r != pr && r.group == pr.group min=[pr.start,r.start].max max=[pr.start+pr.dur,r.start+r.dur].min cs.push([min,max]) if min<max end } cs end
create_rectangle(iter,level=0)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 214 def create_rectangle(iter,level=0) #crawl the tree recursively and create rectangles vi=!iter.nil? start=nil finish=nil height=nil percent=0 dursum=0 while vi r=Rectangle.new(self,iter) r.level=level start=r.start if start.nil? || start>r.start finish=r.finish if finish.nil? || finish<r.finish height=r.y1+r.height if height.nil? || height<r.height+r.y1 dursum+=r.dur percent+=r.dur.to_f * r.percentage/100.0 #calculate the current complete percentage of r @rectangles[r.iter_id]=r if iter.has_child? starts,finishs,percents,heights=create_rectangle(iter.first_child,level+1) r.set_height(heights-r.y1) unless heights-r.y1 == r.height height=r.y1+r.height if height.nil? || height<r.height+r.y1 #recalc height, since it changes by depth r.set_start(starts,false) unless starts == r.start r.set_duration(finishs-starts,false) unless finishs-starts == r.dur r.set_percentage(percents,true) unless percents == r.percentage end vi=iter.next! end [start,finish,if dursum==0 then 0 else (100.0*percent/dursum).to_i end,height] end
display_time(t)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 306 def display_time(t) s=Time.at(t).strftime(@time_format) end
list()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 283 def list gantt_holder.list end
min_for_rectangle(pr)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 254 def min_for_rectangle(pr) min=0 chmin=0 @rectangles.each_value{|r| #by goup items' maximum min=r.finish if group_column && r.group == pr.group && r.start<pr.start && pr.start<r.finish #children's maxmimum r.successors.each{|sid,s| chmin=r.partial_finish if s == pr && r.partial_finish>chmin } } [min,chmin].max end
model()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 286 def model list.list_model.data end
rectangle?(x,y)
click to toggle source
check if this rectangle contains the point @ x,y
# File lib/ListHolder/GanttHolder/Gantt.rb, line 245 def rectangle?(x,y) found=nil @rectangles.each_value{|r| if r.in_area?(x,y) && (found.nil? || found.level<r.level) found=r end } found end
rectangle_by_id?(rid)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 277 def rectangle_by_id?(rid) @rectangles[rid] end
res()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 289 def res Resolution[res_idx][0] end
res_name()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 309 def res_name Resolution[res_idx][4] end
scaler_step()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 292 def scaler_step if @scaler_format.include?("%H") then 60*24 elsif @scaler_format.include?("%d") then 60*60*24 elsif @scaler_format.include?("%W") then 60*60*24*7 else eerror("set gantt_header_format to a value which includes %W,%d or %H"); 60*24 end end
time_round_res(t)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 299 def time_round_res(t) Time.at(t.to_i).round(if @scaler_format.include?("%H") then "H" elsif @scaler_format.include?("%d") then "d" elsif @scaler_format.include?("%W") then "W" else "d" end) end
to_s()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 326 def to_s "Gantt of #{list}" end
update(notifier)
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 165 def update(notifier) if list.model && model && list.list_model.column_of_gantt_start && list.list_model.column_of_gantt_duration @start_column=list.list_model.column_of_gantt_start["model_col"].to_i if list.list_model.column_of_gantt_start @start_editable=list.list_model.column_of_gantt_start["editable"] if list.list_model.column_of_gantt_start @dur_column=list.list_model.column_of_gantt_duration["model_col"].to_i if list.list_model.column_of_gantt_duration @successors_column=list.list_model.column_of_gantt_successors["model_col"].to_i if list.list_model.column_of_gantt_successors @successors_editable=list.list_model.column_of_gantt_successors["editable"] if list.list_model.column_of_gantt_successors @group_column=list.list_model.column_of_gantt_group["model_col"].to_i if list.list_model.column_of_gantt_group @partial_column=list.list_model.column_of_gantt_partial["model_col"].to_i if list.list_model.column_of_gantt_partial @group_color_column=list.list_model.column_of_gantt_group_color["model_col"].to_i if list.list_model.column_of_gantt_group_color @percentage_column=list.list_model.column_of_gantt_percentage["model_col"].to_i if list.list_model.column_of_gantt_percentage #set up rectangles @rectangles.clear create_rectangle(model.iter_first) #visible iters @min_time=@max_time=nil @rectangles.each_value{|r| @min_time=r.start if @min_time.nil? || @min_time>r.start @max_time=r.finish if @max_time.nil? || @max_time<r.finish } @min_time=0 if @min_time.nil? @max_time=0 if @max_time.nil? #extend min_time and max_time to fit resolution @min_time=time_round_res(@min_time).to_i @max_time=time_round_res(@max_time + scaler_step).to_i @points.clear @min_coo=if day0 then 0 else @min_time/res||0 end @max_coo=@max_time/res||0 #set our maximum width @widget.set_width_request(@max_coo-@min_coo) @cursor_id=list.get_cursor_id @rectangles.each_pair{|rid,r| r.set_gantt_min_x(@min_coo) #center on selected hadjustment.clamp_page(r.x1-hadjustment.page_size/3,r.x2+hadjustment.page_size/3) if @cursor_id == rid #set up successors r.init_successors if successors_column #set up scaler points time_round_res(r.start).to_i.step(time_round_res(r.finish+scaler_step).to_i,scaler_step){|i| @points.push(time_round_res(i).to_i)}} @points=@points.uniq.sort! #redraw gantt_holder.scaler.clear show_all clear end end
zoom_in()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 312 def zoom_in unless @res_idx==1 @res_idx-=1 gantt_holder.footer.set_res_label update(self) end end
zoom_out()
click to toggle source
# File lib/ListHolder/GanttHolder/Gantt.rb, line 319 def zoom_out unless @res_idx==Resolution.size @res_idx+=1 gantt_holder.footer.set_res_label update(self) end end