001 /*
002 * Created on Dec 22, 2007
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005 * the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011 * specific language governing permissions and limitations under the License.
012 *
013 * Copyright @2007-2010 the original author or authors.
014 */
015 package org.fest.swing.core;
016
017 import static org.fest.swing.edt.GuiActionRunner.execute;
018 import static org.fest.swing.format.Formatting.format;
019 import static org.fest.swing.hierarchy.NewHierarchy.ignoreExistingComponents;
020
021 import java.awt.Component;
022 import java.awt.Container;
023 import java.io.PrintStream;
024
025 import org.fest.swing.annotation.RunsInCurrentThread;
026 import org.fest.swing.annotation.RunsInEDT;
027 import org.fest.swing.edt.GuiTask;
028 import org.fest.swing.hierarchy.*;
029
030 /**
031 * Understands printing the <code>String</code> representation of <code>{@link java.awt.Component}</code>s to
032 * facilitate debugging.
033 *
034 * @author Alex Ruiz
035 */
036 public final class BasicComponentPrinter implements ComponentPrinter {
037
038 private static final String INDENTATION = " ";
039
040 private static final ComponentMatcher ALWAYS_MATCHES = alwaysMatches();
041
042 private static ComponentMatcher alwaysMatches() {
043 return new ComponentMatcher() {
044 public boolean matches(Component c) {
045 return true;
046 }
047 };
048 }
049
050 private final ComponentHierarchy hierarchy;
051
052 /**
053 * Creates a new <code>{@link BasicComponentPrinter}</code> with a new AWT hierarchy. <code>{@link Component}</code>s
054 * created before the created <code>{@link BasicComponentPrinter}</code> cannot be accessed by the created
055 * <code>{@link BasicComponentPrinter}</code>.
056 * @return the created finder.
057 */
058 public static ComponentPrinter printerWithNewAwtHierarchy() {
059 return new BasicComponentPrinter(ignoreExistingComponents());
060 }
061
062 /**
063 * Creates a new <code>{@link BasicComponentPrinter}</code> that has access to all the GUI components in the AWT
064 * hierarchy.
065 * @return the created printer.
066 */
067 public static ComponentPrinter printerWithCurrentAwtHierarchy() {
068 return new BasicComponentPrinter(new ExistingHierarchy());
069 }
070
071 /**
072 * Creates a new <code>{@link BasicComponentPrinter}</code>.
073 * @param hierarchy the component hierarchy to use.
074 */
075 protected BasicComponentPrinter(ComponentHierarchy hierarchy) {
076 this.hierarchy = hierarchy;
077 }
078
079 /**
080 * Returns the component hierarchy used by this printer.
081 * @return the component hierarchy used by this printer.
082 */
083 protected final ComponentHierarchy hierarchy() { return hierarchy; }
084
085 /** {@inheritDoc} */
086 @RunsInEDT
087 public void printComponents(PrintStream out) {
088 printComponents(out, ALWAYS_MATCHES);
089 }
090
091 /** {@inheritDoc} */
092 @RunsInEDT
093 public void printComponents(PrintStream out, Container root) {
094 printComponents(out, ALWAYS_MATCHES, root);
095 }
096
097 /** {@inheritDoc} */
098 @RunsInEDT
099 public void printComponents(PrintStream out, Class<? extends Component> type) {
100 printComponents(out, type, null);
101 }
102
103 /** {@inheritDoc} */
104 @RunsInEDT
105 public void printComponents(PrintStream out, Class<? extends Component> type, Container root) {
106 validateNotNull(out);
107 if (type == null) throw new NullPointerException("The type to match should not be null");
108 print(hierarchy(root), new TypeMatcher(type), out);
109 }
110
111 /** ${@inheritDoc} */
112 public void printComponents(PrintStream out, ComponentMatcher matcher) {
113 printComponents(out, matcher, null);
114 }
115
116 /** ${@inheritDoc} */
117 public void printComponents(PrintStream out, ComponentMatcher matcher, Container root) {
118 validateNotNull(out);
119 if (matcher == null) throw new NullPointerException("The matcher to use as filter should not be null");
120 print(hierarchy(root), matcher, out);
121 }
122
123 private void validateNotNull(PrintStream out) {
124 if (out == null) throw new NullPointerException("The output stream should not be null");
125 }
126
127 private ComponentHierarchy hierarchy(Container root) {
128 return root != null ? new SingleComponentHierarchy(root, hierarchy) : hierarchy;
129 }
130
131 @RunsInEDT
132 private static void print(final ComponentHierarchy hierarchy, final ComponentMatcher matcher, final PrintStream out) {
133 execute(new GuiTask() {
134 protected void executeInEDT() {
135 for (Component c : hierarchy.roots()) print(c, hierarchy, matcher, 0, out);
136 }
137 });
138 }
139
140 @RunsInCurrentThread
141 private static void print(Component c, ComponentHierarchy h, ComponentMatcher matcher, int level,
142 PrintStream out) {
143 if (matcher.matches(c)) print(c, level, out);
144 for (Component child : h.childrenOf(c))
145 print(child, h, matcher, level + 1, out);
146 }
147
148 @RunsInCurrentThread
149 private static void print(Component c, int level, PrintStream out) {
150 for (int i = 0; i < level; i++) out.print(INDENTATION);
151 out.println(format(c));
152 }
153 }