mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 09:12:09 +10:00
generalize caching
This commit is contained in:
@@ -252,4 +252,9 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
|
|||||||
public boolean canPointMoveFreely(int pointIndex) {
|
public boolean canPointMoveFreely(int pointIndex) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.awt.Point;
|
|||||||
import java.awt.geom.CubicCurve2D;
|
import java.awt.geom.CubicCurve2D;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||||
@@ -361,6 +362,28 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
int minX = Integer.MAX_VALUE;
|
||||||
|
int maxX = Integer.MIN_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE;
|
||||||
|
int maxY = Integer.MIN_VALUE;
|
||||||
|
int margin = 50; // hard coded, replace with something meaningful
|
||||||
|
for (int i = 0; i < getControlPointCount(); i++) {
|
||||||
|
Point p = getControlPoint(i);
|
||||||
|
if (p.x < minX)
|
||||||
|
minX = p.x;
|
||||||
|
if (p.x > maxX)
|
||||||
|
maxX = p.x;
|
||||||
|
if (p.y < minY)
|
||||||
|
minY = p.y;
|
||||||
|
if (p.y > maxY)
|
||||||
|
maxY = p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
|
||||||
|
}
|
||||||
|
|
||||||
public enum PointCount {
|
public enum PointCount {
|
||||||
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
|
TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package org.diylc.core;
|
|||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.diylc.core.annotations.ComponentDescriptor;
|
import org.diylc.core.annotations.ComponentDescriptor;
|
||||||
@@ -190,4 +191,10 @@ public interface IDIYComponent<T> extends Serializable, Cloneable {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean equalsTo(IDIYComponent<?> other);
|
boolean equalsTo(IDIYComponent<?> other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used only if {@link ComponentDescriptor#enableCache()} is set to true.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Rectangle2D getCachingBounds();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
|
||||||
|
*
|
||||||
|
* This file is part of DIYLC.
|
||||||
|
*
|
||||||
|
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||||
|
* General Public License as published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.diylc.presenter;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class Counter {
|
||||||
|
|
||||||
|
private int count;
|
||||||
|
private long nanotime;
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getNanoTime() {
|
||||||
|
return nanotime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(long nanotime) {
|
||||||
|
count++;
|
||||||
|
this.nanotime += nanotime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%dx %dms", count, TimeUnit.MILLISECONDS.convert(nanotime, TimeUnit.NANOSECONDS));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,15 +19,19 @@ package org.diylc.presenter;
|
|||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
import java.awt.geom.Area;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.diylc.common.ComponentType;
|
import org.diylc.common.ComponentType;
|
||||||
import org.diylc.core.ComponentState;
|
import org.diylc.core.ComponentState;
|
||||||
import org.diylc.core.IDIYComponent;
|
import org.diylc.core.IDIYComponent;
|
||||||
import org.diylc.core.Project;
|
import org.diylc.core.Project;
|
||||||
|
import org.diylc.utils.Pair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying
|
* A layer that injects itself between the provided {@link G2DWrapper} instance and the underlying
|
||||||
@@ -39,8 +43,9 @@ import org.diylc.core.Project;
|
|||||||
*/
|
*/
|
||||||
public class DrawingCache {
|
public class DrawingCache {
|
||||||
|
|
||||||
private Map<IDIYComponent<?>, CacheValue> imageCache =
|
private Map<IDIYComponent<?>, CacheValue> imageCache = new HashMap<IDIYComponent<?>, CacheValue>();
|
||||||
new HashMap<IDIYComponent<?>, CacheValue>();
|
|
||||||
|
private Map<String, Pair<Counter, Counter>> renderStatsByType = new HashMap<String, Pair<Counter, Counter>>();
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(DrawingCache.class);
|
private static final Logger LOG = Logger.getLogger(DrawingCache.class);
|
||||||
|
|
||||||
@@ -55,7 +60,6 @@ public class DrawingCache {
|
|||||||
if (type.getEnableCache()) {
|
if (type.getEnableCache()) {
|
||||||
// if we need to apply caching
|
// if we need to apply caching
|
||||||
Point firstPoint = component.getControlPoint(0);
|
Point firstPoint = component.getControlPoint(0);
|
||||||
Point lastPoint = component.getControlPoint(component.getControlPointCount() - 1);
|
|
||||||
|
|
||||||
// cache hit!
|
// cache hit!
|
||||||
CacheValue value = null;
|
CacheValue value = null;
|
||||||
@@ -66,14 +70,22 @@ public class DrawingCache {
|
|||||||
if (value == null || !value.getComponent().equalsTo(component)
|
if (value == null || !value.getComponent().equalsTo(component)
|
||||||
|| value.getState() != componentState || value.getZoom() != zoom) {
|
|| value.getState() != componentState || value.getZoom() != zoom) {
|
||||||
LOG.trace("Rendering " + component.getName() + " for cache.");
|
LOG.trace("Rendering " + component.getName() + " for cache.");
|
||||||
int width = (int) (Math.abs(firstPoint.x - lastPoint.x) * zoom) + 2;
|
Rectangle2D rect = component.getCachingBounds();
|
||||||
int height = (int) (Math.abs(firstPoint.y - lastPoint.y) * zoom) + 2;
|
int width = (int)Math.round(rect.getWidth() * zoom);
|
||||||
|
int height = (int)Math.round(rect.getHeight() * zoom);
|
||||||
|
// calculate the position of the first point relative to the caching bounds
|
||||||
|
int dx = (int) (firstPoint.x - rect.getX());
|
||||||
|
int dy = (int) (firstPoint.y - rect.getY());
|
||||||
|
|
||||||
|
// create image
|
||||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
// create graphics
|
||||||
Graphics2D cg2d = image.createGraphics();
|
Graphics2D cg2d = image.createGraphics();
|
||||||
|
|
||||||
// copy over rendering settings
|
// copy over rendering settings so our cached image has the same features
|
||||||
cg2d.setRenderingHints(g2d.getRenderingHints());
|
cg2d.setRenderingHints(g2d.getRenderingHints());
|
||||||
|
|
||||||
|
// set clip bounds to the whole image
|
||||||
cg2d.setClip(0, 0, width, height);
|
cg2d.setClip(0, 0, width, height);
|
||||||
|
|
||||||
// apply zoom
|
// apply zoom
|
||||||
@@ -81,24 +93,41 @@ public class DrawingCache {
|
|||||||
cg2d.scale(zoom, zoom);
|
cg2d.scale(zoom, zoom);
|
||||||
}
|
}
|
||||||
// translate to make the top-left corner of the component match (0, 0)
|
// translate to make the top-left corner of the component match (0, 0)
|
||||||
cg2d.translate(-firstPoint.x, -firstPoint.y);
|
cg2d.translate(-firstPoint.x + dx, -firstPoint.y + dy);
|
||||||
|
|
||||||
// wrap the graphics so we can track
|
// wrap the graphics so we can track
|
||||||
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
|
G2DWrapper wrapper = new G2DWrapper(cg2d, zoom);
|
||||||
|
|
||||||
|
// initialize wrapper
|
||||||
wrapper.startedDrawingComponent();
|
wrapper.startedDrawingComponent();
|
||||||
if (!trackArea) {
|
if (!trackArea) {
|
||||||
wrapper.stopTracking();
|
wrapper.stopTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long componentStart = System.nanoTime();
|
||||||
|
|
||||||
// now draw the component to the buffer image
|
// now draw the component to the buffer image
|
||||||
component.draw(wrapper, componentState, outlineMode, project, wrapper);
|
component.draw(wrapper, componentState, outlineMode, project, wrapper);
|
||||||
|
|
||||||
|
long componentEnd = System.nanoTime();
|
||||||
|
|
||||||
|
Pair<Counter, Counter> stats;
|
||||||
|
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
|
||||||
|
if (renderStatsByType.containsKey(key)) {
|
||||||
|
stats = renderStatsByType.get(key);
|
||||||
|
} else {
|
||||||
|
stats = new Pair<Counter, Counter>(new Counter(), new Counter());
|
||||||
|
renderStatsByType.put(key, stats);
|
||||||
|
}
|
||||||
|
stats.getFirst().add(componentEnd - componentStart);
|
||||||
|
|
||||||
|
// finalize wrapper
|
||||||
wrapper.finishedDrawingComponent();
|
wrapper.finishedDrawingComponent();
|
||||||
|
|
||||||
cg2d.dispose();
|
cg2d.dispose();
|
||||||
|
|
||||||
// File outputfile = new File("d:\\image_" + component.getName() + ".png");
|
// output cached drawings to separate files
|
||||||
|
// File outputfile = new File("d:\\tmp\\image_" + component.getName() + ".png");
|
||||||
// try {
|
// try {
|
||||||
// ImageIO.write(image, "png", outputfile);
|
// ImageIO.write(image, "png", outputfile);
|
||||||
// } catch (IOException e) {
|
// } catch (IOException e) {
|
||||||
@@ -106,33 +135,60 @@ public class DrawingCache {
|
|||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
value = new CacheValue(component, image, wrapper, componentState, zoom);
|
// add to the cache
|
||||||
|
value = new CacheValue(component, image, wrapper.getCurrentArea(), wrapper.getContinuityPositiveAreas(),
|
||||||
|
wrapper.getContinuityNegativeAreas(), componentState, zoom, dx, dy);
|
||||||
imageCache.put(component, value);
|
imageCache.put(component, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long componentStart = System.nanoTime();
|
||||||
|
|
||||||
// temporarily scale the graphic to compensate for the zoom, since we are rendering an image with the zoom appled
|
// temporarily scale the graphic to compensate for the zoom, since we are rendering an image with the zoom appled
|
||||||
if (Math.abs(1.0 - zoom) > 1e-4) {
|
if (Math.abs(1.0 - zoom) > 1e-4) {
|
||||||
g2d.getCanvasGraphics().scale(1 / zoom, 1 / zoom);
|
g2d.getCanvasGraphics().scale(1 / zoom, 1 / zoom);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// draw cached image
|
// draw cached image
|
||||||
g2d.getCanvasGraphics().drawImage(value.getImage(), (int) (firstPoint.x * zoom),
|
g2d.getCanvasGraphics().drawImage(value.getImage(), (int) ((firstPoint.x - value.getDx()) * zoom),
|
||||||
(int) (firstPoint.y * zoom), null);
|
(int) ((firstPoint.y - value.getDy())* zoom), null);
|
||||||
} finally {
|
} finally {
|
||||||
if (Math.abs(1.0 - zoom) > 1e-4) {
|
if (Math.abs(1.0 - zoom) > 1e-4) {
|
||||||
g2d.getCanvasGraphics().scale(zoom, zoom);
|
g2d.getCanvasGraphics().scale(zoom, zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long componentEnd = System.nanoTime();
|
||||||
|
|
||||||
|
Pair<Counter, Counter> stats;
|
||||||
|
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
|
||||||
|
if (renderStatsByType.containsKey(key)) {
|
||||||
|
stats = renderStatsByType.get(key);
|
||||||
|
} else {
|
||||||
|
stats = new Pair<Counter, Counter>(new Counter(), new Counter());
|
||||||
|
renderStatsByType.put(key, stats);
|
||||||
|
}
|
||||||
|
stats.getSecond().add(componentEnd - componentStart);
|
||||||
|
|
||||||
// copy over tracking area from the cache
|
// copy over tracking area from the cache
|
||||||
g2d.merge(value.getWrapper());
|
g2d.merge(value.getCurrentArea(), value.getContinuityPositiveAreas(), value.getContinuityNegativeAreas());
|
||||||
} else {
|
} else {
|
||||||
// no caching, just draw as usual
|
// no caching, just draw as usual
|
||||||
component.draw(g2d, componentState, outlineMode, project, g2d);
|
component.draw(g2d, componentState, outlineMode, project, g2d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void logStats() {
|
||||||
|
int totalSizeMB = imageCache.values().stream().map(x -> x.image.getData().getDataBuffer().getSize()).reduce(0, Integer::sum) * 4 / 1024 / 1024; // 4 bytes per pixel
|
||||||
|
LOG.debug(String.format("Render cache contains %d elements, approx size is %d MB", imageCache.size(), totalSizeMB));
|
||||||
|
|
||||||
|
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -Long.compare(e1.getValue().getFirst().getNanoTime() + e1.getValue().getSecond().getNanoTime(),
|
||||||
|
e2.getValue().getFirst().getNanoTime() + e2.getValue().getSecond().getNanoTime()))
|
||||||
|
.map(e -> e.getKey() + ": render: " + e.getValue().getFirst() + ", paste: " + e.getValue().getSecond())
|
||||||
|
.collect(Collectors.joining("; ", "{", "}"));
|
||||||
|
|
||||||
|
LOG.debug("Cache render distribution stats: " + mapAsString);
|
||||||
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
imageCache.clear();
|
imageCache.clear();
|
||||||
}
|
}
|
||||||
@@ -140,12 +196,17 @@ public class DrawingCache {
|
|||||||
private class CacheValue {
|
private class CacheValue {
|
||||||
IDIYComponent<?> component;
|
IDIYComponent<?> component;
|
||||||
BufferedImage image;
|
BufferedImage image;
|
||||||
G2DWrapper wrapper;
|
Area currentArea;
|
||||||
|
Map<String, Area> continuityPositiveAreas;
|
||||||
|
Map<String, Area> continuityNegativeAreas;
|
||||||
ComponentState state;
|
ComponentState state;
|
||||||
double zoom;
|
double zoom;
|
||||||
|
int dx;
|
||||||
|
int dy;
|
||||||
|
|
||||||
public CacheValue(IDIYComponent<?> component, BufferedImage image, G2DWrapper wrapper,
|
public CacheValue(IDIYComponent<?> component, BufferedImage image, Area currentArea,
|
||||||
ComponentState state, double zoom) {
|
Map<String, Area> continuityPositiveAreas, Map<String, Area> continuityNegativeAreas,
|
||||||
|
ComponentState state, double zoom, int dx, int dy) {
|
||||||
super();
|
super();
|
||||||
// take a copy of the component, so we can check if it changed in the meantime
|
// take a copy of the component, so we can check if it changed in the meantime
|
||||||
try {
|
try {
|
||||||
@@ -153,9 +214,13 @@ public class DrawingCache {
|
|||||||
} catch (CloneNotSupportedException e) {
|
} catch (CloneNotSupportedException e) {
|
||||||
}
|
}
|
||||||
this.image = image;
|
this.image = image;
|
||||||
this.wrapper = wrapper;
|
this.currentArea = currentArea;
|
||||||
|
this.continuityPositiveAreas = continuityPositiveAreas;
|
||||||
|
this.continuityNegativeAreas = continuityNegativeAreas;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.zoom = zoom;
|
this.zoom = zoom;
|
||||||
|
this.dx = dx;
|
||||||
|
this.dy = dy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDIYComponent<?> getComponent() {
|
public IDIYComponent<?> getComponent() {
|
||||||
@@ -166,8 +231,16 @@ public class DrawingCache {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public G2DWrapper getWrapper() {
|
public Area getCurrentArea() {
|
||||||
return wrapper;
|
return currentArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Area> getContinuityPositiveAreas() {
|
||||||
|
return continuityPositiveAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Area> getContinuityNegativeAreas() {
|
||||||
|
return continuityNegativeAreas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComponentState getState() {
|
public ComponentState getState() {
|
||||||
@@ -178,6 +251,14 @@ public class DrawingCache {
|
|||||||
return zoom;
|
return zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDx() {
|
||||||
|
return dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDy() {
|
||||||
|
return dy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return component.getName() + ":" + state + ":" + zoom;
|
return component.getName() + ":" + state + ":" + zoom;
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ import org.diylc.core.Project;
|
|||||||
import org.diylc.core.Theme;
|
import org.diylc.core.Theme;
|
||||||
import org.diylc.core.VisibilityPolicy;
|
import org.diylc.core.VisibilityPolicy;
|
||||||
import org.diylc.utils.Constants;
|
import org.diylc.utils.Constants;
|
||||||
import org.diylc.utils.Pair;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken
|
* Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken
|
||||||
@@ -109,7 +108,7 @@ public class DrawingManager {
|
|||||||
private boolean debugContinuityAreas;
|
private boolean debugContinuityAreas;
|
||||||
|
|
||||||
// rendering stats
|
// rendering stats
|
||||||
private Map<String, Pair<Integer, Long>> renderStatsByType = new HashMap<String, Pair<Integer, Long>>();
|
private Map<String, Counter> renderStatsByType = new HashMap<String, Counter>();
|
||||||
private long lastStatsReportedTime = System.currentTimeMillis();
|
private long lastStatsReportedTime = System.currentTimeMillis();
|
||||||
private long statReportFrequencyMs = 1000 * 60;
|
private long statReportFrequencyMs = 1000 * 60;
|
||||||
|
|
||||||
@@ -305,26 +304,15 @@ public class DrawingManager {
|
|||||||
} finally {
|
} finally {
|
||||||
// record render stats
|
// record render stats
|
||||||
long componentEnd = System.nanoTime();
|
long componentEnd = System.nanoTime();
|
||||||
Pair<Integer, Long> stats = null;
|
Counter stats = null;
|
||||||
String key = component.getClass().getCanonicalName();
|
String key = component.getClass().getCanonicalName().replace("org.diylc.components.", "");
|
||||||
if (renderStatsByType.containsKey(key)) {
|
if (renderStatsByType.containsKey(key)) {
|
||||||
stats = renderStatsByType.get(key);
|
stats = renderStatsByType.get(key);
|
||||||
stats.setFirst(stats.getFirst() + 1);
|
|
||||||
stats.setSecond(stats.getSecond() + (componentEnd - componentStart));
|
|
||||||
} else {
|
} else {
|
||||||
stats = new Pair<Integer, Long>(1, componentEnd - componentStart);
|
stats = new Counter();
|
||||||
renderStatsByType.put(key, stats);
|
renderStatsByType.put(key, stats);
|
||||||
}
|
}
|
||||||
|
stats.add(componentEnd - componentStart);
|
||||||
// log render time stats periodically
|
|
||||||
if (System.currentTimeMillis() - lastStatsReportedTime > statReportFrequencyMs) {
|
|
||||||
lastStatsReportedTime = System.currentTimeMillis();
|
|
||||||
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -e1.getValue().getSecond().compareTo(e2.getValue().getSecond()))
|
|
||||||
.map(e -> e.getKey() + "=" + e.getValue().getFirst() + "x " +
|
|
||||||
TimeUnit.MILLISECONDS.convert( e.getValue().getSecond(), TimeUnit.NANOSECONDS) + "ms ")
|
|
||||||
.collect(Collectors.joining(", ", "{", "}"));
|
|
||||||
LOG.debug("Render stats: " + mapAsString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ComponentArea area = g2dWrapper.finishedDrawingComponent();
|
ComponentArea area = g2dWrapper.finishedDrawingComponent();
|
||||||
if (trackArea && area != null && !area.getOutlineArea().isEmpty()) {
|
if (trackArea && area != null && !area.getOutlineArea().isEmpty()) {
|
||||||
@@ -470,9 +458,23 @@ public class DrawingManager {
|
|||||||
long ms = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS);
|
long ms = TimeUnit.MILLISECONDS.convert(end - start, TimeUnit.NANOSECONDS);
|
||||||
LOG.trace(String.format("Render time = %d ms", ms));
|
LOG.trace(String.format("Render time = %d ms", ms));
|
||||||
|
|
||||||
|
logStats();
|
||||||
|
|
||||||
return failedComponents;
|
return failedComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void logStats() {
|
||||||
|
// log render time stats periodically
|
||||||
|
if (System.currentTimeMillis() - lastStatsReportedTime > statReportFrequencyMs) {
|
||||||
|
lastStatsReportedTime = System.currentTimeMillis();
|
||||||
|
String mapAsString = renderStatsByType.entrySet().stream().sorted((e1, e2) -> -Long.compare(e1.getValue().getNanoTime(), e2.getValue().getNanoTime()))
|
||||||
|
.map(e -> e.toString())
|
||||||
|
.collect(Collectors.joining("; ", "{", "}"));
|
||||||
|
LOG.debug("Render stats: " + mapAsString);
|
||||||
|
DrawingCache.Instance.logStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double getZoomLevel() {
|
public double getZoomLevel() {
|
||||||
return zoomLevel;
|
return zoomLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,10 +162,26 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
|
|||||||
return new ComponentArea(currentArea, continuityPositiveAreas.values(), continuityNegativeAreas.values());
|
return new ComponentArea(currentArea, continuityPositiveAreas.values(), continuityNegativeAreas.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void merge(G2DWrapper wrapper) {
|
// start - used for caching
|
||||||
currentArea = wrapper.currentArea;
|
|
||||||
continuityPositiveAreas = wrapper.continuityPositiveAreas;
|
public Area getCurrentArea() {
|
||||||
continuityNegativeAreas = wrapper.continuityNegativeAreas;
|
return currentArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Area> getContinuityPositiveAreas() {
|
||||||
|
return continuityPositiveAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Area> getContinuityNegativeAreas() {
|
||||||
|
return continuityNegativeAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end - used for caching
|
||||||
|
|
||||||
|
public void merge(Area currentArea, Map<String, Area> continuityPositiveAreas, Map<String, Area> continuityNegativeAreas) {
|
||||||
|
this.currentArea = currentArea;
|
||||||
|
this.continuityPositiveAreas = continuityPositiveAreas;
|
||||||
|
this.continuityNegativeAreas = continuityNegativeAreas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -669,6 +669,28 @@ public abstract class AbstractLeadedComponent<T> extends AbstractTransparentComp
|
|||||||
return Integer.toString(index + 1);
|
return Integer.toString(index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
int minX = Integer.MAX_VALUE;
|
||||||
|
int maxX = Integer.MIN_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE;
|
||||||
|
int maxY = Integer.MIN_VALUE;
|
||||||
|
int margin = (int) Math.max(Math.max(getWidth().convertToPixels(), getLength().convertToPixels()), getLeadThickness());
|
||||||
|
for (int i = 0; i < getControlPointCount(); i++) {
|
||||||
|
Point p = getControlPoint(i);
|
||||||
|
if (p.x < minX)
|
||||||
|
minX = p.x;
|
||||||
|
if (p.x > maxX)
|
||||||
|
maxX = p.x;
|
||||||
|
if (p.y < minY)
|
||||||
|
minY = p.y;
|
||||||
|
if (p.y > maxY)
|
||||||
|
maxY = p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
|
||||||
|
}
|
||||||
|
|
||||||
public enum LabelOriantation {
|
public enum LabelOriantation {
|
||||||
Directional, Horizontal
|
Directional, Horizontal
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Composite;
|
import java.awt.Composite;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
import org.diylc.awt.StringUtils;
|
import org.diylc.awt.StringUtils;
|
||||||
import org.diylc.common.HorizontalAlignment;
|
import org.diylc.common.HorizontalAlignment;
|
||||||
@@ -333,6 +334,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
|||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
Point finalSecondPoint = getFinalSecondPoint();
|
||||||
|
return new Rectangle2D.Double(firstPoint.x, firstPoint.y, finalSecondPoint.x - firstPoint.x + 1, finalSecondPoint.y - firstPoint.y + 1);
|
||||||
|
}
|
||||||
|
|
||||||
public static enum CoordinateType {
|
public static enum CoordinateType {
|
||||||
Letters, Numbers
|
Letters, Numbers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ import org.diylc.core.measures.SizeUnit;
|
|||||||
@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity",
|
@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity",
|
||||||
instanceNamePrefix = "Trace", description = "Curved copper trace with two control points",
|
instanceNamePrefix = "Trace", description = "Curved copper trace with two control points",
|
||||||
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class)
|
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class,
|
||||||
|
enableCache = true)
|
||||||
public class CurvedTrace extends AbstractCurvedComponent<Void> {
|
public class CurvedTrace extends AbstractCurvedComponent<Void> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.diylc.utils.Constants;
|
|||||||
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
|
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
|
||||||
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
|
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
|
||||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||||
transformer = SimpleComponentTransformer.class)
|
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||||
public class HookupWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
public class HookupWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import org.diylc.utils.Constants;
|
|||||||
@ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic", category = "Connectivity",
|
@ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic", category = "Connectivity",
|
||||||
instanceNamePrefix = "W", description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.COMPONENT,
|
instanceNamePrefix = "W", description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.COMPONENT,
|
||||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||||
transformer = SimpleComponentTransformer.class)
|
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||||
public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ import org.diylc.utils.Constants;
|
|||||||
@ComponentDescriptor(name = "Electrolytic Capacitor (Axial)", author = "Branislav Stojkovic", category = "Passive",
|
@ComponentDescriptor(name = "Electrolytic Capacitor (Axial)", author = "Branislav Stojkovic", category = "Passive",
|
||||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C",
|
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "C",
|
||||||
description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", zOrder = IDIYComponent.COMPONENT,
|
description = "Axial electrolytic capacitor, similar to Sprague Atom, F&T, etc", zOrder = IDIYComponent.COMPONENT,
|
||||||
transformer = SimpleComponentTransformer.class)
|
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||||
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> {
|
public class AxialElectrolyticCapacitor extends AbstractLeadedComponent<Capacitance> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import org.diylc.core.measures.SizeUnit;
|
|||||||
|
|
||||||
@ComponentDescriptor(name = "Resistor", author = "Branislav Stojkovic", category = "Passive",
|
@ComponentDescriptor(name = "Resistor", author = "Branislav Stojkovic", category = "Passive",
|
||||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "Resistor layout symbol",
|
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "R", description = "Resistor layout symbol",
|
||||||
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class)
|
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||||
public class Resistor extends AbstractLeadedComponent<Resistance> {
|
public class Resistor extends AbstractLeadedComponent<Resistance> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ import org.diylc.utils.Constants;
|
|||||||
|
|
||||||
@ComponentDescriptor(name = "DIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
@ComponentDescriptor(name = "DIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
||||||
instanceNamePrefix = "IC", description = "Dual-in-line package IC",
|
instanceNamePrefix = "IC", description = "Dual-in-line package IC",
|
||||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = DIL_ICTransformer.class)
|
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = DIL_ICTransformer.class,
|
||||||
|
enableCache = true)
|
||||||
public class DIL_IC extends AbstractTransparentComponent<String> {
|
public class DIL_IC extends AbstractTransparentComponent<String> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -543,6 +544,28 @@ public class DIL_IC extends AbstractTransparentComponent<String> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
int minX = Integer.MAX_VALUE;
|
||||||
|
int maxX = Integer.MIN_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE;
|
||||||
|
int maxY = Integer.MIN_VALUE;
|
||||||
|
int margin = 50;
|
||||||
|
for (int i = 0; i < getControlPointCount(); i++) {
|
||||||
|
Point p = getControlPoint(i);
|
||||||
|
if (p.x < minX)
|
||||||
|
minX = p.x;
|
||||||
|
if (p.x > maxX)
|
||||||
|
maxX = p.x;
|
||||||
|
if (p.y < minY)
|
||||||
|
minY = p.y;
|
||||||
|
if (p.y > maxY)
|
||||||
|
maxY = p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
|
||||||
|
}
|
||||||
|
|
||||||
public static enum PinCount {
|
public static enum PinCount {
|
||||||
|
|
||||||
_4, _6, _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36, _38, _40, _42, _44, _46, _48, _50;
|
_4, _6, _8, _10, _12, _14, _16, _18, _20, _22, _24, _26, _28, _30, _32, _34, _36, _38, _40, _42, _44, _46, _48, _50;
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ import org.diylc.utils.Constants;
|
|||||||
|
|
||||||
@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors",
|
||||||
instanceNamePrefix = "IC", description = "Single-in-line package IC",
|
instanceNamePrefix = "IC", description = "Single-in-line package IC",
|
||||||
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class)
|
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class,
|
||||||
|
enableCache = true)
|
||||||
public class SIL_IC extends AbstractTransparentComponent<String> {
|
public class SIL_IC extends AbstractTransparentComponent<String> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -431,6 +432,28 @@ public class SIL_IC extends AbstractTransparentComponent<String> {
|
|||||||
this.indentColor = indentColor;
|
this.indentColor = indentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rectangle2D getCachingBounds() {
|
||||||
|
int minX = Integer.MAX_VALUE;
|
||||||
|
int maxX = Integer.MIN_VALUE;
|
||||||
|
int minY = Integer.MAX_VALUE;
|
||||||
|
int maxY = Integer.MIN_VALUE;
|
||||||
|
int margin = 50;
|
||||||
|
for (int i = 0; i < getControlPointCount(); i++) {
|
||||||
|
Point p = getControlPoint(i);
|
||||||
|
if (p.x < minX)
|
||||||
|
minX = p.x;
|
||||||
|
if (p.x > maxX)
|
||||||
|
maxX = p.x;
|
||||||
|
if (p.y < minY)
|
||||||
|
minY = p.y;
|
||||||
|
if (p.y > maxY)
|
||||||
|
maxY = p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin);
|
||||||
|
}
|
||||||
|
|
||||||
public static enum PinCount {
|
public static enum PinCount {
|
||||||
|
|
||||||
_2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20;
|
_2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20;
|
||||||
|
|||||||
@@ -11,5 +11,5 @@
|
|||||||
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <sourceLookupDirector> <sourceContainers duplicates="false"> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;Library&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;DIYLC&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;diylc-core&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;diylc-library&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;default/&gt;&#13;&#10;" typeId="org.eclipse.debug.core.containerType.default"/> </sourceContainers> </sourceLookupDirector> "/>
|
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <sourceLookupDirector> <sourceContainers duplicates="false"> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;Library&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;DIYLC&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;diylc-core&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;javaProject name=&quot;diylc-library&quot;/&gt;&#13;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;default/&gt;&#13;&#10;" typeId="org.eclipse.debug.core.containerType.default"/> </sourceContainers> </sourceLookupDirector> "/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.diylc.DIYLCStarter"/>
|
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.diylc.DIYLCStarter"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/>
|
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms256m -Xmx512m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugContinuityAreas=true -Ddorg.diylc.WriteStaticVariants=true -Ddorg.diylc.debugComponentAreas=true -Dorg.diylc.WriteStaticBlocks=true"/>
|
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms512m -Xmx2048m -Dorg.diylc.scriptRun=true -Ddorg.diylc.debugContinuityAreas=true -Dorg.diylc.debugComponentAreas=true -Ddorg.diylc.WriteStaticVariants=true -Dorg.diylc.WriteStaticBlocks=true"/>
|
||||||
</launchConfiguration>
|
</launchConfiguration>
|
||||||
|
|||||||
Reference in New Issue
Block a user