screen generator progress

This commit is contained in:
rusefi 2020-05-01 13:35:34 -04:00
parent eb480c8cc7
commit 4e115c12c1
8 changed files with 117 additions and 76 deletions

View File

@ -1,6 +1,5 @@
package com.rusefi;
import com.opensr5.ini.DialogModel;
import com.opensr5.ini.IniFileModel;
import com.rusefi.xml.*;
@ -16,18 +15,20 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class ScreenGenerator {
public static final String TS_DIALOG = "com.efiAnalytics.ui.dg";
public static final String PNG = "png";
private static final int MENU_CLICK_DELAY = 300;
private static final int TOP_MENU_CLICK_DELAY = 1000;
private static final String PNG = "png";
private static ArrayList<AbstractButton> topLevelButtons = new ArrayList<>();
private static final int MENU_CLICK_DELAY = 50;
private static final int TOP_MENU_CLICK_DELAY = 200;
private static final int WAITING_FOR_FRAME_PERIOD = 1000;
private static final String DESTINATION = "images" + File.separator;
static Content content = new Content();
static ContentModel contentModel = new ContentModel();
static IniFileModel iniFileModel = new IniFileModel();
static Map<String, DialogModel.Field> byCleanUiName = new TreeMap<>();
static Map<String, com.opensr5.ini.DialogModel.Field> byCleanUiName = new TreeMap<>();
public static void main(String[] args) throws Exception {
if (args.length != 1) {
@ -37,7 +38,7 @@ public class ScreenGenerator {
iniFileModel.readIniFile(".");
for (Map.Entry<String, DialogModel.Field> a : iniFileModel.getAllFields().entrySet()) {
for (Map.Entry<String, com.opensr5.ini.DialogModel.Field> a : iniFileModel.getAllFields().entrySet()) {
String cleanUiName = cleanName(a.getValue().getUiName());
byCleanUiName.put(cleanUiName, a.getValue());
}
@ -50,7 +51,7 @@ public class ScreenGenerator {
new File(DESTINATION).mkdirs();
System.out.println("Launching TunerStudioIntegraion");
Frame mainFrame = TunerStudioIntegraion.findMainFrame();
Frame mainFrame = TunerStudioIntegration.findMainFrame();
waitForMainFrame(mainFrame);
@ -58,7 +59,7 @@ public class ScreenGenerator {
handleTopLevelButtons(mainFrame, topLevelButtons);
XmlUtil.writeXml(content);
XmlUtil.writeXml(contentModel);
}
private static void waitForMainFrame(Frame mainFrame) throws InterruptedException {
@ -68,47 +69,50 @@ public class ScreenGenerator {
AbstractButton ab = (AbstractButton) component;
System.out.println("topLevelButton " + ab.getText());
if (TunerStudioIntegraion.isTopLevelMenuButton(component)) {
if (TunerStudioIntegration.isTopLevelMenuButton(component)) {
topLevelButtons.add(ab);
}
}
});
Thread.sleep(1000);
Thread.sleep(WAITING_FOR_FRAME_PERIOD);
}
}
private static void handleTopLevelButtons(Frame frame, ArrayList<AbstractButton> topLevelButtons) throws Exception {
for (AbstractButton topLevel : topLevelButtons) {
handleTopLevelButton(frame, topLevel, content);
handleTopLevelButton(frame, topLevel);
}
}
private static void handleTopLevelButton(Frame frame, AbstractButton topLevel, Content content) throws Exception {
private static void handleTopLevelButton(Frame frame, AbstractButton topLevel) throws Exception {
SwingUtilities.invokeAndWait(topLevel::doClick);
Thread.sleep(TOP_MENU_CLICK_DELAY);
TopLevelMenu topLevelMenu = new TopLevelMenu(topLevel.getText());
ScreenGenerator.content.getTopLevelMenus().add(topLevelMenu);
String imageName = "top_level_" + cleanName(topLevel.getText()) + "." + PNG;
TopLevelMenuModel topLevelMenuModel = new TopLevelMenuModel(topLevel.getText(), imageName);
ScreenGenerator.contentModel.getTopLevelMenus().add(topLevelMenuModel);
ImageIO.write(
UiUtils.getScreenShot(frame),
"png",
new File(DESTINATION + cleanName(topLevel.getText()) + ".png"));
PNG,
new File(DESTINATION + imageName));
List<JMenuItem> menuItems = TunerStudioIntegraion.findMenuItems(frame);
List<JMenuItem> menuItems = TunerStudioIntegration.findMenuItems(frame);
for (JMenuItem menuItem : menuItems) {
handleMenuItem(menuItem, topLevelMenu);
handleMenuItem(menuItem, topLevelMenuModel);
}
}
private static void handleMenuItem(JMenuItem menuItem, TopLevelMenu topLevelMenu) throws InterruptedException, InvocationTargetException {
private static void handleMenuItem(JMenuItem menuItem, TopLevelMenuModel topLevelMenuModel) throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(menuItem::doClick);
Thread.sleep(MENU_CLICK_DELAY);
AtomicReference<JDialog> ref = new AtomicReference<>();
SwingUtilities.invokeAndWait(() -> ref.set(TunerStudioIntegraion.findDynamicDialog()));
SwingUtilities.invokeAndWait(() -> ref.set(TunerStudioIntegration.findDynamicDialog()));
// let's give it time to appear on the screen
Thread.sleep(MENU_CLICK_DELAY);
JDialog dialog = ref.get();
@ -119,13 +123,13 @@ public class ScreenGenerator {
String dialogTitle = dialog.getTitle();
DialogDescription dialogDescription = new DialogDescription(dialogTitle);
topLevelMenu.getDialogs().add(dialogDescription);
String imageName = "dialog_" + cleanName(dialogTitle) + "." + PNG;
DialogModel dialogModel = new DialogModel(dialogTitle, imageName);
topLevelMenuModel.getDialogs().add(dialogModel);
SwingUtilities.invokeAndWait(() -> {
try {
findSlices(dialog, dialogDescription);
findSlices(dialog, dialogModel);
if (dialog == null) {
// this happens for example for disabled menu items
@ -141,7 +145,7 @@ public class ScreenGenerator {
ImageIO.write(
dialogScreenShot,
PNG,
new File(DESTINATION + cleanName(dialogTitle) + ".png"));
new File(DESTINATION + imageName));
dialog.setVisible(false);
dialog.dispose();
} catch (Exception e) {
@ -150,7 +154,7 @@ public class ScreenGenerator {
});
}
private static void saveSlices(String dialogTitle, Map<Integer, String> yCoordinates, BufferedImage dialogScreenShot, DialogDescription dialogDescription) {
private static void saveSlices(String dialogTitle, Map<Integer, String> yCoordinates, BufferedImage dialogScreenShot, DialogModel dialogModel) {
System.out.println("Label Y coordinates: " + yCoordinates);
yCoordinates.put(0, "top");
yCoordinates.put(dialogScreenShot.getHeight(), "bottom");
@ -176,16 +180,16 @@ public class ScreenGenerator {
System.out.println("Weird");
continue;
}
String fileName = cleanName(dialogTitle) + "_slice_" + fromY + "_" + sectionName + ".png";
String fileName = cleanName(dialogTitle) + "_slice_" + fromY + "_" + sectionName + "." + PNG;
DialogModel.Field f = byCleanUiName.get(sectionName);
com.opensr5.ini.DialogModel.Field f = byCleanUiName.get(sectionName);
if (f == null)
continue;
String fieldName = f.getKey();
String tooltip = iniFileModel.tooltips.get(fieldName);
dialogDescription.fields.add(new FieldDescription(sectionNameWithSpecialCharacters, fieldName, fileName, tooltip));
dialogModel.fields.add(new FieldModel(sectionNameWithSpecialCharacters, fieldName, fileName, tooltip));
File output = new File(DESTINATION + fileName);
if (output == null) {
@ -201,19 +205,19 @@ public class ScreenGenerator {
}
}
private static void findSlices(JDialog dialog, DialogDescription dialogDescription) {
private static void findSlices(JDialog dialog, DialogModel dialogModel) {
UiUtils.visitComponents(dialog, "Dynamic dialog", new Callback() {
@Override
public void onComponent(Component parent, Component component) {
if (component instanceof JPanel) {
JPanel panel = (JPanel) component;
handleBox(dialog.getTitle(), panel, dialogDescription);
handleBox(dialog.getTitle(), panel, dialogModel);
}
}
});
}
private static void handleBox(String dialogTitle, JPanel panel, DialogDescription dialogDescription) {
private static void handleBox(String dialogTitle, JPanel panel, DialogModel dialogModel) {
if (panel.getLayout() instanceof BoxLayout) {
BoxLayout layout = (BoxLayout) panel.getLayout();
if (layout.getAxis() == BoxLayout.X_AXIS)
@ -244,7 +248,7 @@ public class ScreenGenerator {
}
});
saveSlices(dialogTitle, yCoordinates, panelImage, dialogDescription);
saveSlices(dialogTitle, yCoordinates, panelImage, dialogModel);
}
}

View File

@ -5,15 +5,29 @@ import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class TunerStudioIntegraion {
public class TunerStudioIntegration {
/**
* these magic class names are specific to TS build
* At the moment we use 3.1.02 names
* http://www.tunerstudio.com/downloads2/TunerStudioMS_Setup_v3.1.02.exe
*/
private static final String VERSION = "3.1.02";
private static final String TS_DIALOG = "com.efiAnalytics.ui.dg";
private static final String TS_POPUP_MAIN_MENU = "aH.gc";
private static final String TUNER_STUDIO = "TunerStudio";
static Frame findMainFrame() throws InterruptedException {
while (true) {
Frame[] all = JFrame.getFrames();
for (Frame frame : all) {
System.out.println("I see " + frame.getTitle());
if (frame.getTitle().contains("TunerStudio")) {
String frameTitle = frame.getTitle();
System.out.println("I see " + frameTitle);
if (frameTitle.contains(TUNER_STUDIO)) {
if (!frameTitle.contains(VERSION)) {
System.out.println("Title does not look right " + frameTitle + " not " + VERSION);
System.exit(-1);
}
return frame;
}
}
@ -28,7 +42,7 @@ public class TunerStudioIntegraion {
static java.util.List<JMenuItem> findMenuItems(Frame frame) {
List<JMenuItem> menuItems = new ArrayList<>();
UiUtils.visitComponents(frame, "Just clicked ", (parent, component) -> {
if (component instanceof JMenuItem && component.getClass().getName().endsWith("aH.gc")) {
if (component instanceof JMenuItem && component.getClass().getName().endsWith(TS_POPUP_MAIN_MENU)) {
JMenuItem menuItem = (JMenuItem) component;
System.out.println("Menu item " + menuItem.getText());
menuItems.add(menuItem);
@ -39,7 +53,7 @@ public class TunerStudioIntegraion {
static JDialog findDynamicDialog() {
for (Window d : Dialog.getWindows()) {
if (d.getClass().getName().equals(ScreenGenerator.TS_DIALOG) && d.isVisible()) {
if (d.getClass().getName().equals(TS_DIALOG) && d.isVisible()) {
return (JDialog) d;
}
}

View File

@ -1,18 +0,0 @@
package com.rusefi.xml;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement
public class Content {
private List<TopLevelMenu> menus = new ArrayList<>();
@XmlElementWrapper
@XmlElement(name = "keyword")
public List<TopLevelMenu> getTopLevelMenus() {
return menus;
}
}

View File

@ -0,0 +1,27 @@
package com.rusefi.xml;
import com.rusefi.ScreenGenerator;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@XmlRootElement
public class ContentModel {
private List<TopLevelMenuModel> menus = new ArrayList<>();
@XmlElementWrapper
@XmlElement(name = "keyword")
public List<TopLevelMenuModel> getTopLevelMenus() {
return menus;
}
@XmlAttribute
public String getVersion() {
return "Generated by " + ScreenGenerator.class + " on " + new Date();
}
}

View File

@ -6,14 +6,21 @@ import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.ArrayList;
import java.util.List;
public class DialogDescription {
public class DialogModel {
private final String dialogTitle;
private final String imageName;
@XmlElementWrapper
@XmlElement(name = "field")
public List<FieldDescription> fields = new ArrayList<>();
public List<FieldModel> fields = new ArrayList<>();
public DialogDescription(String dialogTitle) {
public DialogModel(String dialogTitle, String imageName) {
this.dialogTitle = dialogTitle;
this.imageName = imageName;
}
@XmlAttribute
public String getImageName() {
return imageName;
}
@XmlAttribute

View File

@ -2,17 +2,17 @@ package com.rusefi.xml;
import javax.xml.bind.annotation.XmlAttribute;
public class FieldDescription {
public class FieldModel {
private final String uiName;
private final String fieldName;
private final String fileName;
private final String imageName;
private final String tooltip;
public FieldDescription(String uiName, String fieldName, String fileName, String tooltip) {
public FieldModel(String uiName, String fieldName, String fileName, String tooltip) {
this.uiName = uiName;
this.fieldName = fieldName;
this.fileName = fileName;
this.imageName = fileName;
this.tooltip = tooltip == null ? "" : tooltip;
}
@ -27,8 +27,8 @@ public class FieldDescription {
}
@XmlAttribute
public String getFileName() {
return fileName;
public String getImageName() {
return imageName;
}
@XmlAttribute

View File

@ -6,15 +6,17 @@ import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.ArrayList;
import java.util.List;
public class TopLevelMenu {
public class TopLevelMenuModel {
private final String title;
private final String imageName;
@XmlElementWrapper
@XmlElement(name = "dialog")
private List<DialogDescription> dialogs = new ArrayList<>();
private List<DialogModel> dialogs = new ArrayList<>();
public TopLevelMenu(String title) {
public TopLevelMenuModel(String title, String imageName) {
this.title = title;
this.imageName = imageName;
}
@XmlAttribute
@ -22,7 +24,12 @@ public class TopLevelMenu {
return title;
}
public List<DialogDescription> getDialogs() {
@XmlAttribute
public String getImageName() {
return imageName;
}
public List<DialogModel> getDialogs() {
return dialogs;
}
}

View File

@ -11,17 +11,17 @@ public class XmlUtil {
public static final String FILE_NAME = "output.xml";
public static void writeXml(Content content) throws JAXBException, IOException {
JAXBContext jaxbContext = JAXBContext.newInstance(Content.class);
public static void writeXml(ContentModel contentModel) throws JAXBException, IOException {
JAXBContext jaxbContext = JAXBContext.newInstance(ContentModel.class);
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter xmlWriter = new StringWriter();
marshaller.marshal(content, xmlWriter);
marshaller.marshal(contentModel, xmlWriter);
System.out.println(xmlWriter.toString());
System.out.println("Writing " + FILE_NAME);
marshaller.marshal(content, new FileWriter(FILE_NAME));
marshaller.marshal(contentModel, new FileWriter(FILE_NAME));
System.out.println("Done " + FILE_NAME);
}
}