Added better stuff and new model.
This commit is contained in:
		
							parent
							
								
									db140733ae
								
							
						
					
					
						commit
						7e22602b57
					
				
							
								
								
									
										14
									
								
								README.md
								
								
								
								
							
							
						
						
									
										14
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -1,2 +1,12 @@
 | 
			
		|||
# EntityRelationMappingEditor
 | 
			
		||||
Simple GUI tool to create entity-relational mapping diagrams.
 | 
			
		||||
# Entity-Relation Mapping Editor
 | 
			
		||||
A simple UI for editing entity-relation mapping diagrams.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## How to Use
 | 
			
		||||
The interface and menus should be pretty self-explanatory, but here are some tips to get you started:
 | 
			
		||||
* Click on a relation to select it.
 | 
			
		||||
* You can CTRL + click to select multiple relations.
 | 
			
		||||
* Drag the relations to move them around in the window.
 | 
			
		||||
* Right-click on different areas to access context menus with some helpful actions.
 | 
			
		||||
* When exporting the model to an image, be sure to add the desired image file extension (`.png`, `.jpg`, `.bmp`, etc.), or the application will default to `.png`.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 9.7 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
package nl.andrewlalis.erme.control.actions;
 | 
			
		||||
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
import nl.andrewlalis.erme.model.MappingModel;
 | 
			
		||||
import nl.andrewlalis.erme.view.DiagramPanel;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import java.awt.event.ActionEvent;
 | 
			
		||||
import java.awt.event.InputEvent;
 | 
			
		||||
import java.awt.event.KeyEvent;
 | 
			
		||||
 | 
			
		||||
public class NewModelAction extends AbstractAction {
 | 
			
		||||
	private static NewModelAction instance;
 | 
			
		||||
 | 
			
