diff --git a/CHANGELOG.md b/CHANGELOG.md index e4ec4101..47a82870 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ FlatLaf Change Log - PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI` (instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier extensibility. +- Table and PopupFactory: Use `StackWalker` in Java 9+ for better performance. + (issue #334) - ToolBar: Paint focus indicator for focused button in toolbar. (issue #346) #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java index 061d9e0a..374e5e6a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java @@ -44,6 +44,7 @@ import javax.swing.Popup; import javax.swing.PopupFactory; import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; import javax.swing.UIManager; import javax.swing.border.Border; import com.formdev.flatlaf.FlatClientProperties; @@ -260,13 +261,7 @@ public class FlatPopupFactory } private boolean wasInvokedFromToolTipManager() { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - for( StackTraceElement stackTraceElement : stackTrace ) { - if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) && - "showTipWindow".equals( stackTraceElement.getMethodName() ) ) - return true; - } - return false; + return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 ); } //---- class NonFlashingPopup --------------------------------------------- diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java index 84e4edfa..11ad7154 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java @@ -240,7 +240,7 @@ public class FlatTableUI if( isDragging && SystemInfo.isJava_9_orLater && ((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) && - wasInvokedFromPaintDraggedArea() ) + wasInvokedFromMethod( "paintDraggedArea" ) ) { if( y1 == y2 ) { // horizontal grid line @@ -282,22 +282,8 @@ public class FlatTableUI return wasInvokedFromMethod( "paintGrid" ); } - private boolean wasInvokedFromPaintDraggedArea() { - return wasInvokedFromMethod( "paintDraggedArea" ); - } - private boolean wasInvokedFromMethod( String methodName ) { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - for( int i = 0; i < 10 || i < stackTrace.length; i++ ) { - if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) { - String methodName2 = stackTrace[i].getMethodName(); - if( "paintCell".equals( methodName2 ) ) - return false; - if( methodName.equals( methodName2 ) ) - return true; - } - } - return false; + return StackUtils.wasInvokedFrom( BasicTableUI.class.getName(), methodName, 8 ); } }; } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtils.java new file mode 100644 index 00000000..0d833689 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * 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 + * + * https://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. + */ + +package com.formdev.flatlaf.ui; + +import java.util.function.BiPredicate; + +/** + * @author Karl Tauber + */ +class StackUtils +{ + private static final StackUtils INSTANCE = new StackUtilsImpl(); + + // hide from javadoc + StackUtils() { + } + + /** + * Checks whether current method was invoked from the given class and method. + */ + public static boolean wasInvokedFrom( String className, String methodName, int limit ) { + return wasInvokedFrom( (c,m) -> c.equals( className ) && m.equals( methodName ), limit ); + } + + /** + * Checks whether current method was invoked from a class and method using the given predicate, + * which gets the class name of the stack frame as first parameter and the method name as second parameter. + */ + public static boolean wasInvokedFrom( BiPredicate predicate, int limit ) { + return INSTANCE.wasInvokedFromImpl( predicate, limit ); + } + + boolean wasInvokedFromImpl( BiPredicate predicate, int limit ) { + throw new UnsupportedOperationException(); + } +} diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtilsImpl.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtilsImpl.java new file mode 100644 index 00000000..0775c413 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/StackUtilsImpl.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * 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 + * + * https://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. + */ + +package com.formdev.flatlaf.ui; + +import java.util.function.BiPredicate; + +/** + * @author Karl Tauber + */ +class StackUtilsImpl + extends StackUtils +{ + @Override + boolean wasInvokedFromImpl( BiPredicate predicate, int limit ) { + int count = -2; + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for( StackTraceElement stackTraceElement : stackTrace ) { + if( predicate.test( stackTraceElement.getClassName(), stackTraceElement.getMethodName() ) ) + return true; + + count++; + if( limit > 0 && count > limit ) + return false; + } + return false; + } +} diff --git a/flatlaf-core/src/main/java9/com/formdev/flatlaf/ui/StackUtilsImpl.java b/flatlaf-core/src/main/java9/com/formdev/flatlaf/ui/StackUtilsImpl.java new file mode 100644 index 00000000..0ba0fcc2 --- /dev/null +++ b/flatlaf-core/src/main/java9/com/formdev/flatlaf/ui/StackUtilsImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * 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 + * + * https://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. + */ + +package com.formdev.flatlaf.ui; + +import java.util.function.BiPredicate; + +/** + * @author Karl Tauber + */ +class StackUtilsImpl + extends StackUtils +{ + @Override + boolean wasInvokedFromImpl( BiPredicate predicate, int limit ) { + return StackWalker.getInstance().walk( stream -> { + if( limit > 0 ) + stream = stream.limit( limit + 2 ); + return stream.anyMatch( f -> { + return predicate.test( f.getClassName(), f.getMethodName() ); + } ); + } ); + } +}