Nakov.com

Thoughts on Software Engineering

  • About
  • Books
  • Courses
  • Videos
  • Presentations
  • Research
  • Publications
  • Others
  • Contacts
  • RSS Feed
  • Home

Categories

  • .net (81)
  • blog (330)
  • bulgarian (203)
  • career (21)
  • contests (28)
  • courses (64)
  • english (131)
  • HTML5 (6)
  • java (44)
  • seminars (81)
  • НЛП (7)
  • предприемачество (3)

Networked Blogs

Follow this blog

Recent Posts

  • Представяне на NASA Space Apps Challenge на 2 април 2013
  • Как да презентираме вдъхновяващо с майсторлък? Мурафетите на Наков
  • Пролетен прием в софтуерната академия: 500 нови студента от април
  • Безплатен курс “Бизнес умения за софтуерни инженери” – от 27 март
  • 580 продължават безплатното си обучение в софтуерната академия след изпитите по CSS и C# част 2

Partners

Intro C# Programming Book by Svetlin Nakov
Telerik Academy

My Projects

  • GWT Advanced Table
  • Internet Programming with Java Book
  • Intro C# Programming Book
  • Intro Java Programming Book
  • Java For Digitally Signing Documents In Web Book
  • Programming for .NET Framework Book
  • Software University

Useful Links

  • Bulgarian Association of Software Developers (BASD)
  • Free Java and Java EE Course
  • NLP Club Bulgaria
  • Stefan Kanev's Blog
  • Telerik Academy
  • Telerik Kids Academy
  • Telerik School Academy

Tags

AJAX ASP.NET C# CSS development HTML Java JavaScript NET Programming Software SQL telerik Академия на Телерик Академия на Телерик за ученици академия академия за софтуерни инженери безплатен курс безплатни курсове безплатни уроци безплатно безплатно обучение курс обучение програмиране разработка на софтуер семинар софтуерна академия състезание телерик

Most Viewed Posts

  • Rejected a Program Manager Position at Microsoft Dublin – My Successful Interview at Microsoft
  • Svetlin Nakov – About Me
  • Innovations in Software Тest Automation – конференция за QA инженери – 25.11.2011
  • Online AES Encryption Tool
  • Disable Certificate Validation in Java SSL Connections
  • My Interview at Google in Zurich
  • Native SQL Queries in Entity Framework
  • JAX-RS, @Path, @PathParam and Optional Parameters
  • Svetlin Nakov – Books
  • NHibernate Lazy Loading BLOB column

Author: Svetlin Nakov

November 30, 2008

  • Svejo.net
  • Tweet

Java SWING Error Dialog with Exception Details

I use SWING for long time but I am amazed how slowly this GUI framework evolve and how far is it comparing to Windows Forms, WPF and Flex. One of the small missing things in Swing is that there is not standard way to display an error message with Exception stacktrace. So I created such dialog and I want to share it with everybody using SWING. The result look like this (shrinked form):

swing-error-dialog-shrinked.png

When the dialog is expanded, it shows the exception:

swing-error-dialog-expanded.png

It seems like creating such a dialog is trivial task but unfortunately you need to solve a number of problems related to correct positioning, scrolling issues, etc. When the exception is large, it needs a scroller. When the error description is logn it needs good layout and scroller. This makes the things a little bit challenging. See the code below (the ErrorDilaog class):


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import javax.swing.*;
import javax.swing.text.*;

/**
 * @author Svetlin Nakov
 */
@SuppressWarnings("serial")
public class ErrorDialog extends JDialog {

 private static final String SHOW_DETAILS_TEXT = "Show Details ...";
 private static final String HIDE_DETAILS_TEXT = "Hide Details";
 private JButton jButtonClose;
 private ImagePanel imagePanelErrorIcon;
 private JButton jButtonShowHideDetails;
 private JPanel jPanelBottom;
 private JPanel jPanelCenter;
 private JPanel jPanelTop;
 private JScrollPane jScrollPaneErrorMsg;
 private JTextPane jTextPaneErrorMsg;
 private JScrollPane jScrollPaneException;
 private JTextArea jTextAreaException;

