帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

274 lines
10 KiB

package com.fr.design.debug.ui;
import com.fine.swing.ui.layout.Row;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.base.extension.FileExtension;
import com.fr.design.border.FineBorderFactory;
import com.fr.design.carton.latency.LatencyLevel;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.icombobox.UIComboBox;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.icontainer.UITableScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itable.FineUITable;
import com.fr.design.gui.itextarea.UITextArea;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.mainframe.DesignerContext;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.general.GeneralUtils;
import com.fr.log.FineLoggerFactory;
import org.jetbrains.annotations.NotNull;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Arrays;
import java.util.Date;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.row;
/**
* UI监控面板
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/11/07
*/
public class UIMonitorPane extends JPanel {
private DefaultTableModel model;
private UICheckBox inspector;
private UICheckBox monitor;
public UIMonitorPane() {
setLayout(new BorderLayout());
setBorder(new ScaledEmptyBorder(10, 10, 10, 10));
initComponent();
}
private void initComponent() {
UITableScrollPane tablePane = initLatencyTable();
Row topSettingRow = initTopSettingRow();
inspector = new UICheckBox("Open UI Inspector");
monitor = new UICheckBox("Open Latency Monitor");
JPanel monitorPane = column(10,
cell(monitor), cell(topSettingRow), cell(tablePane).weight(1)
).getComponent();
add(column(10,
cell(FineUIUtils.wrapComponentWithTitle(inspector, "UI Inspector")),
cell(FineUIUtils.wrapComponentWithTitle(monitorPane, "UI Latency Monitor"))
).getComponent(), BorderLayout.CENTER);
topSettingRow.setVisible(false);
tablePane.setVisible(false);
initMonitorStatus(topSettingRow, tablePane);
}
private void initMonitorStatus(Row topSettingRow, UITableScrollPane tablePane) {
inspector.setSelected(UIInspectorHolder.getInstance().isInstalled());
monitor.setSelected(UILatencyWorker.getInstance().isMonitoring());
// 注册事件监听
inspector.addChangeListener(e -> {
if (inspector.isSelected()) {
UIInspectorHolder.getInstance().install();
} else {
UIInspectorHolder.getInstance().uninstall();
}
});
monitor.addChangeListener(e -> {
topSettingRow.setVisible(monitor.isSelected());
tablePane.setVisible(monitor.isSelected());
if (monitor.isSelected()) {
startMonitor();
} else {
stopMonitor();
}
});
// 初始化卡顿堆栈表
if (monitor.isSelected()) {
SwingUtilities.invokeLater(() -> UILatencyWorker.getInstance().getAllLatencyInfo()
.forEach(info -> model.addRow(parseInfo2Row(info))));
}
}
private Row initTopSettingRow() {
UIComboBox comboBox = initThresholdComboBox();
UIButton export = new UIButton(new LazyIcon("export"));
export.setToolTipText("Export latency log");
UIButton clear = new UIButton(new LazyIcon("remove"));
clear.setToolTipText("Clear latency log");
JToolBar toolbar = new UIToolbar();
toolbar.add(comboBox);
toolbar.add(clear);
toolbar.add(export);
export.addActionListener(e -> exportData());
clear.addActionListener(e -> {
model.setRowCount(0);
UILatencyWorker.getInstance().clearData();
});
return row(5, cell(new UILabel("Latency Threshold")), cell(toolbar)).getComponent();
}
private static @NotNull UIComboBox initThresholdComboBox() {
UIComboBox comboBox = new UIComboBox(Arrays.stream(LatencyLevel.values())
.filter(it -> it != LatencyLevel.FLASH).map(LatencyLevel::getStart).toArray());
comboBox.putClientProperty(FineClientProperties.COMBO_BOX_TYPE, FineClientProperties.ADAPTIVE_COMBO_BOX);
comboBox.setSelectedItem(UILatencyInfoHandler.getInstance().getThreshold());
comboBox.addActionListener(e -> {
if (comboBox.getSelectedItem() != null) {
UILatencyWorker.getInstance().resetThreshold((Long) comboBox.getSelectedItem());
}
});
// 阈值初始化
comboBox.setSelectedItem(comboBox.getSelectedItem());
return comboBox;
}
private UITableScrollPane initLatencyTable() {
model = new DefaultTableModel();
model.addColumn("seq");
model.addColumn("cost(ms)");
model.addColumn("stack");
FineUITable table = new FineUITable(model) {
public boolean isCellEditable(int row, int column) {
return false;
}
};
UITableScrollPane tablePane = new UITableScrollPane(table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
if (row >= 0) {
String stack = (String) table.getValueAt(row, 2);
StackPane stackPane = new StackPane(stack);
BasicDialog dialog = stackPane.showLargeWindow(SwingUtilities.getWindowAncestor(e.getComponent()), null);
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
}
}
});
TableColumnModel columnModel = table.getColumnModel();
adjustColumnWidth(columnModel.getColumn(0));
adjustColumnWidth(columnModel.getColumn(1));
return tablePane;
}
private void adjustColumnWidth(TableColumn column) {
column.setPreferredWidth(100);
column.setMinWidth(100);
column.setMaxWidth(100);
}
/**
* 开启性能监控
*/
public void startMonitor() {
EventDispatcher.listen(LatencyMonitorEvent.OFF_THRESHOLD_EVENT, latencyInfoListener);
UILatencyWorker.getInstance().start();
}
/**
* 关闭性能监控
*/
public void stopMonitor() {
UILatencyWorker.getInstance().stop();
EventDispatcher.stopListen(latencyInfoListener);
model.setRowCount(0);
}
private void exportData() {
// 导出为txt文件
FILEChooserPane fileChooserPane = FILEChooserPane.getMultiEnvInstance(true, false);
String fileName = "latency_log_" + GeneralUtils.objectToString(new Date()).replaceAll(":", "_");
fileChooserPane.setFileNameTextField(fileName, ".txt");
fileChooserPane.addChooseFILEFilter(new ChooseFileFilter(FileExtension.TXT));
int saveValue = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame());
if (saveValue == FILEChooserPane.JOPTIONPANE_OK_OPTION || saveValue == FILEChooserPane.OK_OPTION) {
FILE target = fileChooserPane.getSelectedFILE();
try {
target.mkfile();
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(target.getPath(), true))) {
bufferedWriter.write(UILatencyWorker.getInstance().getLatencyData());
}
} catch (Exception exp) {
FineLoggerFactory.getLogger().error("[Latency] Error export latency log.", exp);
}
}
}
private final Listener<LatencyInfo> latencyInfoListener = new Listener<LatencyInfo>() {
@Override
public void on(Event event, LatencyInfo latencyInfo) {
SwingUtilities.invokeLater(() -> {
// 存量卡顿堆栈信息更新
for (int i = 0; i < model.getRowCount(); i++) {
if (latencyInfo.getSeq() == (Long) model.getValueAt(i, 0)) {
model.removeRow(i);
break;
}
}
model.addRow(parseInfo2Row(latencyInfo));
});
}
};
private Object[] parseInfo2Row(LatencyInfo latencyInfo) {
return new Object[]{
latencyInfo.getSeq(),
latencyInfo.getCost(),
UIMonitorHelper.convertStack(latencyInfo.getDetailStack())};
}
static class StackPane extends BasicPane {
public StackPane(String stack) {
setLayout(new BorderLayout());
UITextArea textArea = new UITextArea();
textArea.setBorder(null);
textArea.setEditable(false);
textArea.setText(stack);
UIScrollPane scrollPane = new UIScrollPane(textArea);
scrollPane.setBorder(FineBorderFactory.createWrappedRoundBorder());
add(scrollPane);
SwingUtilities.invokeLater(() -> scrollPane.getViewport().setViewPosition(new Point(0, 0)));
}
@Override
protected String title4PopupWindow() {
return "Latency Stack";
}
}
}