001 // This file is part of the program FRYSK. 002 // 003 // Copyright 2005, Red Hat Inc. 004 // 005 // FRYSK is free software; you can redistribute it and/or modify it 006 // under the terms of the GNU General Public License as published by 007 // the Free Software Foundation; version 2 of the License. 008 // 009 // FRYSK is distributed in the hope that it will be useful, but 010 // WITHOUT ANY WARRANTY; without even the implied warranty of 011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 // General Public License for more details. 013 // type filter text 014 // You should have received a copy of the GNU General Public License 015 // along with FRYSK; if not, write to the Free Software Foundation, 016 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 017 // 018 // In addition, as a special exception, Red Hat, Inc. gives You the 019 // additional right to link the code of FRYSK with code not covered 020 // under the GNU General Public License ("Non-GPL Code") and to 021 // distribute linked combinations including the two, subject to the 022 // limitations in this paragraph. Non-GPL Code permitted under this 023 // exception must only link to the code of FRYSK through those well 024 // defined interfaces identified in the file named EXCEPTION found in 025 // the source code files (the "Approved Interfaces"). The files of 026 // Non-GPL Code may instantiate templates or use macros or inline 027 // functions from the Approved Interfaces without causing the 028 // resulting work to be covered by the GNU General Public 029 // License. Only Red Hat, Inc. may make changes or additions to the 030 // list of Approved Interfaces. You must obey the GNU General Public 031 // License in all respects for all of the FRYSK code and other code 032 // used in conjunction with FRYSK except the Non-GPL Code covered by 033 // this exception. If you modify this file, you may extend this 034 // exception to your version of the file, but you are not obligated to 035 // do so. If you do not wish to provide this exception without 036 // modification, you must delete this exception statement from your 037 // version and license this file solely under the GPL without 038 // exception. 039 040 package frysk.gui.monitor.eventviewer; 041 042 043 import java.util.Iterator; 044 import java.util.Observable; 045 import java.util.Observer; 046 047 import org.freedesktop.cairo.Point; 048 import org.gnu.gdk.Color; 049 import org.gnu.gdk.EventMask; 050 import org.gnu.gdk.GdkCairo; 051 import org.gnu.gtk.Adjustment; 052 import org.gnu.gtk.EventBox; 053 import org.gnu.gtk.HBox; 054 import org.gnu.gtk.Justification; 055 import org.gnu.gtk.Label; 056 import org.gnu.gtk.SizeGroup; 057 import org.gnu.gtk.SizeGroupMode; 058 import org.gnu.gtk.StateType; 059 import org.gnu.gtk.VBox; 060 import org.gnu.gtk.Viewport; 061 import org.gnu.gtk.Widget; 062 import org.gnu.gtk.event.ExposeEvent; 063 import org.gnu.gtk.event.ExposeListener; 064 import org.gnu.gtk.event.MouseEvent; 065 import org.gnu.gtk.event.MouseListener; 066 067 import com.redhat.ftk.CustomAtkObject; 068 import com.redhat.ftk.CustomDrawingArea; 069 070 import frysk.gui.monitor.GuiObservable; 071 import frysk.gui.srcwin.SourceWindowFactory; 072 073 public abstract class TimeLine 074 extends HBox implements MouseListener 075 { 076 077 public final GuiObservable selected; 078 public final GuiObservable unSelected; 079 080 static int eventSpacing = 30; 081 082 private static SizeGroup labelsSizeGroup = new SizeGroup(SizeGroupMode.HORIZONTAL); 083 private static SizeGroup drawingAreaSizeGroup = new SizeGroup(SizeGroupMode.HORIZONTAL); 084 085 private static final int MINIMUM_HEIGHT = 15; 086 private static int MINIMUM_WIDTH = 0 ; 087 088 String labelString; 089 String name; 090 091 private Viewport viewport; 092 private boolean isSelected; 093 094 private boolean isDead; 095 Label label; 096 097 int startIndex = 0; 098 int endIndex; 099 100 protected static Color SELECTED_COLOR = new Color(55535, 55535, 55535); 101 private static Color UNSELECTED_COLOR = Color.WHITE; 102 103 public TimeLine(String name, TimeLineSelectionManager timeLineSelectionManager){ 104 super(false,0); 105 106 this.selected = new GuiObservable(); 107 this.unSelected = new GuiObservable(); 108 109 this.setBorderWidth(0); 110 111 this.name = name; 112 this.labelString = ""; 113 114 label = new Label(name); 115 label.setAlignment(0.4,0.5); 116 label.setJustification(Justification.RIGHT); 117 118 EventBox labelEventBox = new EventBox(); 119 labelEventBox.add(label); 120 label.getParent().setBackgroundColor(StateType.NORMAL, UNSELECTED_COLOR); 121 122 labelEventBox.addListener((MouseListener)this); 123 this.addListener((MouseListener)this); 124 Viewport labeViewport = new Viewport(null,null); 125 labeViewport.add(labelEventBox); 126 // labeViewport.setShadowType(ShadowType.NONE); 127 addToLabelsSizeGroup(label); 128 129 final TimeLineDrawingArea drawingArea = getTimeLineDrawingArea(); 130 131 viewport = new Viewport(null,null); 132 viewport.add(drawingArea); 133 viewport.setMinimumSize(0, drawingArea.getMinimumHeight()); 134 // viewport.setShadowType(ShadowType.NONE); 135 136 VBox vBox = new VBox(false,0); 137 138 this.packStart(labeViewport, false, false, 0); 139 this.packStart(viewport,true,true,0); 140 this.packEnd(vBox, false, false, 0); 141 142 timeLineSelectionManager.addTimeLine(this); 143 144 EventManager.theManager.getEventsList().itemAdded.addObserver(redrawObserver); 145 } 146 147 public void setStartIdnex(int index){ 148 this.startIndex = index; 149 } 150 151 public void setEndIndex(int index){ 152 this.endIndex = index; 153 } 154 155 public void setHAdjustment(Adjustment adjustment){ 156 this.viewport.setHAdjustment(adjustment); 157 } 158 159 protected TimeLineDrawingArea getTimeLineDrawingArea(){ 160 return new TimeLineDrawingArea(); 161 } 162 163 public void setName(String name){ 164 this.name = name; 165 this.label.setMarkup(name + " "+ this.labelString); 166 } 167 168 protected class TimeLineDrawingArea extends CustomDrawingArea implements ExposeListener, MouseListener{ 169 170 public TimeLineDrawingArea () 171 { 172 TimeLine.addToDrawingAreaSizeGroup(this); 173 174 CustomAtkObject atkObject = new CustomAtkObject(this); 175 176 atkObject.setName(name+" TimeLine"); 177 atkObject.setDescription("TimeLine"); 178 179 this.setAcessible(atkObject); 180 181 182 this.addListener((ExposeListener)this); 183 this.addListener((MouseListener) this); 184 this.setEvents(EventMask.ALL_EVENTS_MASK); 185 186 this.setMinimumSize(MINIMUM_WIDTH , MINIMUM_HEIGHT); 187 } 188 189 public int getMinimumHeight () 190 { 191 return MINIMUM_HEIGHT; 192 } 193 194 /** 195 * Given x and y coordinates returns the Event which 196 * has been drawn there. 197 */ 198 private Event xy2Event(double x, double y){ 199 int index = (int) ((x)/(Event.getWidth() + eventSpacing)); 200 return EventManager.theManager.eventAtIndex(index); 201 } 202 203 public boolean mouseEvent (MouseEvent mouseEvent) 204 { 205 if(mouseEvent.isOfType(MouseEvent.Type.BUTTON_PRESS)){ 206 Event event = this.xy2Event(mouseEvent.getX(), mouseEvent.getY()); 207 if(event != null && ownsEvent(event)){ 208 event.select(); 209 } 210 } 211 212 if(mouseEvent.getClickType() == MouseEvent.DOUBLE_CLICK && mouseEvent.isOfType(MouseEvent.Type.BUTTON_PRESS)){ 213 Event event = this.xy2Event(mouseEvent.getX(), mouseEvent.getY()); 214 if(event != null && event.getStackFrame()!=null && ownsEvent(event)){ 215 SourceWindowFactory.createSourceWindow(event.getStackFrame()); 216 return true; 217 } 218 } 219 return false; 220 } 221 222 public boolean exposeEvent(ExposeEvent exposeEvent) { 223 // if(exposeEvent.isOfType(ExposeEvent.Type.NO_EXPOSE) || !exposeEvent.getWindow().equals(this.getWindow())) 224 // return false; 225 226 GdkCairo cairo = new GdkCairo(this.getWindow()); 227 228 int x = 0; 229 int y = 0; 230 int w = this.getWindow().getWidth(); 231 int h = exposeEvent.getArea().getHeight(); 232 233 // White background 234 if(isSelected){ 235 cairo.setSourceColor(SELECTED_COLOR); 236 }else{ 237 cairo.setSourceColor(UNSELECTED_COLOR); 238 } 239 240 cairo.rectangle(new Point(x,y), new Point(w, this.getWindow().getHeight())); 241 cairo.fill(); 242 243 244 cairo.setSourceColor(SELECTED_COLOR); 245 cairo.rectangle(new Point(x,y+h), new Point(w,y+h-1)); 246 cairo.fill(); 247 248 // draw events 249 Iterator iterator = EventManager.theManager.getEventsList().iterator(); 250 251 int eventX = 0; 252 int eventY = 0; 253 254 while (iterator.hasNext()) 255 { 256 Event event = (Event) iterator.next(); 257 258 if(TimeLine.this.ownsEvent(event)){ 259 eventX = x + eventSpacing/2 + (event.getIndex())*(Event.getWidth() + eventSpacing); 260 eventY = y + h - Event.getHeight(); 261 event.setXY(eventX, eventY); 262 event.draw(cairo); 263 } 264 } 265 266 if(eventX >= w){ 267 MINIMUM_WIDTH = w + MINIMUM_HEIGHT; 268 //this.setMinimumSize(MINIMUM_WIDTH , MINIMUM_HEIGHT); 269 } 270 271 if(isDead){ 272 // White background 273 cairo.setSourceRGBA(1,1,1, 0.5); 274 cairo.rectangle(new Point(x,y), new Point(w, this.getWindow().getHeight())); 275 cairo.fill(); 276 } 277 278 this.setMinimumSize(MINIMUM_WIDTH , MINIMUM_HEIGHT); 279 280 return false; 281 } 282 } 283 284 public boolean mouseEvent(MouseEvent event){ 285 if(event.isOfType(MouseEvent.Type.BUTTON_PRESS)){ 286 this.select(); 287 } 288 289 return false; 290 } 291 /** 292 * Returns wether this time line is associated with the given 293 * event 294 * @param event the event to be checked 295 * @return true of the given event is associated with this TimeLine 296 * false otherwise. 297 */ 298 public abstract boolean ownsEvent(Event event); 299 300 public void select(){ 301 this.isSelected = true; 302 this.label.getParent().setBackgroundColor(StateType.NORMAL, SELECTED_COLOR); 303 this.selected.notifyObservers(); 304 this.draw(); 305 } 306 307 public void unselect(){ 308 this.isSelected = false; 309 this.label.getParent().setBackgroundColor(StateType.NORMAL, UNSELECTED_COLOR); 310 this.unSelected.notifyObservers(); 311 this.draw(); 312 } 313 314 public boolean isSelected(){ 315 return this.isSelected; 316 } 317 318 public void timeLineDead(){ 319 this.isDead = true; 320 321 int grayFactor = 3; 322 this.label.setForegroundColor(StateType.NORMAL, new Color(65535/grayFactor, 65535/grayFactor, 65535/grayFactor)); 323 this.labelString = this.labelString + "\n<i>terminated</i>"; 324 this.label.setMarkup(name + " " + labelString); 325 } 326 327 public static void addToLabelsSizeGroup(Widget widget){ 328 labelsSizeGroup.addWidget(widget); 329 } 330 331 public static void addToDrawingAreaSizeGroup(Widget widget){ 332 drawingAreaSizeGroup.addWidget(widget); 333 } 334 335 private Observer redrawObserver = new Observer(){ 336 private int count; 337 338 public void update (Observable observable, Object arg) 339 { 340 if(count++ == 2){ 341 draw(); 342 count=0; 343 } 344 } 345 }; 346 347 protected void finalize () throws Throwable 348 { 349 EventManager.theManager.getEventsList().itemAdded.deleteObserver(redrawObserver); 350 super.finalize(); 351 } 352 353 }