 private static final String ERROR_ICON_RESOURCE_LOCATION =
  "Error-Icon.gif";

 public ErrorDialog(String errorMessage) {
  this(errorMessage, null);
 }
 
 public ErrorDialog(String errorMessage, Throwable exception) {
  this.setTitle("Error");
  this.setModal(true);
  this.setResizable(false);
  this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        jPanelTop = new JPanel();
        imagePanelErrorIcon = new ImagePanel(ERROR_ICON_RESOURCE_LOCATION);
        jPanelTop.setLayout(null);
        jPanelTop.setPreferredSize(new Dimension(480, 100));
        imagePanelErrorIcon.setLocation(new Point(20, 36));
        jPanelTop.add(imagePanelErrorIcon);

        jTextPaneErrorMsg = new JTextPane();
        jTextPaneErrorMsg.setFont(jTextPaneErrorMsg.getFont().deriveFont(
         jTextPaneErrorMsg.getFont().getStyle() | Font.BOLD,
         jTextPaneErrorMsg.getFont().getSize()+1));
        jTextPaneErrorMsg.setBorder(null);
        jTextPaneErrorMsg.setEditable(false);
        jTextPaneErrorMsg.setBackground(null);
        jScrollPaneErrorMsg = new JScrollPane(jTextPaneErrorMsg);
        jScrollPaneErrorMsg.setBorder(null);
        jScrollPaneErrorMsg.setSize(new Dimension(405, 80));
        jScrollPaneErrorMsg.setLocation(new Point(71, 13));
        jPanelTop.add(jScrollPaneErrorMsg);

        jPanelCenter = new JPanel();
        jPanelCenter.setSize(new Dimension(420, 300));
        jTextAreaException = new JTextArea();
        jScrollPaneException = new JScrollPane(jTextAreaException);
        jScrollPaneException.setPreferredSize(new Dimension(470, 300));
        jPanelCenter.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
        jPanelCenter.add(jScrollPaneException);

        jPanelBottom = new JPanel();
        jButtonShowHideDetails = new JButton();
        jButtonClose = new JButton();
        jPanelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 15));

        jButtonShowHideDetails.setText(SHOW_DETAILS_TEXT);
        jButtonShowHideDetails.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                showHideExceptionDetails();
            }
        });
        jPanelBottom.add(jButtonShowHideDetails);

        jButtonClose.setText("Close");
        jButtonClose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
             dispose();
            }
        });
        jPanelBottom.add(jButtonClose);
 
        this.setLayout(new BorderLayout());
        this.add(jPanelTop, BorderLayout.NORTH);
        this.add(jPanelCenter, BorderLayout.CENTER);
        this.add(jPanelBottom, BorderLayout.SOUTH);

        this.jTextPaneErrorMsg.setEditorKit(new VerticalCenteredEditorKit());
        this.jTextPaneErrorMsg.setText(errorMessage);
       
        this.jPanelCenter.setVisible(false);
       
        if (exception != null) {
         String exceptionText = getStackTraceAsString(exception);
         jTextAreaException.setText(exceptionText);
         jTextAreaException.setEditable(false);
        } else {
         this.jButtonShowHideDetails.setVisible(false);
        }

  // Make [Escape] key as close button
  this.registerEscapeKey();

        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setModal(true);
  this.pack();
  centerDialogOnTheScreen();
 }

 private void centerDialogOnTheScreen() {
  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  Dimension dialogSize = this.getSize();
  int centerPosX = (screenSize.width - dialogSize.width) / 2;
  int centerPosY = (screenSize.height - dialogSize.height) / 2;
  setLocation(centerPosX, centerPosY);
 }
 
 private void showHideExceptionDetails() {
        if (this.jPanelCenter.isVisible()) {
            // Hide the exception details
            this.jButtonShowHideDetails.setText(SHOW_DETAILS_TEXT);
            this.jPanelCenter.setVisible(false);
      this.pack();
            centerDialogOnTheScreen();
        } else {
            // Show the exception details
            this.jButtonShowHideDetails.setText(HIDE_DETAILS_TEXT);
            this.jPanelCenter.setVisible(true);
      this.pack();
            centerDialogOnTheScreen();
        }
 }

 private String getStackTraceAsString(Throwable exception) {
  Writer result = new StringWriter();
  PrintWriter printWriter = new PrintWriter(result);
  exception.printStackTrace(printWriter);
  return result.toString();
 }

 /**
  * Make the [Escape] key to behave like the [Close] button.
  */
 public void registerEscapeKey() {
  KeyStroke escapeKeyStroke =
   KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
  Action escapeAction = new AbstractAction() {
   private static final long serialVersionUID = 1L;

   public void actionPerformed(ActionEvent e) {
    jButtonClose.doClick();
   }
  };

  this.rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    escapeKeyStroke, "ESCAPE");
  this.rootPane.getActionMap().put("ESCAPE", escapeAction);
 }
 
 public void hideAndDisposeDialog() {
  this.setVisible(false);
  this.dispose();
 }

 public static void showError(String errorMessage,
   Throwable throwable) {
  ErrorDialog errorDialog =
   new ErrorDialog(errorMessage, throwable);
  errorDialog.setVisible(true);  
 }

 public static void showError(String errorMessage) {
  ErrorDialog.showError(errorMessage, null); 
 }
 
 public static void main(String[] args) {
  ErrorDialog.showError("This is an error message.", new Exception());
 }
}