		||||
	public static NewModelAction getInstance() {
 | 
			
		||||
		if (instance == null) {
 | 
			
		||||
			instance = new NewModelAction();
 | 
			
		||||
		}
 | 
			
		||||
		return instance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Setter
 | 
			
		||||
	private DiagramPanel diagramPanel;
 | 
			
		||||
 | 
			
		||||
	public NewModelAction() {
 | 
			
		||||
		super("New Model");
 | 
			
		||||
		this.putValue(SHORT_DESCRIPTION, "Create a new model.");
 | 
			
		||||
		this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void actionPerformed(ActionEvent e) {
 | 
			
		||||
		this.diagramPanel.setModel(new MappingModel());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,13 @@ public class AddAttributeAction extends AbstractAction {
 | 
			
		|||
				AttributeType.values(),
 | 
			
		||||
				AttributeType.PLAIN
 | 
			
		||||
		);
 | 
			
		||||
		if (type.equals(AttributeType.FOREIGN_KEY)) {
 | 
			
		||||
		boolean shouldUseForeignKey = JOptionPane.showConfirmDialog(
 | 
			
		||||
				c,
 | 
			
		||||
				"Is this attribute a foreign key?",
 | 
			
		||||
				"Foreign Key",
 | 
			
		||||
				JOptionPane.YES_NO_OPTION
 | 
			
		||||
		) == JOptionPane.YES_OPTION;
 | 
			
		||||
		if (shouldUseForeignKey) {
 | 
			
		||||
			if (this.model.getRelations().size() < 2) {
 | 
			
		||||
				JOptionPane.showMessageDialog(c, "There should be at least 2 relations present in the model.", "Not Enough Relations", JOptionPane.WARNING_MESSAGE);
 | 
			
		||||
				return;
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +100,7 @@ public class AddAttributeAction extends AbstractAction {
 | 
			
		|||
					eligibleAttributes.get(0)
 | 
			
		||||
			);
 | 
			
		||||
			if (fkAttribute != null) {
 | 
			
		||||
				r.addAttribute(new ForeignKeyAttribute(r, name, fkAttribute));
 | 
			
		||||
				r.addAttribute(new ForeignKeyAttribute(r, type, name, fkAttribute), index);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			r.addAttribute(new Attribute(r, type, name), index);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,8 +47,8 @@ public class RemoveAttributeAction extends AbstractAction {
 | 
			
		|||
		Relation r = selectedRelations.get(0);
 | 
			
		||||
		Attribute attribute = (Attribute) JOptionPane.showInputDialog(
 | 
			
		||||
				(Component) e.getSource(),
 | 
			
		||||
				"Select the index to insert this attribute at.",
 | 
			
		||||
				"Attribute Index",
 | 
			
		||||
				"Select the attribute to remove.",
 | 
			
		||||
				"Select Attribute",
 | 
			
		||||
				JOptionPane.PLAIN_MESSAGE,
 | 
			
		||||
				null,
 | 
			
		||||
				r.getAttributes().toArray(new Attribute[0]),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ public class Attribute implements Serializable {
 | 
			
		|||
		if (o == null || getClass() != o.getClass()) return false;
 | 
			
		||||
		Attribute attribute = (Attribute) o;
 | 
			
		||||
		return type == attribute.type &&
 | 
			
		||||
				relation.equals(attribute.getRelation()) &&
 | 
			
		||||
				name.equals(attribute.name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +57,6 @@ public class Attribute implements Serializable {
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return this.getName() + ":" + this.getType().name();
 | 
			
		||||
		return this.getName();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,5 @@ package nl.andrewlalis.erme.model;
 | 
			
		|||
public enum AttributeType {
 | 
			
		||||
	PLAIN,
 | 
			
		||||
	ID_KEY,
 | 
			
		||||
	PARTIAL_ID_KEY,
 | 
			
		||||
	FOREIGN_KEY
 | 
			
		||||
	PARTIAL_ID_KEY
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,13 @@ import lombok.Getter;
 | 
			
		|||
public class ForeignKeyAttribute extends Attribute {
 | 
			
		||||
	private Attribute reference;
 | 
			
		||||
 | 
			
		||||
	public ForeignKeyAttribute(Relation relation, String name, Attribute reference) {
 | 
			
		||||
		super(relation, AttributeType.FOREIGN_KEY, name);
 | 
			
		||||
	public ForeignKeyAttribute(Relation relation, AttributeType type, String name, Attribute reference) {
 | 
			
		||||
		super(relation, type, name);
 | 
			
		||||
		this.reference = reference;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public ForeignKeyAttribute(Relation relation, String name, String referencedRelationName, String referencedAttributeName) {
 | 
			
		||||
		this(relation, name, relation.getModel().findAttribute(referencedRelationName, referencedAttributeName));
 | 
			
		||||
	public ForeignKeyAttribute(Relation relation, AttributeType type, String name, String referencedRelationName, String referencedAttributeName) {
 | 
			
		||||
		this(relation, type, name, relation.getModel().findAttribute(referencedRelationName, referencedAttributeName));
 | 
			
		||||
		if (this.getReference() == null) {
 | 
			
		||||
			throw new IllegalArgumentException("Unknown attribute name.");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,4 +22,13 @@ public class ForeignKeyAttribute extends Attribute {
 | 
			
		|||
		this.reference = reference;
 | 
			
		||||
		this.getRelation().getModel().fireChangedEvent();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public String getFullReferenceName() {
 | 
			
		||||
		return this.getReference().getRelation().getName() + "." + this.getReference().getName();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return super.toString() + "->" + this.getFullReferenceName();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,21 @@ public class MappingModel implements Serializable {
 | 
			
		|||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void removeAllReferencingAttributes(Attribute referenced) {
 | 
			
		||||
		for (Relation r : this.getRelations()) {
 | 
			
		||||
			Set<Attribute> removalSet = new HashSet<>();
 | 
			
		||||
			for (Attribute a : r.getAttributes()) {
 | 
			
		||||
				if (a instanceof ForeignKeyAttribute) {
 | 
			
		||||
					ForeignKeyAttribute fkA = (ForeignKeyAttribute) a;
 | 
			
		||||
					if (fkA.getReference().equals(referenced)) {
 | 
			
		||||
						removalSet.add(fkA);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			removalSet.forEach(r::removeAttribute);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void addChangeListener(ModelChangeListener listener) {
 | 
			
		||||
		if (this.changeListeners == null) {
 | 
			
		||||
			this.changeListeners = new HashSet<>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,7 @@ public class Relation implements Serializable {
 | 
			
		|||
 | 
			
		||||
	public void removeAttribute(Attribute attribute) {
 | 
			
		||||
		if (this.attributes.remove(attribute)) {
 | 
			
		||||
			this.model.removeAllReferencingAttributes(attribute);
 | 
			
		||||
			this.model.fireChangedEvent();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -83,4 +84,9 @@ public class Relation implements Serializable {
 | 
			
		|||
	public int hashCode() {
 | 
			
		||||
		return this.getName().hashCode();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return this.getName();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package nl.andrewlalis.erme.view;
 | 
			
		|||
import lombok.Getter;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.ExportToImageAction;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.LoadAction;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.NewModelAction;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.SaveAction;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.edits.AddAttributeAction;
 | 
			
		||||
import nl.andrewlalis.erme.control.actions.edits.AddRelationAction;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +75,7 @@ public class DiagramPanel extends JPanel implements ModelChangeListener {
 | 
			
		|||
	 * Updates all the action singletons with the latest model information.
 | 
			
		||||
	 */
 | 
			
		||||
	private void updateActionModels() {
 | 
			
		||||
		NewModelAction.getInstance().setDiagramPanel(this);
 | 
			
		||||
		SaveAction.getInstance().setModel(this.model);
 | 
			
		||||
		LoadAction.getInstance().setDiagramPanel(this);
 | 
			
		||||
		ExportToImageAction.getInstance().setModel(this.model);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@ public class DiagramPopupMenu extends JPopupMenu {
 | 
			
		|||
		List<Relation> selectedRelations = model.getSelectedRelations();
 | 
			
		||||
		if (selectedRelations.size() == 0) {
 | 
			
		||||
			this.add(AddRelationAction.getInstance());
 | 
			
		||||
			this.add(ExportToImageAction.getInstance());
 | 
			
		||||
		}
 | 
			
		||||
		if (selectedRelations.size() > 0) {
 | 
			
		||||
			this.add(RemoveRelationAction.getInstance());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ public class EditorFrame extends JFrame {
 | 
			
		|||
		model.addRelation(usersRelation);
 | 
			
		||||
		Relation tokensRelation = new Relation(model, new Point(50, 120), "Tokens");
 | 
			
		||||
		tokensRelation.addAttribute(new Attribute(tokensRelation, AttributeType.ID_KEY, "tokenCode"));
 | 
			
		||||
		tokensRelation.addAttribute(new ForeignKeyAttribute(tokensRelation,"username", "Users", "username"));
 | 
			
		||||
		tokensRelation.addAttribute(new ForeignKeyAttribute(tokensRelation, AttributeType.PLAIN, "username", "Users", "username"));
 | 
			
		||||
		tokensRelation.addAttribute(new Attribute(tokensRelation, AttributeType.PLAIN, "expirationDate"));
 | 
			
		||||
		model.addRelation(tokensRelation);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,12 +15,15 @@ public class EditorMenuBar extends JMenuBar {
 | 
			
		|||
	public EditorMenuBar() {
 | 
			
		||||
		this.add(this.buildFileMenu());
 | 
			
		||||
		this.add(this.buildEditMenu());
 | 
			
		||||
		this.add(this.buildHelpMenu());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private JMenu buildFileMenu() {
 | 
			
		||||
		JMenu menu = new JMenu("File");
 | 
			
		||||
		menu.add(NewModelAction.getInstance());
 | 
			
		||||
		menu.add(SaveAction.getInstance());
 | 
			
		||||
		menu.add(LoadAction.getInstance());
 | 
			
		||||
		menu.addSeparator();
 | 
			
		||||
		menu.add(ExportToImageAction.getInstance());
 | 
			
		||||
		menu.addSeparator();
 | 
			
		||||
		menu.add(ExitAction.getInstance());
 | 
			
		||||
| 
						 | 
				
			
			@ -38,4 +41,10 @@ public class EditorMenuBar extends JMenuBar {
 | 
			
		|||
		menu.add(RedoAction.getInstance());
 | 
			
		||||
		return menu;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private JMenu buildHelpMenu() {
 | 
			
		||||
		JMenu menu = new JMenu("Help");
 | 
			
		||||
		menu.add("About");
 | 
			
		||||
		return menu;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ package nl.andrewlalis.erme.view.view_models;
 | 
			
		|||
 | 
			
		||||
import nl.andrewlalis.erme.model.Attribute;
 | 
			
		||||
import nl.andrewlalis.erme.model.AttributeType;
 | 
			
		||||
import nl.andrewlalis.erme.model.ForeignKeyAttribute;
 | 
			
		||||
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.font.TextAttribute;
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +14,7 @@ public class AttributeViewModel implements ViewModel {
 | 
			
		|||
	public static final int PADDING_Y = 5;
 | 
			
		||||
	public static final Color BACKGROUND_COLOR = Color.LIGHT_GRAY;
 | 
			
		||||
	public static final Color FONT_COLOR = Color.BLACK;
 | 
			
		||||
	public static final float FK_FONT_SIZE = 11.0f;
 | 
			
		||||
 | 
			
		||||
	private final Attribute attribute;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,33 +25,45 @@ public class AttributeViewModel implements ViewModel {
 | 
			
		|||
	@Override
 | 
			
		||||
	public void draw(Graphics2D g) {
 | 
			
		||||
		AttributedString as = this.getAttributedString(g);
 | 
			
		||||
		Rectangle r = this.getBounds(g, as);
 | 
			
		||||
		Rectangle r = this.getBoxBounds(g, as);
 | 
			
		||||
		g.setColor(BACKGROUND_COLOR);
 | 
			
		||||
		g.fillRect(r.x, r.y, r.width, r.height);
 | 
			
		||||
		g.setColor(FONT_COLOR);
 | 
			
		||||
		g.drawRect(r.x, r.y, r.width, r.height);
 | 
			
		||||
		g.drawString(as.getIterator(), r.x + PADDING_X, r.y + (r.height - PADDING_Y));
 | 
			
		||||
		if (this.attribute instanceof ForeignKeyAttribute) {
 | 
			
		||||
			ForeignKeyAttribute fkAttribute = (ForeignKeyAttribute) this.attribute;
 | 
			
		||||
			Font originalFont = g.getFont();
 | 
			
		||||
			g.setFont(g.getFont().deriveFont(Font.ITALIC, FK_FONT_SIZE));
 | 
			
		||||
			g.drawString(fkAttribute.getFullReferenceName(), r.x + PADDING_X, r.y - PADDING_Y);
 | 
			
		||||
			g.setFont(originalFont);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Rectangle getBounds(Graphics2D g, AttributedString as) {
 | 
			
		||||
	private Rectangle getBoxBounds(Graphics2D g, AttributedString as) {
 | 
			
		||||
		int x = this.attribute.getRelation().getPosition().x + RelationViewModel.PADDING_X;
 | 
			
		||||
		int y = this.attribute.getRelation().getPosition().y + this.attribute.getRelation().getViewModel().getNameBounds(g).height + PADDING_Y;
 | 
			
		||||
		int y = this.attribute.getRelation().getPosition().y + this.attribute.getRelation().getViewModel().getNameBounds(g).height + RelationViewModel.ATTRIBUTE_SEPARATION;
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		while (!this.attribute.getRelation().getAttributes().get(i).equals(this.attribute)) {
 | 
			
		||||
			x += g.getFontMetrics().stringWidth(this.attribute.getRelation().getAttributes().get(i).getName()) + (2 * PADDING_X);
 | 
			
		||||
			x += this.attribute.getRelation().getAttributes().get(i).getViewModel().getBoxBounds(g).width;
 | 
			
		||||
			i++;
 | 
			
		||||
		}
 | 
			
		||||
		Rectangle2D rect = g.getFontMetrics().getStringBounds(as.getIterator(), 0, this.attribute.getName().length(), g);
 | 
			
		||||
		return new Rectangle(
 | 
			
		||||
				x,
 | 
			
		||||
				y,
 | 
			
		||||
				(int) rect.getWidth() + (2 * PADDING_X),
 | 
			
		||||
				(int) rect.getHeight() + (2 * PADDING_Y)
 | 
			
		||||
		);
 | 
			
		||||
		Rectangle2D nameRect = g.getFontMetrics().getStringBounds(as.getIterator(), 0, this.attribute.getName().length(), g);
 | 
			
		||||
		int width = (int) nameRect.getWidth() + (2 * PADDING_X);
 | 
			
		||||
		int height = (int) nameRect.getHeight() + (2 * PADDING_Y);
 | 
			
		||||
		if (this.attribute instanceof ForeignKeyAttribute) {
 | 
			
		||||
			ForeignKeyAttribute fkAttribute = (ForeignKeyAttribute) this.attribute;
 | 
			
		||||
			Font originalFont = g.getFont();
 | 
			
		||||
			g.setFont(g.getFont().deriveFont(Font.ITALIC, FK_FONT_SIZE));
 | 
			
		||||
			Rectangle referenceNameBounds = g.getFontMetrics().getStringBounds(fkAttribute.getFullReferenceName(), g).getBounds();
 | 
			
		||||
			g.setFont(originalFont);
 | 
			
		||||
			width = Math.max(width, referenceNameBounds.width + (2 * PADDING_X));
 | 
			
		||||
		}
 | 
			
		||||
		return new Rectangle(x, y, width, height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Rectangle getBounds(Graphics2D g) {
 | 
			
		||||
		return this.getBounds(g, this.getAttributedString(g));
 | 
			
		||||
	public Rectangle getBoxBounds(Graphics2D g) {
 | 
			
		||||
		return this.getBoxBounds(g, this.getAttributedString(g));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private AttributedString getAttributedString(Graphics2D g) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ import java.text.AttributedString;
 | 
			
		|||
public class RelationViewModel implements ViewModel {
 | 
			
		||||
	public static final int PADDING_X = 5;
 | 
			
		||||
	public static final int PADDING_Y = 5;
 | 
			
		||||
	public static final int ATTRIBUTE_SEPARATION = 10;
 | 
			
		||||
 | 
			
		||||
	private final Relation relation;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -40,13 +41,13 @@ public class RelationViewModel implements ViewModel {
 | 
			
		|||
		int totalAttributeWidth = 0;
 | 
			
		||||
		int maxAttributeHeight = 0;
 | 
			
		||||
		for (Attribute a : this.relation.getAttributes()) {
 | 
			
		||||
			Rectangle attributeBounds = a.getViewModel().getBounds(g);
 | 
			
		||||
			Rectangle attributeBounds = a.getViewModel().getBoxBounds(g);
 | 
			
		||||
			totalAttributeWidth += attributeBounds.width;
 | 
			
		||||
			maxAttributeHeight = Math.max(maxAttributeHeight, attributeBounds.height);
 | 
			
		||||
		}
 | 
			
		||||
		Rectangle nameBounds = this.getNameBounds(g);
 | 
			
		||||
		rect.width = Math.max(totalAttributeWidth, nameBounds.width) + (2 * PADDING_X);
 | 
			
		||||
		rect.height = nameBounds.height + maxAttributeHeight + (2 * PADDING_Y);
 | 
			
		||||
		rect.height = nameBounds.height + maxAttributeHeight + (2 * PADDING_Y) + ATTRIBUTE_SEPARATION;
 | 
			
		||||
		return rect;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue