/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2015 the original author or authors.
*/
package org.assertj.swing.core;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.swing.edt.GuiActionRunner.execute;
import static org.assertj.swing.format.Formatting.format;
import static org.assertj.swing.hierarchy.NewHierarchy.ignoreExistingComponents;
import java.awt.Component;
import java.awt.Container;
import java.io.PrintStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.assertj.swing.annotation.RunsInCurrentThread;
import org.assertj.swing.annotation.RunsInEDT;
import org.assertj.swing.hierarchy.ComponentHierarchy;
import org.assertj.swing.hierarchy.ExistingHierarchy;
import org.assertj.swing.hierarchy.SingleComponentHierarchy;
/**
* Default implementation of {@link ComponentPrinter}.
*
* @author Alex Ruiz
*
* @see ComponentPrinter
* @see org.assertj.swing.format.Formatting#format(Component)
*/
public final class BasicComponentPrinter implements ComponentPrinter {
private static final String INDENTATION = " ";
private static final ComponentMatcher ALWAYS_MATCHES = alwaysMatches();
private static @Nonnull ComponentMatcher alwaysMatches() {
return new ComponentMatcher() {
@Override
public boolean matches(@Nullable Component c) {
return true;
}
};
}
private final ComponentHierarchy hierarchy;
/**
* Creates a new {@link BasicComponentPrinter} with a new AWT hierarchy. AWT and Swing {@code Component}s created
* before the created {@link BasicComponentPrinter} cannot be accessed by the created {@link BasicComponentPrinter}.
*
* @return the created finder.
*/
public static @Nonnull ComponentPrinter printerWithNewAwtHierarchy() {
return new BasicComponentPrinter(ignoreExistingComponents());
}
/**
* Creates a new {@link BasicComponentPrinter} that has access to all the AWT and Swing {@code Component}s in the AWT
* hierarchy.
*
* @return the created printer.
*/
public static @Nonnull ComponentPrinter printerWithCurrentAwtHierarchy() {
return new BasicComponentPrinter(new ExistingHierarchy());
}
/**
* Creates a new {@link BasicComponentPrinter}.
*
* @param hierarchy the component hierarchy to use.
*/
protected BasicComponentPrinter(@Nonnull ComponentHierarchy hierarchy) {
this.hierarchy = hierarchy;
}
/**
* @return the component hierarchy used by this printer.
*/
protected final @Nonnull ComponentHierarchy hierarchy() {
return hierarchy;
}
@RunsInEDT
@Override
public void printComponents(@Nonnull PrintStream out) {
printComponents(out, ALWAYS_MATCHES);
}
@RunsInEDT
@Override
public void printComponents(@Nonnull PrintStream out, @Nullable Container root) {
printComponents(out, ALWAYS_MATCHES, root);
}
@RunsInEDT
@Override
public void printComponents(@Nonnull PrintStream out, @Nonnull Class<? extends Component> type) {
printComponents(out, type, null);
}
@RunsInEDT
@Override
public void printComponents(@Nonnull PrintStream out, @Nonnull Class<? extends Component> type,
@Nullable Container root) {
print(hierarchy(root), new TypeMatcher(checkNotNull(type)), checkNotNull(out));
}
@Override
public void printComponents(@Nonnull PrintStream out, @Nonnull ComponentMatcher matcher) {
printComponents(out, matcher, null);
}
@Override
public void printComponents(@Nonnull PrintStream out, @Nonnull ComponentMatcher matcher, @Nullable Container root) {
print(hierarchy(root), checkNotNull(matcher), checkNotNull(out));
}
private @Nonnull ComponentHierarchy hierarchy(@Nullable Container root) {
return root != null ? new SingleComponentHierarchy(root, hierarchy) : hierarchy;
}
@RunsInEDT
private static void print(@Nonnull final ComponentHierarchy hierarchy, @Nonnull final ComponentMatcher matcher,
@Nonnull final PrintStream out) {
execute(() -> {
for (Component c : hierarchy.roots()) {
print(checkNotNull(c), hierarchy, matcher, 0, out);
}
});
}
@RunsInCurrentThread
private static void print(@Nonnull Component c, @Nonnull ComponentHierarchy h, @Nonnull ComponentMatcher matcher,
int level, @Nonnull PrintStream out) {
if (matcher.matches(c)) {
print(c, level, out);
}
for (Component child : h.childrenOf(c)) {
print(checkNotNull(child), h, matcher, level + 1, out);
}
}
@RunsInCurrentThread
private static void print(@Nonnull Component c, int level, @Nonnull PrintStream out) {
for (int i = 0; i < level; i++) {
out.print(INDENTATION);
}
out.println(format(c));
}
}