@SuppressWarnings("serial")
class VerticalCenteredEditorKit extends StyledEditorKit {
 public ViewFactory getViewFactory() {
  return new StyledViewFactory();
 }

 static class StyledViewFactory implements ViewFactory {
  public View create(Element elem) {
   String kind = elem.getName();
   if (kind != null) {
    if (kind.equals(AbstractDocument.ContentElementName)) {
     return new LabelView(elem);
    } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
     return new ParagraphView(elem);
    } else if (kind.equals(AbstractDocument.SectionElementName)) {
     return new CenteredBoxView(elem, View.Y_AXIS);
    } else if (kind.equals(StyleConstants.ComponentElementName)) {
     return new ComponentView(elem);
    } else if (kind.equals(StyleConstants.IconElementName)) {
     return new IconView(elem);
    }
   }

   // Default to text display
   return new LabelView(elem);
  }
 }
 
 static class CenteredBoxView extends BoxView {
  public CenteredBoxView(Element elem, int axis) {
   super(elem, axis);
  }

  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
    int[] spans) {
   super.layoutMajorAxis(targetSpan, axis, offsets, spans);
   int textBlockHeight = 0;
   int offset = 0;

   for (int i = 0; i < spans.length; i++) {
    textBlockHeight += spans[i];
   }
   offset = (targetSpan - textBlockHeight) / 2;
   for (int i = 0; i < offsets.length; i++) {
    offsets[i] += offset;
   }
  }
 }
}

The ImageUtils class provides a simplified API for loading images from a file:


import java.awt.Component;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author Svetlin Nakov
 */
public class ImageUtils {
 
 private static final int BUF_SIZE = 4096;

 public static Image loadImageFromResource(String resourceLocation,
   Component imageOwner) {
  InputStream inputStream = ImageUtils.class.getClassLoader()
    .getResourceAsStream(resourceLocation);
  try {
   byte[] imageBinaryData = readStreamToEnd(inputStream);
   Image image = Toolkit.getDefaultToolkit().createImage(imageBinaryData);
   ImageUtils.ensureImageIsLoaded(image, imageOwner);
   return image;
  } catch (Exception ex) {
   throw new RuntimeException(
    "Cannot load image from resource: " + resourceLocation, ex);
  } finally {
   try {
    inputStream.close();
   } catch (IOException e) {
    // Ignore IO exceptions during file closing
   }
  }
 }

 private static byte[] readStreamToEnd(InputStream inputStream)
 throws IOException {
  ByteArrayOutputStream output = new ByteArrayOutputStream(BUF_SIZE);
  byte[] buf = new byte[BUF_SIZE];
  while (true) {
   int bytesRead = inputStream.read(buf);
   if (bytesRead == -1) {
    // End of stream reached
    break;
   }
   output.write(buf, 0, bytesRead);
  }
  byte[] streamData = output.toByteArray();
  return streamData;
 }

 public static void ensureImageIsLoaded(Image image, Component imageOwner) {
  MediaTracker mediaTracker = new MediaTracker(imageOwner);
  mediaTracker.addImage(image, 0);
  try {
   mediaTracker.waitForAll();
  } catch (InterruptedException intEx) {
   throw new RuntimeException("Image loading was interrupted.", intEx);
  }
 }

}

The class ImagePanel shows image in a JPanel:


import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;

/**
 * @author Svetlin Nakov
 */
public class ImagePanel extends JPanel {

 private static final long serialVersionUID = 3813223397371003521L;

 private Image image;
 private int imageWidth;
 private int imageHeight;

 public ImagePanel(String resourceLocation) {
  Image image = ImageUtils.loadImageFromResource(resourceLocation, this);
  setImage(image);
 }

 public ImagePanel(Image image) {
  setImage(image);
 }

 private void setImage(Image image) {
  this.image = image;
  this.imageWidth = this.image.getWidth(null);
  this.imageHeight = this.image.getHeight(null);
  Dimension imageSize = new Dimension(this.imageWidth, this.imageHeight);
  this.setSize(imageSize);
  this.setPreferredSize(imageSize);
 }
 
 @Override
 protected void paintComponent(Graphics gr) {
  super.paintComponent(gr);
  if (this.image != null) {
   gr.drawImage(image, 0, 0, this.imageWidth, this.imageHeight, this);
  }
 }
}

Download the entire example source code (Eclipse project): errordialog.zip.

I hope all this would be helpful to anyone. Enjoy!

Tags: awt event, awt toolkit, errorMessage, import java, int, java awt, java swing, jButtonClose, jPanelBottom, jPanelCenter

Previews (4,040), Views (1,360), Comments (3)

Author: Svetlin Nakov

November 20, 2008

  • Svejo.net
  • Tweet

Connect to Oracle Express Edition from Remote Machine

For development purposes and small applications I prefer using Oracle Database 10g Express Edition instead of the heavyweight Oracle Database 10g / 11g Enterprise. It can be installed and run for just 2-3 minutes but it has a small problem: by default the TNS Listener listens for connections on port 1521 from the local machine only and thus remote clients can not connect. A quick fix for this issue is to edit the LISTENER.ORA file located typically in here:

C:\oraclexe\app\oracle\product\10.2.0\server\NETWORK\ADMIN

You should change the socket bind address to 0.0.0.0. The LISTENER configuration should look like this:

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC_FOR_XE))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521))
    )
  )

Tags: Database, DESCRIPTION, development, machine, oracle database 10g, oracle database 10g express edition, oracle express, oracle product, port, using oracle

Previews (4,536), Views (2,020), Comments (0)

Top Posts

  • Семинар “Как да си намерим работа в ИТ индустрията?” – CV, cover letter, интервю

  • Университет като за софтуерни инженери: къде да учим програмиране след 12 клас? (класацията на Наков)

  • Rejected a Program Manager Position at Microsoft Dublin – My Successful Interview at Microsoft

  • My Interview at Google in Zurich

Translation

Recent Posts

  • Представяне на NASA Space Apps Challenge на 2 април 2013
  • Как да презентираме вдъхновяващо с майсторлък? Мурафетите на Наков
  • Пролетен прием в софтуерната академия: 500 нови студента от април
  • Безплатен курс “Бизнес умения за софтуерни инженери” – от 27 март
  • 580 продължават безплатното си обучение в софтуерната академия след изпитите по CSS и C# част 2

