Community
Participate
Working Groups
I am trying to print out a figure using Draw2D. I have the code working under Windows XP. It is a standalone application using SWT (3062) and the Draw2D jar (3.0.0). The code is below (it's sloppy, but this is just a prototyping application to make sure everything works). The interesting part is: PrintDialog dialog = new PrintDialog(this.getShell(), SWT.NULL); Printer printer = new Printer(dialog.open()); PrintFigureOperation pfo = new PrintFigureOperation(printer, c); pfo.run("TEST PRINT JOB"); This run method "hangs" the application. I've tried debugging it and it looks like it's just printing really slowly down int the JNI code, but I'm not sure about that. Anyway, I haven't gotten it to print anything yet on Mac OS X even after wait for about 10 minutes (on a really simple figure) so I know something is wrong there. Let me know if I'm doing something wrong with the code ... File NewSWTApp.java import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.SWT; import org.eclipse.swt.printing.*; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.draw2d.*; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Scale; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.layout.RowData; import org.eclipse.draw2d.parts.*; import org.eclipse.draw2d.geometry.*; /**import org. * This code was generated using CloudGarden's Jigloo * SWT/Swing GUI Builder, which is free for non-commercial * use. If Jigloo is being used commercially (ie, by a * for-profit company or business) then you should purchase * a license - please visit www.cloudgarden.com for details. */ public class NewSWTApp extends org.eclipse.swt.widgets.Composite { private Scale scale1; private Button button1; private Canvas thumbnailCanvas; private Combo scaleCombo; private Canvas canvas; private Composite composite1; private SashForm sashForm1; private MenuItem aboutMenuItem; private MenuItem contentsMenuItem; private Menu helpMenu; private MenuItem helpMenuItem; private MenuItem exitMenuItem; private MenuItem closeFileMenuItem; private MenuItem saveFileMenuItem; private MenuItem newFileMenuItem; private MenuItem openFileMenuItem; private Menu fileMenu; private MenuItem fileMenuItem; private Menu menu1; private ScalableLayeredPane p = null; private ScrollableThumbnail t = null; private IFigure c = null; public NewSWTApp(Composite parent, int style) { super(parent, style); initGUI(); } /** * Initializes the GUI. * Auto-generated code - any changes you make will disappear. */ public void initGUI(){ try { preInitGUI(); sashForm1 = new SashForm(this,SWT.NULL); canvas = new Canvas(sashForm1,SWT.NULL); composite1 = new Composite(sashForm1,SWT.NULL); scaleCombo = new Combo(composite1,SWT.NULL); thumbnailCanvas = new Canvas(composite1,SWT.NULL); button1 = new Button(composite1,SWT.PUSH| SWT.CENTER); scale1 = new Scale(composite1,SWT.NULL); this.setSize(new org.eclipse.swt.graphics.Point(605,335)); final Color NewSWTAppbackground = new Color(Display.getDefault(),128,128,128); this.setBackground(NewSWTAppbackground); FormData sashForm1LData = new FormData(); sashForm1LData.height = 315; sashForm1LData.width = 605; sashForm1LData.left = new FormAttachment(0, 1000, 0); sashForm1LData.right = new FormAttachment(1000, 1000, 0); sashForm1LData.top = new FormAttachment(0, 1000, 0); sashForm1LData.bottom = new FormAttachment(1000, 1000, -20); sashForm1.setLayoutData(sashForm1LData); sashForm1.setSize(new org.eclipse.swt.graphics.Point(605,295)); canvas.setSize(new org.eclipse.swt.graphics.Point(298,295)); final Color canvasbackground = new Color(Display.getDefault(),255,255,255); canvas.setBackground(canvasbackground); composite1.setSize(new org.eclipse.swt.graphics.Point(304,295)); FormData scaleComboLData = new FormData(); scaleComboLData.height = 20; scaleComboLData.width = 290; scaleComboLData.left = new FormAttachment(0, 1000, 5); scaleComboLData.right = new FormAttachment(1000, 1000, -9); scaleComboLData.top = new FormAttachment(0, 1000, 5); scaleComboLData.bottom = new FormAttachment(0, 1000, 25); scaleCombo.setLayoutData(scaleComboLData); scaleCombo.setSize(new org.eclipse.swt.graphics.Point(290,20)); scaleCombo.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { scaleComboWidgetSelected(evt); } }); FormData thumbnailCanvasLData = new FormData(); thumbnailCanvasLData.height = 115; thumbnailCanvasLData.width = 290; thumbnailCanvasLData.left = new FormAttachment(0, 1000, 5); thumbnailCanvasLData.right = new FormAttachment(1000, 1000, -9); thumbnailCanvasLData.top = new FormAttachment(0, 1000, 35); thumbnailCanvasLData.bottom = new FormAttachment(0, 1000, 150); thumbnailCanvas.setLayoutData(thumbnailCanvasLData); thumbnailCanvas.setSize(new org.eclipse.swt.graphics.Point(290,115)); FormData button1LData = new FormData(); button1LData.height = 36; button1LData.width = 286; button1LData.left = new FormAttachment(0, 1000, 5); button1LData.right = new FormAttachment(1000, 1000, -9); button1LData.top = new FormAttachment(0, 1000, 155); button1LData.bottom = new FormAttachment(0, 1000, 195); button1.setLayoutData(button1LData); button1.setText("button1"); button1.setSize(new org.eclipse.swt.graphics.Point(286,36)); button1.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { button1WidgetSelected(evt); } }); FormData scale1LData = new FormData(); scale1LData.height = 20; scale1LData.width = 290; scale1LData.left = new FormAttachment(0, 1000, 5); scale1LData.right = new FormAttachment(1000, 1000, -9); scale1LData.top = new FormAttachment(0, 1000, 205); scale1LData.bottom = new FormAttachment(0, 1000, 225); scale1.setLayoutData(scale1LData); scale1.setMaximum(800); scale1.setMinimum(25); scale1.setSize(new org.eclipse.swt.graphics.Point(290,20)); scale1.addSelectionListener( new SelectionAdapter() { public void widgetSelected(SelectionEvent evt) { scale1WidgetSelected(evt); } }); scale1.addMouseMoveListener( new MouseMoveListener() { public void mouseMove(MouseEvent evt) { scale1MouseMove(evt); } }); FormLayout composite1Layout = new FormLayout(); composite1.setLayout(composite1Layout); composite1Layout.marginWidth = 0; composite1Layout.marginHeight = 0; composite1Layout.spacing = 0; composite1.layout(); FormLayout thisLayout = new FormLayout(); this.setLayout(thisLayout); thisLayout.marginWidth = 0; thisLayout.marginHeight = 0; thisLayout.spacing = 0; this.layout(); menu1 = new Menu(getShell(),SWT.BAR); fileMenuItem = new MenuItem(menu1,SWT.CASCADE); fileMenu = new Menu(fileMenuItem); openFileMenuItem = new MenuItem(fileMenu,SWT.CASCADE); newFileMenuItem = new MenuItem(fileMenu,SWT.CASCADE); saveFileMenuItem = new MenuItem(fileMenu,SWT.CASCADE); closeFileMenuItem = new MenuItem(fileMenu,SWT.CASCADE); exitMenuItem = new MenuItem(fileMenu,SWT.CASCADE); helpMenuItem = new MenuItem(menu1,SWT.CASCADE); helpMenu = new Menu(helpMenuItem); contentsMenuItem = new MenuItem(helpMenu,SWT.CASCADE); aboutMenuItem = new MenuItem(helpMenu,SWT.CASCADE); getShell().setMenuBar(menu1); fileMenuItem.setText("File"); fileMenuItem.setMenu(fileMenu); openFileMenuItem.setText("Open"); newFileMenuItem.setText("New"); saveFileMenuItem.setText("Save"); closeFileMenuItem.setText("Close"); exitMenuItem.setText("Exit"); helpMenuItem.setText("Help"); helpMenuItem.setMenu(helpMenu); contentsMenuItem.setText("Contents"); aboutMenuItem.setText("About"); addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { NewSWTAppbackground.dispose(); canvasbackground.dispose(); } }); postInitGUI(); } catch (Exception e) { e.printStackTrace(); } } /** Add your pre-init code in here */ public void preInitGUI(){ } /** Add your post-init code in here */ public void postInitGUI(){ scaleCombo.add("0.2"); scaleCombo.add("0.4"); scaleCombo.add("0.6"); scaleCombo.add("0.8"); scaleCombo.add("1.0"); scaleCombo.add("1.5"); scaleCombo.add("2.0"); scaleCombo.add("4.0"); scaleCombo.add("8.0"); LightweightSystem lws = new LightweightSystem(canvas); final Layer contents = new Layer(); final ScalableLayeredPane pane = new ScalableLayeredPane(); final ScrollPane scroll = new ScrollPane(); pane.add(contents, "1", 0); scroll.setContents(pane); final XYLayout layout = new XYLayout(); contents.setLayoutManager(layout); c = contents; p = pane; IFigure old = null; int row = 0; int col = 0; for (int i = 0; i < 100; i++) { if (i % 10 == 0) System.out.println(i); IFigure btn = new WindowFrame(); /* final IFigure btn = new Button("TEST" + i); btn.setBorder(new FrameBorder("WINDOW" + i)); btn.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent arg0) { // System.out.println(arg0.x + " " + arg0.y); // btn.setBounds(new org.eclipse.draw2d.geometry.Rectangle( // arg0.x, arg0.y, btn.getBounds().width, btn.getBounds().height)); contents.setConstraint(btn, new org.eclipse.draw2d.geometry.Rectangle( arg0.x - 10, arg0.y - 10, btn.getBounds().width, btn.getBounds().height)); // btn.invalidate(); // contents.invalidate(); } public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseHover(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseMoved(MouseEvent arg0) { //System.out.println("MOVED: " + arg0.x + " " + arg0.y); } }); */ btn.setOpaque(true); layout.setConstraint(btn, new org.eclipse.draw2d.geometry.Rectangle(200 * row, 200 * col,-1,-1)); contents.add(btn); if (old != null) { PolylineConnection conn = new PolylineConnection(); ChopboxAnchor srcAnchor = new ChopboxAnchor(btn); ChopboxAnchor dstAnchor = new ChopboxAnchor(old); conn.setSourceAnchor(srcAnchor); conn.setTargetAnchor(dstAnchor); contents.add(conn); } old = btn; row++; if (row > 10) { row = 0; col++; } } LightweightSystem tlws = new LightweightSystem(thumbnailCanvas); ScrollableThumbnail thumb = new ScrollableThumbnail(); thumb.setViewport(scroll.getViewport()); thumb.setSource(contents); tlws.setContents(thumb); t = thumb; lws.setContents(scroll); } /** Auto-generated mainForm method */ public static void main(String[] args){ showGUI(); } /** * This static method creates a new instance of this class and shows * it inside a new Shell. * * It is a convenience method for showing the GUI, but it can be * copied and used as a basis for your own code. * * It is auto-generated code - the body of this method will be * re-generated after any changes are made to the GUI. * However, if you delete this method it will not be re-created. */ public static void showGUI(){ try { Display display = Display.getDefault(); Shell shell = new Shell(display); NewSWTApp inst = new NewSWTApp(shell, SWT.NULL); shell.setLayout(new org.eclipse.swt.layout.FillLayout()); Rectangle shellBounds = shell.computeTrim(0,0,605,315); shell.setSize(shellBounds.width, shellBounds.height); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } } catch (Exception e) { e.printStackTrace(); } } /** Auto-generated event handler method */ protected void scaleComboWidgetSelected(SelectionEvent evt){ try { System.out.println("TEST"); double scale = Double.parseDouble(scaleCombo.getText()); p.setScale(scale); p.invalidate(); } catch (Exception e) { e.printStackTrace(); } } /** Auto-generated event handler method */ protected void button1WidgetSelected(SelectionEvent evt){ PrintDialog dialog = new PrintDialog(this.getShell(), SWT.NULL); Printer printer = new Printer(dialog.open()); PrintFigureOperation pfo = new PrintFigureOperation(printer, c); pfo.run("TEST PRINT JOB"); } /** Auto-generated event handler method */ protected void scale1WidgetSelected(SelectionEvent evt){ double s = scale1.getSelection() / 100f; p.setScale(s); t.setDirty(true); t.invalidate(); //t.setDirty(true); scaleCombo.setText(String.valueOf(s)); } /** Auto-generated event handler method */ protected void scale1MouseMove(MouseEvent evt){ double s = scale1.getSelection() / 100f; scaleCombo.setText(String.valueOf(s)); } } File WindowFrame.java import org.eclipse.draw2d.Clickable; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FrameBorder; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.MouseEvent; import org.eclipse.draw2d.MouseMotionListener; import org.eclipse.draw2d.*; /* * Created on Dec 15, 2004 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ /** * @author ncallender * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class WindowFrame extends Clickable { public WindowFrame() { super(); ToolbarLayout layout = new ToolbarLayout(false); Label label1 = new Label("Line 1"); Label label2 = new Label("Line 2"); Label label3 = new Label("Line 3"); Label label4 = new Label("Line 4"); setLayoutManager(layout); add(label1); add(label2); add(label3); add(label4); label1.setBorder(new LineBorder(1)); label2.setBorder(new LineBorder(1)); label3.setBorder(new LineBorder(1)); label4.setBorder(new LineBorder(1)); FrameBorder border = new FrameBorder("ASF"); setBorder(border); final Figure me = this; addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent arg0) { getParent().setConstraint(me, new org.eclipse.draw2d.geometry.Rectangle( arg0.x - 10, arg0.y - 10, me.getBounds().width, me.getBounds().height)); } public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseHover(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseMoved(MouseEvent arg0) { // TODO Auto-generated method stub } }); } }
This might be an SWT problem. Although printing is not supported on all platforms, I believe Mac OSX is supported. Can you successfully run the SWT printing snippet? http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclip se/swt/snippets/Snippet132.java?rev=HEAD&content-type=text/vnd.viewcvs-markup
Yes, I can run the SWT printing snippet. I just downloaded the code, compiled and ran the application and the output was correct. I also modified the snippet to use the same PrinterData settings that I have been using in the Draw2D application: PrintDialog dialog = new PrintDialog(shell, SWT.NULL); PrinterData data = dialog.open(); This also produced the correct output. So, SWT is working, but I'm wondering if Draw2D is either not drawing on the right GC or I'm not setting up the GC correctly (or some resources are on the wrong GC). However, the sample code is pretty basic as far as the Draw2D functionality is concerned.
Whatever draw2d is doing, it works fine on win32. You should try to reduce the snippet to its very basic elements. Perhaps remove figures until the problem stops happening. If you remove everything and the problem still occurs, it be related to simply drawing an Image. I'd like to help but I don't have any printers installed on my Mac.
Please try running the following test case and append the results here: public class Bug81467 { public static void main(String[] args) { Font font = new Font(null, "Helvetica", 12, 0); Printer printer = new Printer(); printer.startJob("bugzilla 81467"); GC gc = new GC(printer); SWTGraphics graphics = new SWTGraphics(gc); PrinterGraphics printGraphics = new PrinterGraphics(graphics, printer); printGraphics.scale((double)printer.getDPI().x / Display.getDefault ().getDPI().x); printGraphics.setFont(font); printGraphics.drawString("Hello world", 50, 50); printGraphics.dispose(); graphics.dispose(); gc.dispose(); printer.endJob(); printer.dispose(); font.dispose(); } }
I am having trouble printing a GEF editor's on Mac OS X 10.4.5. The symptom is an infinite loop that I traced down to the clip rect having zero extent. I believe this bug is related. Trying Randy Hudson's test case (see comment #4) I get a single blank page out of the printer.
some additional information. If I modify Randy's test case (see comment #4) thusly, ... GC gc = new GC(printer); SWTGraphics graphics = new SWTGraphics(gc); graphics.setClip(new Rectangle(0,0,500, 500)); // FORCE a clip rect PrinterGraphics printGraphics = new PrinterGraphics(graphics, printer); ... Then the test produces the expected result ("Hello World"). The relevant code in SWTGraphics.init() is: currentState.relativeClip = new RectangleClipping(gc.getClipping()); GC.getClipping() is returning a rect {0,0,0,0} I can't tell without a lot more study whether the fault lies in the GC class for Mac OS, in SWTGraphics (or somewhere else). I suspect GC.getClipping() is not adhering to its contract as laid out in the method comment: /** * Returns the bounding rectangle of the receiver's clipping * region. If no clipping region is set, the return value * will be a rectangle which covers the entire bounds of the * object the receiver is drawing on. * * @return the bounding rectangle of the clipping region In this case no clipping region is set but the returned rectangle is clearly not covering the bounds of the printable area.
Reopening. Sounds like we almost have a test snippet here. SWT folks, any chance a printer fresh GC has empty clip rect on the Mac?
Mac was changed to use HIView for 3.2. Could this be causing the trouble? You can go and hammer a constant in org.eclipse.swt.internal.carbon.OS to test out this theory?
Eric, please try removing Draw2d from the snippet: Printer printer = new Printer(); printer.startJob("bugzilla 81467"); GC gc = new GC(printer); System.out.println(gc.getClipping()); gc.dispose(); printer.dispose(); If getClipping() is returning an empty Rectangle, I think this should moved to SWT. But, the infinite loop is interesting. Is your code in the loop, or is it 100% draw2d code looping? A partial stack trace would help.
Regarding comment #8 My tests have been on Eclipse 3.1.2 not 3.2 so changes in the latter version did not bring this about. To what constant in org.eclipse.swt.internal.carbon.OS are you referring?
Regarding comment #9 Randy's draw2D-free snippet prints: Rectangle {0, 0, 0, 0} i.e. the clip rect has zero extent.
Regarding the second part of comment #9 The infinite loop is all in draw2D code: org.eclipse.draw2D.PrintFigureOperation.printPages() protected void printPages() { Graphics graphics = getFreshPrinterGraphics(); IFigure figure = getPrintSource(); setupPrinterGraphicsFor(graphics, figure); Rectangle bounds = figure.getBounds(); int x = bounds.x, y = bounds.y; Rectangle clipRect = new Rectangle(); while (y < bounds.y + bounds.height) { while (x < bounds.x + bounds.width) { // <<<----- (0) graphics.pushState(); getPrinter().startPage(); graphics.translate(-x, -y); graphics.getClip(clipRect); // <<<------ (1) this always sets clipRect to {0,0,0,0} clipRect.setLocation(x, y); graphics.clipRect(clipRect); figure.paint(graphics); getPrinter().endPage(); graphics.popState(); x += clipRect.width; // <<<------- (2) clipRect.width is always 0 } x = bounds.x; y += clipRect.height; } } (1) always sets clipRect to {0,0,0,0} This is because the underlying SWTGraphics has a currentState.relativeClip which is {0,0,0,0} in turn it has this zero size clip due to the SWTGraphics.init() doing currentState.relativeClip = new RectangleClipping(gc.getClipping()); where the GC.getClipping() has returned {0,0,0,0} (2) x increments by zero since the clipRect width is zero. Therefore the loop (0) never exits. For what it's worth, I looked at how the StyledText prints (because printing of, for example, Java code works on OS X). In this case the bounds of the printer are derived from org.eclipse.swt.printing.Printer.getClientArea() instead of from the clipRect of the printer GC. This yields a Rectangle of non-zero size.
This clip rect thing looks like our bug.
Changing Severity since there are several workarounds. One workaround would be to override setupPrinterGraphics to set the clipRect to the Printer's clientArea, as StyledText is doing.
What is the best workaround to use on Mac OS to get printing from GEF working?
CAR, can you check out the clip rect bug?
Fixed > 20070416. Will be in tomorrow's I-build. The Printer object now saves the page bounds in the GCData, so that the getClipping methods can return a clip rectangle for printers.
Note that I only tested using Randy's snippet from comment 9: import org.eclipse.swt.graphics.*; import org.eclipse.swt.printing.*; public class Bug81467 { public static void main(String[] args) { Printer printer = new Printer(); printer.startJob("bugzilla 81467"); GC gc = new GC(printer); System.out.println(gc.getClipping()); printer.endJob(); printer.dispose(); } } i.e. I am unable to easily test GEF. Can someone please get tomorrow's I-build and try Randy's snippet in comment 4 to make sure that GEF no longer gets stuck in an infinite loop? I suspect that it should be ok.