Recent Comments

  • extra resources on Семинар “Как да си намерим работа в ИТ индустрията?” – CV, cover letter, интервю: While farmacia on line has won wide acceptance, it has served Southeast Asian doctors for...
  • http://theprostitutiontimes.blogspot.com on Нов безплатен курс по уеб дизайн с HTML 5, CSS и JavaScript – от март в академията на Телерик: Instead, it's diverted hundreds of millions of dollars to two children with autism for" pain...
  • Paul Crocker on X.509 Certificate Validation in Java: Build and Verify Chain and Verify CLR with Bouncy Castle: Thanks - It works fine for me after tidying the code up a bit and...
  • look at this web-site on Безплатните курсове в Академията на Телерик за софтуерни инженери – какво да очакваме за 2011-2012?: But beyond the financial implications it is the most logical thing in the world, but...
  • check This link right Here now on 85 продължават в Софтуерната академия в курса Software Engineering Basics от 17 април: Isn't the very name," National News" mean that it s not just about themedication. Our...

Archives

  • March 2013 (4)
  • February 2013 (5)
  • January 2013 (7)
  • December 2012 (1)
  • November 2012 (11)
  • October 2012 (8)
  • September 2012 (8)
  • August 2012 (2)
  • July 2012 (10)
  • June 2012 (1)
  • May 2012 (9)
  • April 2012 (9)
  • March 2012 (9)
  • February 2012 (10)
  • January 2012 (8)
  • December 2011 (5)
  • November 2011 (12)
  • October 2011 (18)
  • September 2011 (16)
  • August 2011 (7)
  • July 2011 (7)
  • June 2011 (2)
  • May 2011 (3)
  • April 2011 (10)
  • March 2011 (8)
  • February 2011 (5)
  • January 2011 (7)
  • December 2010 (3)
  • November 2010 (17)
  • October 2010 (8)
  • September 2010 (4)
  • August 2010 (2)
  • July 2010 (4)
  • June 2010 (3)
  • May 2010 (4)
  • April 2010 (2)
  • March 2010 (1)
  • February 2010 (2)
  • January 2010 (4)
  • December 2009 (3)
  • November 2009 (6)
  • October 2009 (3)
  • September 2009 (6)
  • July 2009 (4)
  • June 2009 (1)
  • May 2009 (3)
  • December 2008 (2)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (5)
  • July 2008 (2)
  • June 2008 (4)
  • May 2008 (2)
  • April 2008 (1)
  • March 2008 (2)
  • February 2008 (2)
  • January 2008 (1)
  • December 2007 (4)
  • November 2007 (7)
  • October 2007 (3)
  • September 2007 (9)
  • August 2007 (5)

RSS Academy Forums

  • Answered: [КПК Изпит] Вариант 2 - Phonebook
  • Answered: Проблем при сваляне на домашно за оценяване
  • Answered: Неофициални резултати по JS 2
  • Answered: "C# - част I" дати на теста и изпита???
  • Answered: [C#] Домашно Operators and Expressions - 7 Задача

navigation:

Home About Books Courses Presentations Videos Research Publications Others Contacts
Svetlin Nakov @ Google+

My Projects

  • GWT Advanced Table
  • Internet Programming with Java Book
  • Intro C# Programming Book
  • Intro Java Programming Book
  • Java For Digitally Signing Documents In Web Book
  • Programming for .NET Framework Book
  • Software University

Useful Links

  • Bulgarian Association of Software Developers (BASD)
  • Free Java and Java EE Course
  • NLP Club Bulgaria
  • Stefan Kanev's Blog
  • Telerik Academy
  • Telerik Kids Academy
  • Telerik School Academy

Categories

  • .net
  • blog
  • bulgarian
  • career
  • contests
  • courses
  • english
  • HTML5
  • java
  • seminars
  • НЛП
  • предприемачество

Recent Posts

  • Представяне на NASA Space Apps Challenge на 2 април 2013
  • Как да презентираме вдъхновяващо с майсторлък? Мурафетите на Наков
  • Пролетен прием в софтуерната академия: 500 нови студента от април
  • Безплатен курс “Бизнес умения за софтуерни инженери” – от 27 март
  • 580 продължават безплатното си обучение в софтуерната академия след изпитите по CSS и C# част 2

Copyright © 1999 - 2013 Svetlin Nakov