diff options
Diffstat (limited to 'rule_api')
30 files changed, 3610 insertions, 0 deletions
diff --git a/rule_api/.classpath b/rule_api/.classpath new file mode 100644 index 0000000..f9c91e7 --- /dev/null +++ b/rule_api/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry combineaccessrules="false" kind="src" path="/common"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/rule_api/.gitignore b/rule_api/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/rule_api/.gitignore @@ -0,0 +1 @@ +bin diff --git a/rule_api/.project b/rule_api/.project new file mode 100644 index 0000000..2e2a12e --- /dev/null +++ b/rule_api/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>rule_api</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/rule_api/.settings/org.eclipse.jdt.core.prefs b/rule_api/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..e755df2 --- /dev/null +++ b/rule_api/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,71 @@ +#Thu Jun 09 12:26:44 PDT 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning diff --git a/rule_api/Android.mk b/rule_api/Android.mk new file mode 100644 index 0000000..6f5d034 --- /dev/null +++ b/rule_api/Android.mk @@ -0,0 +1,28 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# 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 +# +# http://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. +# +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_JAVA_RESOURCE_DIRS := src + +LOCAL_JAVA_LIBRARIES := \ + common + +LOCAL_MODULE := rule_api +LOCAL_MODULE_TAGS := optional + +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/rule_api/NOTICE b/rule_api/NOTICE new file mode 100644 index 0000000..becc120 --- /dev/null +++ b/rule_api/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/rule_api/README.txt b/rule_api/README.txt new file mode 100644 index 0000000..b094e60 --- /dev/null +++ b/rule_api/README.txt @@ -0,0 +1,10 @@ +The Rule API is a library intended for view authors to add designtime +support for their custom views in Android layout editors. + +NOTE: The API is *not* final and will very likely continue to change +incompatibly until we finish it and incorporate feedback. + +The rule API attempts to be IDE agnostic, so it should not have +specific dependencies on any tools. IDE vendors building layout +editors should provide IDE-side implementations of the rule interfaces +such that they can interact with view rules. diff --git a/rule_api/src/com/android/ide/common/api/DrawingStyle.java b/rule_api/src/com/android/ide/common/api/DrawingStyle.java new file mode 100644 index 0000000..199608e --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/DrawingStyle.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Drawing styles are used to distinguish the visual appearance of selection, + * hovers, anchors, etc. Each style may have different colors, line thickness, + * dashing style, transparency, etc. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public enum DrawingStyle { + /** + * The style used to draw the selected views + */ + SELECTION, + + /** + * The style used to draw guidelines - overlay lines which indicate + * significant geometric positions. + */ + GUIDELINE, + + /** + * The style used to guideline shadows + */ + GUIDELINE_SHADOW, + + /** + * The style used to draw guidelines, in particular shared edges and center lines; this + * is a dashed edge. + */ + GUIDELINE_DASHED, + + /** + * The style used to draw distance annotations + */ + DISTANCE, + + /** + * The style used to draw grids + */ + GRID, + + /** + * The style used for hovered views (e.g. when the mouse is directly on top + * of the view) + */ + HOVER, + + /** + * The style used for hovered views (e.g. when the mouse is directly on top + * of the view), when the hover happens to be the same object as the selection + */ + HOVER_SELECTION, + + /** + * The style used to draw anchors (lines to the other views the given view + * is anchored to) + */ + ANCHOR, + + /** + * The style used to draw outlines (the structure of views) + */ + OUTLINE, + + /** + * The style used to draw the recipient/target View of a drop. This is + * typically going to be the bounding-box of the view into which you are + * adding a new child. + */ + DROP_RECIPIENT, + + /** + * The style used to draw a potential drop area <b>within</b> a + * {@link #DROP_RECIPIENT}. For example, if you are dragging into a view + * with a LinearLayout, the {@link #DROP_RECIPIENT} will be the view itself, + * whereas each possible insert position between two children will be a + * {@link #DROP_ZONE}. If the mouse is over a {@link #DROP_ZONE} it should + * be drawn using the style {@link #DROP_ZONE_ACTIVE}. + */ + DROP_ZONE, + + /** + * The style used to draw a currently active drop zone within a drop + * recipient. See the documentation for {@link #DROP_ZONE} for details on + * the distinction between {@link #DROP_RECIPIENT}, {@link #DROP_ZONE} and + * {@link #DROP_ZONE_ACTIVE}. + */ + DROP_ZONE_ACTIVE, + + /** + * The style used to draw a preview of where a dropped view would appear if + * it were to be dropped at a given location. + */ + DROP_PREVIEW, + + /** + * The style used to preview a resize operation. Similar to {@link #DROP_PREVIEW} + * but usually fainter to work better in combination with guidelines which + * are often overlaid during resize. + */ + RESIZE_PREVIEW, + + /** + * The style used to show a proposed resize bound which is being rejected (for example, + * because there is no near edge to attach to in a RelativeLayout). + */ + RESIZE_FAIL, + + /** + * The style used to draw help/hint text. + */ + HELP, + + /** + * The style used to draw illegal/error/invalid markers + */ + INVALID, + + /** + * The style used to highlight dependencies + */ + DEPENDENCY, + + /** + * The style used to draw an invalid cycle + */ + CYCLE, + + /** + * The style used to highlight the currently dragged views during a layout + * move (if they are not hidden) + */ + DRAGGED, + + /** + * The style used to draw empty containers of zero bounds (which are padded + * a bit to make them visible during a drag or selection). + */ + EMPTY, + + /** + * A style used for unspecified purposes; can be used by a client to have + * yet another color that is domain specific; using this color constant + * rather than your own hardcoded value means that you will be guaranteed to + * pick up a color that is themed properly and will look decent with the + * rest of the colors + */ + CUSTOM1, + + /** + * A second styled used for unspecified purposes; see {@link #CUSTOM1} for + * details. + */ + CUSTOM2 +} diff --git a/rule_api/src/com/android/ide/common/api/DropFeedback.java b/rule_api/src/com/android/ide/common/api/DropFeedback.java new file mode 100755 index 0000000..4be9c9e --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/DropFeedback.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Structure returned by onDropEnter/Move and passed to over onDropXyz methods. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public class DropFeedback { + /** + * User data that the rule can use in any way it wants to carry state from one + * operation to another. + * <p/> + * Filled and owned by the view rule. + */ + public Object userData; + + /** + * If true the next screen update will invoke the paint callback. + * <p/> + * Filled by the view rule to request a paint, and reset by the canvas after + * the paint occurred. + */ + public boolean requestPaint; + + /** + * Set to false by the engine when entering a new view target. + * The view rule should set this to true if the current view target is not + * a valid drop zone. + * <p/> + * When set to true, the onDropped() method will not be called if the user releases + * the mouse button. Depending on the platform or implementation, the mouse cursor + * <em>may</em> reflect that the drop operation is invalid. + * <p/> + * Rationale: an operation like onDropEnter() is called each time the mouse enters + * a new view target and is supposed to return null when the drop cannot happen + * <em>at all</em> in that target. However a layout like RelativeLayout decorates + * potential targets with "hot spots" that are suitable drop zones, whereas some + * other parts of the view are not suitable drop zones. In this case the onDropEnter() + * or onDropMove() operation would return a {@link DropFeedback} with + * <code>invalidTarget=true</code>. + */ + public boolean invalidTarget; + + /** + * Painter invoked by the canvas to paint the feedback. + * Filled by the view rule, called by the engine. + * <p/> + */ + public IFeedbackPainter painter; + + /** + * When set to a non-null valid rectangle, this informs the engine that a drag'n'drop + * feedback wants to capture the mouse as long as it stays in the given area. + * <p/> + * When the mouse is captured, drop events will keep going to the rule that started the + * capture and the current INode proxy will not change. + * <p/> + * Filled by the view rule, read by the engine. + */ + public Rect captureArea; + + /** + * Set to true by the drag'n'drop engine when the current drag operation is a copy. + * When false the operation is a move and <em>after</em> a successful drop the source + * elements will be deleted. + * <p/> + * Filled by the engine, read by view rule. + */ + public boolean isCopy; + + /** + * The bounds of the drag, relative to the starting mouse position. For example, if + * you have a rectangular view of size 100x80, and you start dragging at position + * (15,20) from the top left corner of this rectangle, then the drag bounds would be + * (-15,-20, 100x80). + * <p> + * NOTE: The coordinate units will be in layout/view coordinates. In other words, they + * are unaffected by the canvas zoom. + */ + public Rect dragBounds; + + /** + * The baseline of the primary dragged view. -1 means that the view does not have a baseline. + */ + public int dragBaseline = -1; + + /** + * Set to true when the drag'n'drop starts and ends in the same canvas of the + * same Eclipse instance. + * <p/> + * Filled by the engine, read by view rule. + */ + public boolean sameCanvas; + + /** + * Density scale for pixels. To compute the dip (device independent pixel) in the + * view from a layout coordinate, apply this scale. + */ + public double dipScale = 1.0; + + /** + * Initializes the drop feedback with the given user data and paint + * callback. A paint is requested if the paint callback is non-null. + * + * @param userData Data stored for later retrieval by the client + * @param painter A callback invoked to paint the drop feedback + */ + public DropFeedback(Object userData, IFeedbackPainter painter) { + this.userData = userData; + this.painter = painter; + this.requestPaint = painter != null; + this.captureArea = null; + } + + /** + * A message to be displayed to the user, if any. Should not contain line separators. + */ + public String message; + + /** + * An error message to be displayed to the user, if any. Should not contain line + * separators. + */ + public String errorMessage; + + /** + * A message to be displayed in a tooltip to the user, which should be short, but + * can be multiple lines (use embedded newlines) + */ + public String tooltip; + + /** + * Horizontal alignment for the tooltip, or null if no preference + */ + public SegmentType tooltipX; + + /** + * Vertical alignment for the tooltip, or null if no preference + */ + public SegmentType tooltipY; + + /** + * A mask of the currently held keyboard modifier keys - some combination of + * {@link #MODIFIER1}, {@link #MODIFIER2}, {@link #MODIFIER3}, or none. + */ + public int modifierMask; + + /** Bitmask value for modifier key 1 (Control on Windows/Linux, Command on Mac, etc) */ + public static final int MODIFIER1 = 1; + /** Bitmask value for modifier key 2 (Shift) */ + public static final int MODIFIER2 = 2; + /** Bitmask value for modifier key 3 (Alt on Windows/Linux, Option on Mac, etc) */ + public static final int MODIFIER3 = 4; +} diff --git a/rule_api/src/com/android/ide/common/api/IAttributeInfo.java b/rule_api/src/com/android/ide/common/api/IAttributeInfo.java new file mode 100755 index 0000000..2a6ecd8 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IAttributeInfo.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Information about an attribute as gathered from the attrs.xml file where + * the attribute was declared. This must include a format (string, reference, float, etc.), + * possible flag or enum values, whether it's deprecated and its javadoc. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IAttributeInfo { + + /** An attribute format, e.g. string, reference, float, etc. */ + public enum Format { + STRING, + BOOLEAN, + INTEGER, + FLOAT, + REFERENCE, + COLOR, + DIMENSION, + FRACTION, + ENUM, + FLAG; + + /** + * Returns true if and only if this format is in the given array of + * formats + * + * @param formats An array of formats, or null. + * @return True if and only if the given array (if any) contains this + * format. + */ + public boolean in(Format[] formats) { + if (formats == null) { + return false; + } + for (Format f : formats) { + if (f == this) { + return true; + } + } + + return false; + } + } + + /** Returns the XML Name of the attribute */ + public String getName(); + + /** Returns the formats of the attribute. Cannot be null. + * Should have at least one format. */ + public Format[] getFormats(); + + /** Returns the values for enums. null for other types. */ + public String[] getEnumValues(); + + /** Returns the values for flags. null for other types. */ + public String[] getFlagValues(); + + /** Returns a short javadoc, .i.e. the first sentence. */ + public String getJavaDoc(); + + /** Returns the documentation for deprecated attributes. Null if not deprecated. */ + public String getDeprecatedDoc(); + +} diff --git a/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java b/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java new file mode 100755 index 0000000..0853378 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import com.android.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +/** + * A Client Rules Engine is a set of methods that {@link IViewRule}s can use to + * access the client public API of the Rules Engine. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IClientRulesEngine { + + /** + * Returns the FQCN for which the rule was loaded. + * + * @return the fully qualified name of the rule + */ + String getFqcn(); + + /** + * Prints a debug line in the Eclipse console using the ADT formatter. + * + * @param msg A String format message. + * @param params Optional parameters for the message. + */ + void debugPrintf(String msg, Object...params); + + /** + * Loads and returns an {@link IViewRule} for the given FQCN. + * + * @param fqcn A non-null, non-empty FQCN for the rule to load. + * @return The rule that best matches the given FQCN according to the + * inheritance chain. Rules are cached and requesting the same FQCN twice + * is fast and will return the same rule instance. + */ + IViewRule loadRule(String fqcn); + + /** + * Returns the metadata associated with the given fully qualified class name. + * + * @param fqcn a fully qualified class name for an Android view class + * @return the metadata associated with the given fully qualified class name. + */ + IViewMetadata getMetadata(String fqcn); + + /** + * Displays the given message string in an alert dialog with an "OK" button. + * + * @param message the message to be shown + */ + void displayAlert(String message); + + /** + * Displays a simple input alert dialog with an OK and Cancel buttons. + * + * @param message The message to display in the alert dialog. + * @param value The initial value to display in the input field. Can be null. + * @param filter An optional filter to validate the input. Specify null (or + * a validator which always returns true) if you do not want + * input validation. + * @return Null if canceled by the user. Otherwise the possibly-empty input string. + * @null Return value is null if dialog was canceled by the user. + */ + @Nullable + String displayInput(String message, @Nullable String value, @Nullable IValidator filter); + + /** + * Returns the minimum API level that the current Android project is targeting. + * + * @return the minimum API level to be supported, or -1 if it cannot be determined + */ + int getMinApiLevel(); + + /** + * Returns a resource name validator for the current project + * + * @return an {@link IValidator} for validating new resource name in the current + * project + */ + IValidator getResourceValidator(); + + /** + * Displays an input dialog where the user can enter an Android reference value + * + * @param currentValue the current reference to select + * @return the reference selected by the user, or null + */ + String displayReferenceInput(String currentValue); + + /** + * Displays an input dialog where the user can enter an Android resource name of the + * given resource type ("id", "string", "drawable", and so on.) + * + * @param currentValue the current reference to select + * @param resourceTypeName resource type, such as "id", "string", and so on (never + * null) + * @return the margins selected by the user in the same order as the input arguments, + * or null + */ + String displayResourceInput(String resourceTypeName, String currentValue); + + /** + * Displays an input dialog tailored for editing margin properties. + * + * @param all The current, initial value display for "all" margins (applied to all + * sides) + * @param left The current, initial value to display for the "left" margin + * @param right The current, initial value to display for the "right" margin + * @param top The current, initial value to display for the "top" margin + * @param bottom The current, initial value to display for the "bottom" margin + * @return an array of length 5 containing the user entered values for the all, left, + * right, top and bottom margins respectively + */ + String[] displayMarginInput(String all, String left, String right, String top, String bottom); + + /** + * Displays an input dialog tailored for inputing the source of an {@code <include>} + * layout tag. This is similar to {@link #displayResourceInput} for resource type + * "layout", but should also attempt to filter out layout resources that cannot be + * included from the current context (because it would result in a cyclic dependency). + * + * @return the layout resource to include + */ + String displayIncludeSourceInput(); + + /** + * Displays an input dialog tailored for inputing the source of a {@code <fragment>} + * layout tag. + * + * @return the fully qualified class name of the fragment activity + */ + String displayFragmentSourceInput(); + + /** + * Select the given nodes + * + * @param nodes the nodes to be selected, never null + */ + void select(Collection<INode> nodes); + + /** + * Triggers a redraw + */ + void redraw(); + + /** + * Triggers a layout refresh and redraw + */ + void layout(); + + /** + * Converts a pixel to a dp (device independent pixel) for the current screen density + * + * @param px the pixel dimension + * @return the corresponding dp dimension + */ + public int pxToDp(int px); + + /** + * Converts a device independent pixel to a screen pixel for the current screen density + * + * @param dp the device independent pixel dimension + * @return the corresponding pixel dimension + */ + public int dpToPx(int dp); + + /** + * Converts an IDE screen pixel distance to the corresponding layout distance. This + * can be used to draw annotations on the graphics object that should be unaffected by + * the zoom, or handle mouse events within a certain pixel distance regardless of the + * screen zoom. + * + * @param pixels the size in IDE screen pixels + * @return the corresponding pixel distance in the layout coordinate system + */ + public int screenToLayout(int pixels); + + /** + * Measure the preferred or actual ("wrap_content") size of the given nodes. + * + * @param parent the parent whose children should be measured + * @param filter a filter to change attributes in the process of measuring, for + * example forcing the layout_width to wrap_content or the layout_weight to + * unset + * @return the corresponding bounds of the nodes + */ + Map<INode, Rect> measureChildren(INode parent, AttributeFilter filter); + + /** + * The {@link AttributeFilter} allows a client of + * {@link IClientRulesEngine#measureChildren} to modify the actual XML values of the + * nodes being rendered, for example to force width and height values to wrap_content + * when measuring preferred size. + */ + public interface AttributeFilter { + /** + * Returns the attribute value for the given node and attribute name. This filter + * allows a client to adjust the attribute values that a node presents to the + * layout library. + * <p> + * Return "" to unset an attribute. Return null to return the unfiltered value. + * + * @param node the node for which the attribute value should be returned + * @param namespace the attribute namespace + * @param localName the attribute local name + * @return an override value, or null to return the unfiltered value + */ + String getAttribute(INode node, String namespace, String localName); + } + + /** + * Given a UI root node and a potential XML node name, returns the first available id + * that matches the pattern "prefix%d". + * <p/> + * TabWidget is a special case and the method will always return "@android:id/tabs". + * + * @param fqcn The fully qualified class name of the view to generate a unique id for + * @return A suitable generated id in the attribute form needed by the XML id tag + * (e.g. "@+id/something") + */ + public String getUniqueId(String fqcn); + +} + diff --git a/rule_api/src/com/android/ide/common/api/IColor.java b/rule_api/src/com/android/ide/common/api/IColor.java new file mode 100755 index 0000000..f75d30a --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IColor.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * A color, to be used with {@link IGraphics} draw operations. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IColor { + // pass +} diff --git a/rule_api/src/com/android/ide/common/api/IDragElement.java b/rule_api/src/com/android/ide/common/api/IDragElement.java new file mode 100755 index 0000000..a5e339a --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IDragElement.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Represents an XML element with a name, attributes and inner elements. + * <p/> + * The semantic of the element name is to be a fully qualified class name of a View to inflate. + * The element name is not expected to have a namespace. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IDragElement { + + /** + * Returns the element name, which must match a fully qualified class name of + * a View to inflate. + */ + public abstract String getFqcn(); + + /** + * Returns the bounds of the element's node, if it originated from an existing + * canvas. The rectangle is invalid and non-null when the element originated + * from the object palette. + * + * The bounds are absolute for the canvas. + */ + public abstract Rect getBounds(); + + /** + * Returns the fully qualified class name of the parent, if the element originated + * from an existing canvas. Returns null if the element has no parent, such as a top + * level element or an element originating from the object palette. + */ + public abstract String getParentFqcn(); + + /** + * Returns the bounds of the element's parent, absolute for the canvas, or invalid if there + * is no suitable parent. This is generally invalid when {@link #getParentFqcn()} is null. + * + * The returned rectangle can be invalid. It is never null. + */ + public abstract Rect getParentBounds(); + + /** + * Returns a list of attributes. The list can be empty but is never null. + */ + public abstract IDragAttribute[] getAttributes(); + + /** + * Returns the requested attribute or null if not found. + */ + public abstract IDragAttribute getAttribute(String uri, String localName); + + /** + * Returns a list of inner elements. The list can be empty but is never null. + */ + public abstract IDragElement[] getInnerElements(); + + /** + * An XML attribute in the {@link IDragElement}. + * <p/> + * The attribute is always represented by a namespace URI, a name and a value. + * The name cannot be empty. + * The namespace URI can be empty for an attribute without a namespace but is never null. + * The value can be empty but cannot be null. + */ + public interface IDragAttribute { + + /** + * Returns the namespace URI of the attribute. + * Can be empty for an attribute without a namespace but is never null. + */ + public abstract String getUri(); + + /** Returns the XML local name of the attribute. Cannot be null nor empty. */ + public abstract String getName(); + + /** Returns the value of the attribute. Cannot be null. Can be empty. */ + public abstract String getValue(); + } +} + diff --git a/rule_api/src/com/android/ide/common/api/IFeedbackPainter.java b/rule_api/src/com/android/ide/common/api/IFeedbackPainter.java new file mode 100644 index 0000000..7478f6b --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IFeedbackPainter.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * A feedback painter paints drop feedback during a drag & drop operation. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IFeedbackPainter { + /** + * Paints feedback for the given target node into the given graphics context. + * + * @param gc The graphics context to paint into + * @param targetNode The node being dragged + * @param feedback The feedback data + */ + void paint(IGraphics gc, INode targetNode, DropFeedback feedback); +} diff --git a/rule_api/src/com/android/ide/common/api/IGraphics.java b/rule_api/src/com/android/ide/common/api/IGraphics.java new file mode 100755 index 0000000..0ee2ef2 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IGraphics.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import java.util.List; + +/** + * Represents a graphical context that rules can use to draw on the canvas. + * <p/> + * The wrapper GC is only valid during the context of a paint operation. + * This means {@link IViewRule}s should not cache this object and call it at + * just about any time, it is only valid during a call that actually receives + * the GC wrapper. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IGraphics { + + /** + * Draws a line between 2 points, using the current foreground color and + * alpha. + */ + void drawLine(int x1, int y1, int x2, int y2); + + /** + * Draws a line between 2 points, using the current foreground color and + * alpha. + */ + void drawLine(Point p1, Point p2); + + /** + * Draws an arrow from (x1, y1) to (x2, y2). + * + * @param x1 The x coordinate of the beginning of the arrow + * @param y1 The y coordinate of the beginning of the arrow + * @param x2 The x coordinate of the end (point) of the arrow + * @param y2 The y coordinate of the end (point) of the arrow + * @param size The size of the arrowhead + */ + void drawArrow(int x1, int y1, int x2, int y2, int size); + + /** + * Draws a dot at the given position. + * + * @param x The x coordinate of the dot + * @param y The y coordinate of the dot + */ + void drawPoint(int x, int y); + + /** + * Draws a rectangle outline between 2 points, using the current foreground + * color and alpha. + */ + void drawRect(int x1, int y1, int x2, int y2); + + /** + * Draws a rectangle outline between 2 points, using the current foreground + * color and alpha. + */ + void drawRect(Point p1, Point p2); + + /** + * Draws a rectangle outline between 2 points, using the current foreground + * color and alpha. + */ + void drawRect(Rect r); + + /** + * Fills a rectangle outline between 2 points, using the current background + * color and alpha. + */ + void fillRect(int x1, int y1, int x2, int y2); + + /** + * Fills a rectangle outline between 2 points, using the current background + * color and alpha. + */ + void fillRect(Point p1, Point p2); + + /** + * Fills a rectangle outline between 2 points, using the current background + * color and alpha. + */ + void fillRect(Rect r); + + /** + * Draws the given string, using the current foreground color. No tab + * expansion or carriage return processing will be performed. + * + * @param string the string to be drawn. + * @param x the x coordinate of the top left corner of the text. + * @param y the y coordinate of the top left corner of the text. + */ + void drawString(String string, int x, int y); + + /** + * Draws the given string, using the current foreground color. No tab + * expansion or carriage return processing will be performed. + * + * @param string the string to be drawn. + * @param topLeft the top left corner of the text. + */ + void drawString(String string, Point topLeft); + + /** + * Draw the given strings, using the current stroke color and alpha for the + * text, and the current fill color and alpha for a rectangle behind the + * bounding box fitting all the lines of text. Each subsequent string is + * drawn on consecutive lines below the previous string. + * + * @param x The left edge to start each string at + * @param y The top position of the first string; subsequent strings are + * painted on lines below + * @param strings An array of labels to be displayed (should not be null). + * The actual String used is the {@link Object#toString()} value + * of each list item. + */ + void drawBoxedStrings(int x, int y, List<?> strings); + + /** + * Set up the graphics context to use the given style for subsequent drawing + * operations. + * + * @param style The drawing style to be used. May not be null. + */ + void useStyle(DrawingStyle style); + + /** + * Registers a color using 0x00rrggbb where each component is 0..0xFF. + * <p/> + * Transparency is handled separately using {@link #setAlpha(int)}. + * <p/> + * If the same color is registered twice, the same object will be returned. + * <p/> + * NOTE: It's preferable to use {@link #useStyle(DrawingStyle)} if possible + * to ensure that your colors work properly across multiple current and + * future themes. + */ + IColor registerColor(int rgb); + + /** + * Returns the height, in pixels, of the default font. + */ + int getFontHeight(); + + /** + * Returns the current foreground color. + * The foreground color is used for drawing operations including when text is drawn. + */ + IColor getForeground(); + + /** + * Sets the foreground color. The foreground color is used for drawing + * operations including when text is drawn. + */ + void setForeground(IColor color); + + /** + * Returns the current background color. The background color is used for + * fill operations. + */ + IColor getBackground(); + + /** + * Sets the background color. The background color is used for fill + * operations. + */ + void setBackground(IColor color); + + /** + * Returns the current alpha value (varies between 0 for transparent and 255 + * for opaque). + * + * @return The current alpha value in use + */ + int getAlpha(); + + /** + * Sets the receiver's alpha value which must be + * between 0 (transparent) and 255 (opaque). + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * <p> + * TODO: Consider removing this method; it will usually be ignored because + * most graphics operations apply the alpha from the current drawing style + */ + void setAlpha(int alpha); + + /** + * A line style for {@link IGraphics#setLineStyle(LineStyle)}. + */ + enum LineStyle { + /** Style for solid lines. */ + LINE_SOLID, + /** Style for dashed lines. */ + LINE_DASH, + /** Style for dotted lines. */ + LINE_DOT, + /** Style for alternating dash-dot lines. */ + LINE_DASHDOT, + /** Style for dash-dot-dot lines. */ + LINE_DASHDOTDOT + } + + /** + * Sets the current line style. + */ + void setLineStyle(LineStyle style); + + /** + * Sets the width that will be used when drawing lines. + * The operation is ignored if <var>width</var> is less than 1. + */ + void setLineWidth(int width); +} diff --git a/rule_api/src/com/android/ide/common/api/IMenuCallback.java b/rule_api/src/com/android/ide/common/api/IMenuCallback.java new file mode 100644 index 0000000..80f77b8 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IMenuCallback.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import java.util.List; + +/** + * Callback interface for a {@link RuleAction}. The callback performs the actual + * work of the action, and this level of indirection allows multiple actions (which + * typically do not have their own class, only their own instances) to share a single + * implementation callback class. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IMenuCallback { + /** + * Performs the actual work promised by the {@link RuleAction}. + * @param action The action being applied. + * @param selectedNodes The nodes to apply the action to + * @param valueId For a Choices action, the string id of the selected choice + * @param newValue For a toggle or for a flag, true if the item is being + * checked, false if being unchecked. For enums this is not + * useful; however for flags it allows one to add or remove items + * to the flag's choices. + */ + void action(RuleAction action, List<? extends INode> selectedNodes, String valueId, + Boolean newValue); +} diff --git a/rule_api/src/com/android/ide/common/api/INode.java b/rule_api/src/com/android/ide/common/api/INode.java new file mode 100755 index 0000000..e3f34a9 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/INode.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import com.android.ide.common.api.IDragElement.IDragAttribute; + + +/** + * Represents a view in the XML layout being edited. + * Each view or layout maps to exactly one XML node, thus the name. + * <p/> + * The primordial characteristic of a node is the fully qualified View class name that + * it represents (a.k.a FQCN), for example "android.view.View" or "android.widget.Button". + * <p/> + * There are 2 kind of nodes: + * - Nodes matching a view actually rendered in the layout canvas have a valid "bounds" + * rectangle that describe their position in pixels in the canvas. <br/> + * - Nodes created by IViewRule scripts but not yet rendered have an invalid bounds rectangle + * since they only exist in the uncommitted XML model and not yet in the rendered View model. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface INode { + + /** + * Returns the FQCN of the view class represented by this node. + */ + String getFqcn(); + + /** + * Returns the bounds of this node. + * <p/> + * The bounds are valid when this node maps a view that is already rendered. + * Typically, if the node is the target of a drag'n'drop operation then you can be + * guaranteed that its bounds are known and thus are valid. + * <p/> + * However the bounds are invalid (e.g. not known yet) for new XML elements + * that have just been created, e.g. by the {@link #appendChild(String)} method. + * + * @return A non-null rectangle, in canvas coordinates. + */ + Rect getBounds(); + + /** + * Returns the margins for this node. + * + * @return the margins for this node, never null + */ + Margins getMargins(); + + /** + * Returns the baseline of this node, or -1 if it has no baseline. + * The baseline is the distance from the top down to the baseline. + * + * @return the baseline, or -1 if not applicable + */ + int getBaseline(); + + // ---- Hierarchy handling ---- + + /** + * Returns the root element of the view hierarchy. + * <p/> + * When a node is not attached to a hierarchy, it is its own root node. + * This may return null if the {@link INode} was not created using a correct UiNode, + * which is unlikely. + */ + INode getRoot(); + + /** + * Returns the parent node of this node, corresponding to the parent view in the layout. + * The returned parent can be null when the node is the root element, or when the node is + * not yet or no longer attached to the hierarchy. + */ + INode getParent(); + + /** + * Returns the list of valid children nodes. The list can be empty but not null. + */ + INode[] getChildren(); + + + // ---- XML Editing --- + + /** + * Absolutely <em>all</em> calls that are going to edit the XML must be wrapped + * by an editXml() call. This call creates both an undo context wrapper and an + * edit-XML wrapper. + * + * @param undoName The UI name that will be given to the undo action. + * @param callback The code to execute. + */ + void editXml(String undoName, final INodeHandler callback); + + // TODO define an exception that methods below will throw if editXml() is not wrapping + // these calls. + + /** + * Creates a new XML element as a child of this node's XML element. + * <p/> + * For this to work, the editor must have a descriptor for the given FQCN. + * <p/> + * This call must be done in the context of editXml(). + * + * @param viewFqcn The FQCN of the element to create. The actual XML local name will + * depend on whether this is an Android view or a custom project view. + * @return The node for the newly created element. Can be null if we failed to create it. + */ + INode appendChild(String viewFqcn); + + /** + * Creates a new XML element as a child of this node's XML element and inserts + * it at the specified position in the children list. + * <p/> + * For this to work, the editor must have a descriptor for the given FQCN. + * <p/> + * This call must be done in the context of editXml(). + * + * @param viewFqcn The FQCN of the element to create. The actual XML local name will + * depend on whether this is an Android view or a custom project view. + * @param index Index of the child to insert before. If the index is out of bounds + * (less than zero or larger that current last child), appends at the end. + * @return The node for the newly created element. Can be null if we failed to create it. + */ + INode insertChildAt(String viewFqcn, int index); + + /** + * Removes the given XML element child from this node's list of children. + * <p/> + * This call must be done in the context of editXml(). + * + * @param node The child to be deleted. + */ + void removeChild(INode node); + + /** + * Sets an attribute for the underlying XML element. + * Attributes are not written immediately -- instead the XML editor batches edits and + * then commits them all together at once later. + * <p/> + * Custom attributes will be created on the fly. + * <p/> + * Passing an empty value actually <em>removes</em> an attribute from the XML. + * <p/> + * This call must be done in the context of editXml(). + * + * @param uri The XML namespace URI of the attribute. + * @param localName The XML <em>local</em> name of the attribute to set. + * @param value It's value. Cannot be null. An empty value <em>removes</em> the attribute. + * @return Whether the attribute was actually set or not. + */ + boolean setAttribute(String uri, String localName, String value); + + /** + * Returns a given XML attribute. + * <p/> + * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. + * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value + * returned here is not affected by {@link #setAttribute(String, String, String)} until + * the editXml closure is completed and the actual XML is updated. + * + * @param uri The XML name-space URI of the attribute. + * @param attrName The <em>local</em> name of the attribute. + * @return the attribute as a {@link String}, if it exists, or <code>null</code>. + */ + String getStringAttr(String uri, String attrName); + + /** + * Returns the {@link IAttributeInfo} for a given attribute. + * <p/> + * The information is useful to determine the format of an attribute (e.g. reference, string, + * float, enum, flag, etc.) and in the case of enums and flags also gives the possible values. + * <p/> + * Note: in Android resources, an enum can only take one of the possible values (e.g. + * "visibility" can be either "visible" or "none"), whereas a flag can accept one or more + * value (e.g. "align" can be "center_vertical|center_horizontal".) + * <p/> + * Note that this method does not handle custom non-android attributes. It may either + * return null for these or it may return a synthetic "string" format attribute depending + * on how the attribute was loaded. + * + * @param uri The XML name-space URI of the attribute. + * @param attrName The <em>local</em> name of the attribute. + * @return the {@link IAttributeInfo} if the attribute is known, or <code>null</code>. + */ + public IAttributeInfo getAttributeInfo(String uri, String attrName); + + /** + * Returns the list of all attributes declared by this node's descriptor. + * <p/> + * This returns a fixed list of all attributes known to the view or layout descriptor. + * This list does not depend on whether the attributes are actually used in the + * XML for this node. + * <p/> + * Note that for views, the list of attributes also includes the layout attributes + * inherited from the parent view. This means callers must not cache this list based + * solely on the type of the node, as its attribute list changes depending on the place + * of the view in the view hierarchy. + * <p/> + * If you want attributes actually written in the XML and their values, please use + * {@link #getStringAttr(String, String)} or {@link #getLiveAttributes()} instead. + * + * @return A non-null possible-empty list of {@link IAttributeInfo}. + */ + public IAttributeInfo[] getDeclaredAttributes(); + + /** + * Returns the list of all attributes defined in the XML for this node. + * <p/> + * This looks up an attribute in the <em>current</em> XML source, not the in-memory model. + * That means that if called in the context of {@link #editXml(String, INodeHandler)}, the value + * returned here is not affected by {@link #setAttribute(String, String, String)} until + * the editXml closure is completed and the actual XML is updated. + * <p/> + * If you want a list of all possible attributes, whether used in the XML or not by + * this node, please see {@link #getDeclaredAttributes()} instead. + * + * @return A non-null possible-empty list of {@link IAttribute}. + */ + public IAttribute[] getLiveAttributes(); + + // ----------- + + /** + * An XML attribute in an {@link INode} with a namespace URI, a name and its current value. + * <p/> + * The name cannot be empty. + * The namespace URI can be empty for an attribute without a namespace but is never null. + * The value can be empty but cannot be null. + */ + public static interface IAttribute extends IDragAttribute { } +} diff --git a/rule_api/src/com/android/ide/common/api/INodeHandler.java b/rule_api/src/com/android/ide/common/api/INodeHandler.java new file mode 100644 index 0000000..e261395 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/INodeHandler.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * A node handler is a callback which operates on a Node, such as for example + * the implementation of an XML editing operation via + * {@link INode#editXml(String, INodeHandler)}. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface INodeHandler { + /** + * Operates on the given node. + * + * @param node The node to be operated on + */ + void handle(INode node); +} diff --git a/rule_api/src/com/android/ide/common/api/IValidator.java b/rule_api/src/com/android/ide/common/api/IValidator.java new file mode 100644 index 0000000..6ef44cd --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IValidator.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * An IValidator can validate strings and return custom messages if validation + * fails. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IValidator { + /** + * Validates the given input string, and return null if the text is valid, + * and otherwise return a description for why the text is invalid. Returning + * an empty String ("") is acceptable (but should only be done when it is + * obvious to the user why the String is not valid.) + * + * @param text The input string to be validated + * @return Null if the text is valid, and otherwise a description (possibly + * empty) for why the text is not valid. + */ + String validate(String text); +} diff --git a/rule_api/src/com/android/ide/common/api/IViewMetadata.java b/rule_api/src/com/android/ide/common/api/IViewMetadata.java new file mode 100644 index 0000000..0687f30 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IViewMetadata.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Metadata about a particular view. The metadata for a View can be found by asking the + * {@link IClientRulesEngine} for the metadata for a given class via + * {@link IClientRulesEngine#getMetadata}. + */ +public interface IViewMetadata { + /** + * Returns the display name views of this type (a name suitable to display to the + * user, normally capitalized and usually but not necessarily tied to the + * implementation class). To be clear, a specific view may have an id attribute and a + * text attribute, <b>neither</b> of these is the display name. Instead, the class + * android.widget.ZoomControls may have the display name "Zoom Controls", and an + * individual view created into a layout can for example have the id "ZoomControl01". + * + * @return the user visible name of views of this type (never null) + */ + public String getDisplayName(); + + /** + * Gets the insets for this view + * + * @return the insets for this view + */ + public Margins getInsets(); + + /** + * Returns the {@link FillPreference} of this view + * + * @return the {@link FillPreference} of this view + */ + public FillPreference getFillPreference(); + + /** + * Types of fill behavior that views can prefer. + * <p> + * TODO: Consider better names. FillPolicy? Stretchiness? + */ + public enum FillPreference { + /** This view does not want to fill */ + NONE, + /** This view wants to always fill both horizontal and vertical */ + BOTH, + /** This view wants to fill horizontally but not vertically */ + WIDTH, + /** This view wants to fill vertically but not horizontally */ + HEIGHT, + /** + * This view wants to fill in the opposite dimension of the context, e.g. in a + * vertical context it wants to fill horizontally, and vice versa + */ + OPPOSITE, + /** This view wants to fill horizontally, but only in a vertical context */ + WIDTH_IN_VERTICAL, + /** This view wants to fill vertically, but only in a horizontal context */ + HEIGHT_IN_HORIZONTAL; + + /** + * Returns true if this view wants to fill horizontally, if the context is + * vertical or horizontal as indicated by the parameter. + * + * @param verticalContext If true, the context is vertical, otherwise it is + * horizontal. + * @return true if this view wants to fill horizontally + */ + public boolean fillHorizontally(boolean verticalContext) { + return (this == BOTH || this == WIDTH || + (verticalContext && (this == OPPOSITE || this == WIDTH_IN_VERTICAL))); + } + + /** + * Returns true if this view wants to fill vertically, if the context is + * vertical or horizontal as indicated by the parameter. + * + * @param verticalContext If true, the context is vertical, otherwise it is + * horizontal. + * @return true if this view wants to fill vertically + */ + public boolean fillVertically(boolean verticalContext) { + return (this == BOTH || this == HEIGHT || + (!verticalContext && (this == OPPOSITE || this == HEIGHT_IN_HORIZONTAL))); + } + } + +} diff --git a/rule_api/src/com/android/ide/common/api/IViewRule.java b/rule_api/src/com/android/ide/common/api/IViewRule.java new file mode 100755 index 0000000..d29ef71 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/IViewRule.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import java.util.List; + + +/** + * An {@link IViewRule} describes the rules that apply to a given Layout or View object + * in the Graphical Layout Editor. + * <p/> + * Rules are implemented by builtin layout helpers, or 3rd party layout rule implementations + * provided with or for a given 3rd party widget. + * <p/> + * A 3rd party layout rule should use the same fully qualified class name as the layout it + * represents, plus "Rule" as a suffix. For example, the layout rule for the + * LinearLayout class is LinearLayoutRule, in the same package. + * <p/> + * Rule instances are stateless. They are created once per View class to handle and are shared + * across platforms or editor instances. As such, rules methods should never cache editor-specific + * arguments that they might receive. + * <p/> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public interface IViewRule { + + /** + * This method is called by the rule engine when the script is first loaded. + * It gives the rule a chance to initialize itself. + * + * @param fqcn The fully qualified class name of the Layout or View that will be managed by + * this rule. This can be cached as it will never change for the lifetime of this rule + * instance. This may or may not match the script's filename as it may be the fqcn of a + * class derived from the one this rule can handle. + * @param engine The engine that is managing the rules. A rule can store a reference to + * the engine during initialization and then use it later to invoke some of the + * {@link IClientRulesEngine} methods for example to request user input. + * @return True if this rule can handle the given FQCN. False if the rule can't handle the + * given FQCN, in which case the rule engine will find another rule matching a parent class. + */ + boolean onInitialize(String fqcn, IClientRulesEngine engine); + + /** + * This method is called by the rules engine just before the script is unloaded. + */ + void onDispose(); + + /** + * Returns the class name to display when an element is selected in the GLE. + * <p/> + * If null is returned, the GLE will automatically shorten the class name using its + * own heuristic, which is to keep the first 2 package components and the class name. + * The class name is the <code>fqcn</code> argument that was given + * to {@link #onInitialize(String,IClientRulesEngine)}. + * + * @return Null for the default behavior or a shortened string. + */ + String getDisplayName(); + + /** + * Invoked by the Rules Engine to produce a set of actions to customize + * the context menu displayed for this view. The result is not cached and the + * method is invoked every time the context menu is about to be shown. + * <p> + * The order of the menu items is determined by the sort priority set on + * the actions. + * <p/> + * Most rules should consider calling super.{@link #addContextMenuActions(List, INode)} + * as well. + * <p/> + * Menu actions are either toggles or fixed lists with one currently-selected + * item. It is expected that the rule will need to recreate the actions with + * different selections when a menu is going to shown, which is why the result + * is not cached. However rules are encouraged to cache some or all of the result + * to speed up following calls if it makes sense. + * + * @param actions a list of actions to add new context menu actions into. The order + * of the actions in this list is not important; it will be sorted by + * {@link RuleAction#getSortPriority()} later. + * @param node the node to add actions for. + */ + void addContextMenuActions(List<RuleAction> actions, INode node); + + /** + * Invoked by the Rules Engine to ask the parent layout for the set of layout actions + * to display in the layout bar. The layout rule should add these into the provided + * list. The order the items are added in does not matter; the + * {@link RuleAction#getSortPriority()} values will be used to sort the actions prior + * to display, which makes it easier for parent rules and deriving rules to interleave + * their respective actions. + * + * @param actions the list of actions to add newly registered actions into + * @param parentNode the parent of the selection, or the selection itself if the root + * @param targets the targeted/selected nodes, if any + */ + void addLayoutActions(List<RuleAction> actions, + INode parentNode, List<? extends INode> targets); + + // ==== Selection ==== + + /** + * Returns a list of strings that will be displayed when a single child is being + * selected in a layout corresponding to this rule. This gives the container a chance + * to describe the child's layout attributes or other relevant information. + * <p/> + * Note that this is called only for single selections. + * <p/> + * + * @param parentNode The parent of the node selected. Never null. + * @param childNode The child node that was selected. Never null. + * @return a list of strings to be displayed, or null or empty to display nothing + */ + List<String> getSelectionHint(INode parentNode, INode childNode); + + /** + * Paints any layout-specific selection feedback for the given parent layout. + * + * @param graphics the graphics context to paint into + * @param parentNode the parent layout node + * @param childNodes the child nodes selected in the parent layout + */ + void paintSelectionFeedback(IGraphics graphics, INode parentNode, + List<? extends INode> childNodes); + + // ==== Drag'n'drop support ==== + + /** + * Called when the d'n'd starts dragging over the target node. + * If interested, returns a DropFeedback passed to onDrop/Move/Leave/Paint. + * If not interested in drop, return null. + * Followed by a paint. + */ + DropFeedback onDropEnter(INode targetNode, + IDragElement[] elements); + + /** + * Called after onDropEnter. + * Returns a DropFeedback passed to onDrop/Move/Leave/Paint (typically same + * as input one). + * Returning null will invalidate the drop workflow. + */ + DropFeedback onDropMove(INode targetNode, + IDragElement[] elements, + DropFeedback feedback, + Point where); + + /** + * Called when drop leaves the target without actually dropping. + * <p/> + * When switching between views, onDropLeave is called on the old node *after* onDropEnter + * is called after a new node that returned a non-null feedback. The feedback received here + * is the one given by the previous onDropEnter on the same target. + * <p/> + * E.g. call order is: + * <pre> + * - onDropEnter(node1) => feedback1 + * <i>...user moves to new view...</i> + * - onDropEnter(node2) => feedback2 + * - onDropLeave(node1, feedback1) + * <i>...user leaves canvas...</i> + * - onDropLeave(node2, feedback2) + * </pre> + */ + void onDropLeave(INode targetNode, + IDragElement[] elements, + DropFeedback feedback); + + /** + * Called when drop is released over the target to perform the actual drop. + * <p> + * TODO: Document that this method will be called under an edit lock so you can + * directly manipulate the nodes without wrapping it in an + * {@link INode#editXml(String, INodeHandler)} call + */ + void onDropped(INode targetNode, + IDragElement[] elements, + DropFeedback feedback, + Point where); + + /** + * Called when pasting elements in an existing document on the selected target. + * + * @param targetNode The first node selected. + * @param pastedElements The elements being pasted. + */ + void onPaste(INode targetNode, IDragElement[] pastedElements); + + // ==== XML Creation ==== + + /** + * Called when a view for this rule is being created. This allows for the rule to + * customize the newly created object. Note that this method is called not just when a + * view is created from a palette drag, but when views are constructed via a drag-move + * (where views are created in the destination and then deleted from the source), and + * even when views are constructed programmatically from other view rules. The + * {@link InsertType} parameter can be used to distinguish the context for the + * insertion. For example, the <code>DialerFilterRule</code> will insert EditText children + * when a DialerFilter is first created, but not during a copy/paste or a move. + * + * @param node the newly created node (which will always be a View that applies to + * this {@link IViewRule}) + * @param parent the parent of the node (which may not yet contain the newly created + * node in its child list) + * @param insertType whether this node was created as part of a newly created view, or + * as a copy, or as a move, etc. + */ + void onCreate(INode node, INode parent, InsertType insertType); + + /** + * Called when a child for this view has been created and is being inserted into the + * view parent for which this {@link IViewRule} applies. Allows the parent to perform + * customizations of the object. As with {@link #onCreate}, the {@link InsertType} + * parameter can be used to handle new creation versus moves versus copy/paste + * operations differently. + * + * @param child the newly created node + * @param parent the parent of the newly created node (which may not yet contain the + * newly created node in its child list) + * @param insertType whether this node was created as part of a newly created view, or + * as a copy, or as a move, etc. + */ + void onChildInserted(INode child, INode parent, InsertType insertType); + + /** + * Called when one or more children are about to be deleted by the user. Note that + * children deleted programmatically from view rules (via + * {@link INode#removeChild(INode)}) will not notify about deletion. + * <p> + * Note that this method will be called under an edit lock, so rules can directly + * add/remove nodes and attributes as part of the deletion handling (and their + * actions will be part of the same undo-unit.) + * + * @param deleted a nonempty list of children about to be deleted + * @param parent the parent of the deleted children (which still contains the children + * since this method is called before the deletion is performed) + */ + void onRemovingChildren(List<INode> deleted, INode parent); + + /** + * Called by the IDE on the parent layout when a child widget is being resized. This + * is called once at the beginning of the resizing operation. A horizontal edge, + * or a vertical edge, or both, can be resized simultaneously. + * + * @param child the widget being resized + * @param parent the layout containing the child + * @param horizEdge The horizontal edge being resized, or null + * @param verticalEdge the vertical edge being resized, or null + * @return a {@link DropFeedback} object which performs an update painter callback + * etc. + */ + DropFeedback onResizeBegin(INode child, INode parent, + SegmentType horizEdge, SegmentType verticalEdge); + + /** + * Called by the IDE on the parent layout when a child widget is being resized. This + * is called repeatedly during the resize as the mouse is dragged to update the drag + * bounds, recompute guidelines, etc. The resize has not yet been "committed" so the + * XML should not be edited yet. + * + * @param feedback the {@link DropFeedback} object created in {@link #onResizeBegin} + * @param child the widget being resized + * @param parent the layout containing the child + * @param newBounds the new bounds the user has chosen to resize the widget to, + * in absolute coordinates + * @param modifierMask The modifier keys currently pressed by the user, as a bitmask + * of the constants {@link DropFeedback#MODIFIER1}, {@link DropFeedback#MODIFIER2} + * and {@link DropFeedback#MODIFIER3}. + */ + void onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, + int modifierMask); + + /** + * Called by the IDE on the parent layout when a child widget is being resized. This + * is called once at the end of the resize operation, if it was not canceled. + * This method can call {@link INode#editXml} to update the node to reflect the + * new bounds. + * + * @param feedback the {@link DropFeedback} object created in {@link #onResizeBegin} + * @param child the widget being resized + * @param parent the layout containing the child + * @param newBounds the new bounds the user has chosen to resize the widget to, + * in absolute coordinates + */ + void onResizeEnd(DropFeedback feedback, INode child, INode parent, Rect newBounds); +} diff --git a/rule_api/src/com/android/ide/common/api/InsertType.java b/rule_api/src/com/android/ide/common/api/InsertType.java new file mode 100644 index 0000000..806b2bb --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/InsertType.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * An enumerated type of different insertion events, such as an insertion from a + * copy/paste operation or as the first half of a move operation. + */ +public enum InsertType { + /** The view is newly created (by for example a palette drag) */ + CREATE, + + /** + * Same as {@link #CREATE} but when the views are constructed for previewing, for + * example as part of a palette drag. + */ + CREATE_PREVIEW, + + /** The view is being inserted here because it was moved from somewhere else within + * the same layout */ + MOVE_WITHIN, + + /** The view is being inserted here because it was moved from some other layout */ + MOVE_INTO, + + /** + * The view is being inserted here as a result of a copy/paste from elsewhere + * (including drags, but not from the palette) + */ + PASTE; + + /** + * Returns true if this insert type is for a newly created view (for example a by + * palette drag). Note that this includes both normal create events as well as well as + * views created as part of previewing operations. + * + * @return true if this {@link InsertType} is for a newly created view + */ + public boolean isCreate() { + return this == CREATE || this == CREATE_PREVIEW; + } +} diff --git a/rule_api/src/com/android/ide/common/api/MarginType.java b/rule_api/src/com/android/ide/common/api/MarginType.java new file mode 100644 index 0000000..d3a27a4 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/MarginType.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + + +/** + * A {@link MarginType} indicates whether a {@link Segment} corresponds to the visual edge + * of the node, or whether it is offset by a margin in the edge's direction, or whether + * it's both (which is the case when the margin is 0). + * <p> + * We need to keep track of the distinction because different constraints apply + * differently w.r.t. margins. Let's say you have a target node with a 50 dp margin in all + * directions. If you layout_alignTop with this node, the match will be on the visual + * bounds of the target node (ignoring the margin). If you layout_above this node, you + * will be offset by the margin on the target node. Therefore, we have to add <b>both</b> + * edges (the bounds of the target node with and without edges) and check for matches on + * each edge depending on the constraint being considered. + */ +public enum MarginType { + /** + * This margin type is used for nodes that have margins, and this segment includes the + * margin distance + */ + WITH_MARGIN, + + /** + * This margin type is used for nodes that have margins, and this segment does not + * include the margin distance + */ + WITHOUT_MARGIN, + + /** + * This margin type is used for nodes that do not have margins, so margin edges and + * non-margin edges are the same + */ + NO_MARGIN; +} diff --git a/rule_api/src/com/android/ide/common/api/Margins.java b/rule_api/src/com/android/ide/common/api/Margins.java new file mode 100644 index 0000000..40f44ce --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/Margins.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * Set of margins - distances to outer left, top, right and bottom edges. These objects + * can be used for both actual <b>margins</b> as well as insets - and in general any + * deltas to the bounds of a rectangle. + */ +public class Margins { + /** The left margin */ + public final int left; + + /** The right margin */ + public final int right; + + /** The top margin */ + public final int top; + + /** The bottom margin */ + public final int bottom; + + /** + * Creates a new {@link Margins} instance. + * + * @param left the left side margin + * @param right the right side margin + * @param top the top margin + * @param bottom the bottom margin + */ + public Margins(int left, int right, int top, int bottom) { + super(); + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; + } + + @Override + public String toString() { + return "Margins [left=" + left + ", right=" + right + ", top=" + top + ", bottom=" + bottom + + "]"; + } +} diff --git a/rule_api/src/com/android/ide/common/api/Point.java b/rule_api/src/com/android/ide/common/api/Point.java new file mode 100755 index 0000000..67c41d3 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/Point.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + + +/** + * Mutable point. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public class Point { + public int x, y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public Point(Point p) { + x = p.x; + y = p.y; + } + + /** Sets the point to the given coordinates. */ + public void set(int x, int y) { + this.x = x; + this.y = y; + } + + /** Returns a new instance of a point with the same values. */ + public Point copy() { + return new Point(x, y); + } + + /** + * Offsets this point by adding the given x,y deltas to the x,y coordinates. + * @return Returns self, for chaining. + */ + public Point offsetBy(int x, int y) { + this.x += x; + this.y += y; + return this; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Point) { + Point rhs = (Point) obj; + return this.x == rhs.x && this.y == rhs.y; + } + return false; + } + + @Override + public int hashCode() { + int h = x ^ ((y >> 16) & 0x0FFFF) ^ ((y & 0x0FFFF) << 16); + return h; + } + + @Override + public String toString() { + return String.format("Point [%dx%d]", x, y); + } +} diff --git a/rule_api/src/com/android/ide/common/api/Rect.java b/rule_api/src/com/android/ide/common/api/Rect.java new file mode 100755 index 0000000..f3922e2 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/Rect.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + + + +/** + * Mutable rectangle bounds. + * <p/> + * To be valid, w >= 1 and h >= 1. + * By definition: + * - right side = x + w - 1. + * - bottom side = y + h - 1. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public class Rect { + public int x, y, w, h; + + /** Initialize an invalid rectangle. */ + public Rect() { + } + + /** Initialize rectangle to the given values. They can be invalid. */ + public Rect(int x, int y, int w, int h) { + set(x, y, w, h); + } + + /** Initialize rectangle to the given values. They can be invalid. */ + public Rect(Rect r) { + set(r); + } + + /** Initialize rectangle to the given values. They can be invalid. */ + public Rect set(int x, int y, int w, int h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + return this; + } + + /** Initialize rectangle to match the given one. */ + public Rect set(Rect r) { + set(r.x, r.y, r.w, r.h); + return this; + } + + /** Returns a new instance of a rectangle with the same values. */ + public Rect copy() { + return new Rect(x, y, w, h); + } + + /** Returns true if the rectangle has valid bounds, i.e. w>0 and h>0. */ + public boolean isValid() { + return w > 0 && h > 0; + } + + /** Returns true if the rectangle contains the x,y coordinates, borders included. */ + public boolean contains(int x, int y) { + return isValid() && + x >= this.x && + y >= this.y && + x < (this.x + this.w) && + y < (this.y + this.h); + } + + /** Returns true if the rectangle contains the x,y coordinates, borders included. */ + public boolean contains(Point p) { + return p != null && contains(p.x, p.y); + } + + /** + * Moves this rectangle by setting it's x,y coordinates to the new values. + * @return Returns self, for chaining. + */ + public Rect moveTo(int x, int y) { + this.x = x; + this.y = y; + return this; + } + + /** + * Offsets this rectangle by adding the given x,y deltas to the x,y coordinates. + * @return Returns self, for chaining. + */ + public Rect offsetBy(int x, int y) { + this.x += x; + this.y += y; + return this; + } + + public Point getCenter() { + return new Point(x + (w > 0 ? w / 2 : 0), + y + (h > 0 ? h / 2 : 0)); + } + + public Point getTopLeft() { + return new Point(x, y); + } + + public Point getBottomLeft() { + return new Point(x, + y + (h > 0 ? h : 0)); + } + + public Point getTopRight() { + return new Point(x + (w > 0 ? w : 0), + y); + } + + public Point getBottomRight() { + return new Point(x + (w > 0 ? w : 0), + y + (h > 0 ? h : 0)); + } + + /** + * Returns the X coordinate of the right hand side of the rectangle + * + * @return the X coordinate of the right hand side of the rectangle + */ + public int x2() { + return x + w; + } + + /** + * Returns the Y coordinate of the bottom of the rectangle + * + * @return the Y coordinate of the bottom of the rectangle + */ + public int y2() { + return y + h; + } + + /** + * Returns the X coordinate of the center of the rectangle + * + * @return the X coordinate of the center of the rectangle + */ + public int centerX() { + return x + w / 2; + } + + /** + * Returns the Y coordinate of the center of the rectangle + * + * @return the Y coordinate of the center of the rectangle + */ + public int centerY() { + return y + h / 2; + } + + @Override + public String toString() { + return String.format("Rect [(%d,%d)-(%d,%d): %dx%d]", x, y, x + w, y + h, w, h); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Rect) { + Rect rhs = (Rect) obj; + // validity must be equal on both sides. + if (isValid() != rhs.isValid()) { + return false; + } + // an invalid rect is equal to any other invalid rect regardless of coordinates + if (!isValid() && !rhs.isValid()) { + return true; + } + + return this.x == rhs.x && this.y == rhs.y && this.w == rhs.w && this.h == rhs.h; + } + + return false; + } + + @Override + public int hashCode() { + int hc = x; + hc ^= ((y >> 8) & 0x0FFFFFF) | ((y & 0x00000FF) << 24); + hc ^= ((w >> 16) & 0x000FFFF) | ((w & 0x000FFFF) << 16); + hc ^= ((h >> 24) & 0x00000FF) | ((h & 0x0FFFFFF) << 8); + return hc; + } + + /** + * Returns the center point in the rectangle + * + * @return the center point in the rectangle + */ + public Point center() { + return new Point(x + w / 2, y + h / 2); + } +} diff --git a/rule_api/src/com/android/ide/common/api/ResizePolicy.java b/rule_api/src/com/android/ide/common/api/ResizePolicy.java new file mode 100644 index 0000000..05ad81c --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/ResizePolicy.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * A {@link ResizePolicy} records state for whether a widget is resizable, and if so, in + * which directions + */ +public class ResizePolicy { + private static final int NONE = 0; + private static final int LEFT_EDGE = 1; + private static final int RIGHT_EDGE = 2; + private static final int TOP_EDGE = 4; + private static final int BOTTOM_EDGE = 8; + private static final int PRESERVE_RATIO = 16; + + // Aliases + private static final int HORIZONTAL = LEFT_EDGE | RIGHT_EDGE; + private static final int VERTICAL = TOP_EDGE | BOTTOM_EDGE; + private static final int ANY = HORIZONTAL | VERTICAL; + + // Shared objects for common policies + + public static final ResizePolicy sAny = new ResizePolicy(ANY); + private static final ResizePolicy sNone = new ResizePolicy(NONE); + private static final ResizePolicy sHorizontal = new ResizePolicy(HORIZONTAL); + private static final ResizePolicy sVertical = new ResizePolicy(VERTICAL); + private static final ResizePolicy sScaled = new ResizePolicy(ANY | PRESERVE_RATIO); + + private final int mFlags; + + + // Use factory methods to construct + private ResizePolicy(int flags) { + mFlags = flags; + } + + /** + * Returns true if this policy allows resizing in at least one direction + * + * @return true if this policy allows resizing in at least one direction + */ + public boolean isResizable() { + return (mFlags & ANY) != 0; + } + + /** + * Returns true if this policy allows resizing the top edge + * + * @return true if this policy allows resizing the top edge + */ + public boolean topAllowed() { + return (mFlags & TOP_EDGE) != 0; + } + + /** + * Returns true if this policy allows resizing the right edge + * + * @return true if this policy allows resizing the right edge + */ + public boolean rightAllowed() { + return (mFlags & RIGHT_EDGE) != 0; + } + + /** + * Returns true if this policy allows resizing the bottom edge + * + * @return true if this policy allows resizing the bottom edge + */ + public boolean bottomAllowed() { + return (mFlags & BOTTOM_EDGE) != 0; + } + + /** + * Returns true if this policy allows resizing the left edge + * + * @return true if this policy allows resizing the left edge + */ + public boolean leftAllowed() { + return (mFlags & LEFT_EDGE) != 0; + } + + /** + * Returns true if this policy requires resizing in an aspect-ratio preserving manner + * + * @return true if this policy requires resizing in an aspect-ratio preserving manner + */ + public boolean isAspectPreserving() { + return (mFlags & PRESERVE_RATIO) != 0; + } + + /** + * Returns a resize policy allowing resizing in any direction + * + * @return a resize policy allowing resizing in any direction + */ + public static ResizePolicy full() { + return sAny; + } + + /** + * Returns a resize policy not allowing any resizing + * + * @return a policy which does not allow any resizing + */ + public static ResizePolicy none() { + return sNone; + } + + /** + * Returns a resize policy allowing horizontal resizing only + * + * @return a policy which allows horizontal resizing only + */ + public static ResizePolicy horizontal() { + return sHorizontal; + } + + /** + * Returns a resize policy allowing vertical resizing only + * + * @return a policy which allows vertical resizing only + */ + public static ResizePolicy vertical() { + return sVertical; + } + + /** + * Returns a resize policy allowing scaled / aspect-ratio preserving resizing only + * + * @return a resize policy allowing scaled / aspect-ratio preserving resizing only + */ + public static ResizePolicy scaled() { + return sScaled; + } + + /** + * Returns a resize policy with the specified resizability along the edges and the + * given aspect ratio behavior + * @param top whether the top edge is resizable + * @param right whether the right edge is resizable + * @param bottom whether the bottom edge is resizable + * @param left whether the left edge is resizable + * @param preserve whether the policy requires the aspect ratio to be preserved + * @return a resize policy recording the constraints required by the parameters + */ + public static ResizePolicy create(boolean top, boolean right, boolean bottom, boolean left, + boolean preserve) { + int mask = NONE; + if (top) mask |= TOP_EDGE; + if (right) mask |= RIGHT_EDGE; + if (bottom) mask |= BOTTOM_EDGE; + if (left) mask |= LEFT_EDGE; + if (preserve) mask |= PRESERVE_RATIO; + + return new ResizePolicy(mask); + } +} diff --git a/rule_api/src/com/android/ide/common/api/RuleAction.java b/rule_api/src/com/android/ide/common/api/RuleAction.java new file mode 100755 index 0000000..2ebab36 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/RuleAction.java @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +import com.android.util.Pair; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * A {@link RuleAction} represents an action provided by an {@link IViewRule}, typically + * shown in a context menu or in the layout actions bar. + * <p/> + * Each action should have a reasonably unique ID. This is used when multiple nodes + * are selected to filter the actions down to just those actions that are supported + * across all selected nodes. If an action does not support multiple nodes, it can + * return false from {@link #supportsMultipleNodes()}. + * <p/> + * Actions can be grouped into a hierarchy of sub-menus using the {@link NestedAction} class, + * or into a flat submenu using the {@link Choices} class. + * <p/> + * Actions (including separators) all have a "sort priority", and this is used to + * sort the menu items or toolbar buttons into a specific order. + * <p> + * <b>NOTE: This is not a public or final API; if you rely on this be prepared + * to adjust your code for the next tools release.</b> + * </p> + */ +public class RuleAction implements Comparable<RuleAction> { + /** + * Character used to split multiple checked choices. + * The pipe character "|" is used, to natively match Android resource flag separators. + */ + public final static String CHOICE_SEP = "|"; //$NON-NLS-1$ + + /** + * Same as {@link #CHOICE_SEP} but safe for use in regular expressions. + */ + public final static String CHOICE_SEP_PATTERN = Pattern.quote(CHOICE_SEP); + + /** + * The unique id of the action. + * @see #getId() + */ + private final String mId; + /** + * The UI-visible title of the action. + */ + private final String mTitle; + + /** A URL pointing to an icon, or null */ + private URL mIconUrl; + + /** + * A callback executed when the action is selected in the context menu. + */ + private final IMenuCallback mCallback; + + /** + * The sorting priority of this item; actions can be sorted according to these + */ + protected final int mSortPriority; + + /** + * Whether this action supports multiple nodes, see + * {@link #supportsMultipleNodes()} for details. + */ + private final boolean mSupportsMultipleNodes; + + /** + * Special value which will insert a separator in the choices' submenu. + */ + public final static String SEPARATOR = "----"; + + // Factories + + /** + * Constructs a new separator which will be shown in places where separators + * are supported such as context menus + * + * @param sortPriority a priority used for sorting this action + * @return a new separator + */ + public static Separator createSeparator(int sortPriority) { + return new Separator(sortPriority, true /* supportsMultipleNodes*/); + } + + /** + * Constructs a new base {@link RuleAction} with its ID, title and action callback. + * + * @param id The unique ID of the action. Must not be null. + * @param title The title of the action. Must not be null. + * @param callback The callback executed when the action is selected. + * Must not be null. + * @param iconUrl a URL pointing to an icon to use for this action, or null + * @param sortPriority a priority used for sorting this action + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @return the new {@link RuleAction} + */ + public static RuleAction createAction(String id, String title, + IMenuCallback callback, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) { + RuleAction action = new RuleAction(id, title, callback, sortPriority, + supportsMultipleNodes); + action.setIconUrl(iconUrl); + + return action; + } + + /** + * Creates a new immutable toggle action. + * + * @param id The unique id of the action. Cannot be null. + * @param title The UI-visible title of the context menu item. Cannot be null. + * @param isChecked Whether the context menu item has a check mark. + * @param callback A callback to execute when the context menu item is + * selected. + * @param iconUrl a URL pointing to an icon to use for this action, or null + * @param sortPriority a priority used for sorting this action + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @return the new {@link Toggle} + */ + public static Toggle createToggle(String id, String title, boolean isChecked, + IMenuCallback callback, URL iconUrl, int sortPriority, + boolean supportsMultipleNodes) { + Toggle toggle = new Toggle(id, title, isChecked, callback, sortPriority, + supportsMultipleNodes); + toggle.setIconUrl(iconUrl); + return toggle; + } + + /** + * Creates a new immutable multiple-choice action with a defined ordered set + * of action children. + * + * @param id The unique id of the action. Cannot be null. + * @param title The title of the action to be displayed to the user + * @param provider Provides the actions to be shown as children of this + * action + * @param callback A callback to execute when the context menu item is + * selected. + * @param iconUrl the icon to use for the multiple choice action itself + * @param sortPriority the sorting priority to use for the multiple choice + * action itself + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @return the new {@link NestedAction} + */ + public static NestedAction createChoices(String id, String title, + IMenuCallback callback, URL iconUrl, + int sortPriority, boolean supportsMultipleNodes, ActionProvider provider) { + NestedAction choices = new NestedAction(id, title, provider, callback, + sortPriority, supportsMultipleNodes); + choices.setIconUrl(iconUrl); + return choices; + } + + /** + * Creates a new immutable multiple-choice action with a defined ordered set + * of children. + * + * @param id The unique id of the action. Cannot be null. + * @param title The title of the action to be displayed to the user + * @param iconUrls The icon urls for the children items (may be null) + * @param ids The internal ids for the children + * @param current The id(s) of the current choice(s) that will be check + * marked. Can be null. Can be an id not present in the choices + * map. There can be more than one id separated by + * {@link #CHOICE_SEP}. + * @param callback A callback to execute when the context menu item is + * selected. + * @param titles The UI-visible titles of the children + * @param iconUrl the icon to use for the multiple choice action itself + * @param sortPriority the sorting priority to use for the multiple choice + * action itself + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @return the new {@link Choices} + */ + public static Choices createChoices(String id, String title, + IMenuCallback callback, List<String> titles, List<URL> iconUrls, List<String> ids, + String current, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) { + Choices choices = new Choices(id, title, callback, titles, iconUrls, + ids, current, sortPriority, supportsMultipleNodes); + choices.setIconUrl(iconUrl); + + return choices; + } + + /** + * Creates a new immutable multiple-choice action with a defined ordered set + * of children. + * + * @param id The unique id of the action. Cannot be null. + * @param title The title of the action to be displayed to the user + * @param iconUrls The icon urls for the children items (may be null) + * @param current The id(s) of the current choice(s) that will be check + * marked. Can be null. Can be an id not present in the choices + * map. There can be more than one id separated by + * {@link #CHOICE_SEP}. + * @param callback A callback to execute when the context menu item is + * selected. + * @param iconUrl the icon to use for the multiple choice action itself + * @param sortPriority the sorting priority to use for the multiple choice + * action itself + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @param idsAndTitles a list of pairs (of ids and titles) to use for the + * menu items + * @return the new {@link Choices} + */ + public static Choices createChoices(String id, String title, + IMenuCallback callback, List<URL> iconUrls, + String current, URL iconUrl, int sortPriority, + boolean supportsMultipleNodes, List<Pair<String, String>> idsAndTitles) { + int itemCount = idsAndTitles.size(); + List<String> titles = new ArrayList<String>(itemCount); + List<String> ids = new ArrayList<String>(itemCount); + for (Pair<String, String> pair : idsAndTitles) { + ids.add(pair.getFirst()); + titles.add(pair.getSecond()); + } + Choices choices = new Choices(id, title, callback, titles, iconUrls, + ids, current, sortPriority, supportsMultipleNodes); + choices.setIconUrl(iconUrl); + return choices; + } + + /** + * Creates a new immutable multiple-choice action with lazily computed children. + * + * @param id The unique id of the action. Cannot be null. + * @param title The title of the multiple-choice itself + * @param callback A callback to execute when the context menu item is + * selected. + * @param provider the provider which provides choices lazily + * @param current The id(s) of the current choice(s) that will be check + * marked. Can be null. Can be an id not present in the choice + * alternatives. There can be more than one id separated by + * {@link #CHOICE_SEP}. + * @param iconUrl the icon to use for the multiple choice action itself + * @param sortPriority the sorting priority to use for the multiple choice + * action itself + * @param supportsMultipleNodes whether this action supports multiple nodes, + * see {@link #supportsMultipleNodes()} for details + * @return the new {@link Choices} + */ + public static Choices createChoices(String id, String title, + IMenuCallback callback, ChoiceProvider provider, + String current, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) { + Choices choices = new DelayedChoices(id, title, callback, + current, provider, sortPriority, supportsMultipleNodes); + choices.setIconUrl(iconUrl); + return choices; + } + + /** + * Creates a new {@link RuleAction} with the given id and the given title. + * Actions which have the same id and the same title are deemed equivalent. + * + * @param id The unique id of the action, which must be similar for all actions that + * perform the same task. Cannot be null. + * @param title The UI-visible title of the action. + * @param callback A callback to execute when the context menu item is + * selected. + * @param sortPriority a priority used for sorting this action + * @param supportsMultipleNodes the new return value for + * {@link #supportsMultipleNodes()} + */ + private RuleAction(String id, String title, IMenuCallback callback, int sortPriority, + boolean supportsMultipleNodes) { + mId = id; + mTitle = title; + mSortPriority = sortPriority; + mSupportsMultipleNodes = supportsMultipleNodes; + mCallback = callback; + } + + /** + * Returns the unique id of the action. In the context of a multiple selection, + * actions which have the same id are collapsed together and must represent the same + * action. Cannot be null. + * + * @return the unique id of the action, never null + */ + public String getId() { + return mId; + } + + /** + * Returns the UI-visible title of the action, shown in the context menu. + * Cannot be null. + * + * @return the user name of the action, never null + */ + public String getTitle() { + return mTitle; + } + + /** + * Actions which have the same id and the same title are deemed equivalent. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof RuleAction) { + RuleAction rhs = (RuleAction) obj; + + if (mId != rhs.mId && !(mId != null && mId.equals(rhs.mId))) return false; + if (mTitle != rhs.mTitle && + !(mTitle != null && mTitle.equals(rhs.mTitle))) return false; + return true; + } + return false; + } + + /** + * Whether this action supports multiple nodes. An action which supports + * multiple nodes can be applied to different nodes by passing in different + * nodes to its callback. Some actions are hardcoded for a specific node (typically + * one that isn't selected, such as an action which affects the parent of a selected + * node), and these actions will not be added to the context menu when more than + * one node is selected. + * + * @return true if this node supports multiple nodes + */ + public boolean supportsMultipleNodes() { + return mSupportsMultipleNodes; + } + + /** + * Actions which have the same id and the same title have the same hash code. + */ + @Override + public int hashCode() { + int h = mId == null ? 0 : mId.hashCode(); + h = h ^ (mTitle == null ? 0 : mTitle.hashCode()); + return h; + } + + /** + * Gets a URL pointing to an icon to use for this action, if any. + * + * @return a URL pointing to an icon to use for this action, or null + */ + public URL getIconUrl() { + return mIconUrl; + } + + /** + * Sets a URL pointing to an icon to use for this action, if any. + * + * @param iconUrl a URL pointing to an icon to use for this action, or null + * @return this action, to allow setter chaining + */ + public RuleAction setIconUrl(URL iconUrl) { + mIconUrl = iconUrl; + + return this; + } + + /** + * Return a priority used for sorting this action + * + * @return a priority used for sorting this action + */ + public int getSortPriority() { + return mSortPriority; + } + + /** + * Returns the callback executed when the action is selected in the + * context menu. Cannot be null. + * + * @return the callback, never null + */ + public IMenuCallback getCallback() { + return mCallback; + } + + // Implements Comparable<MenuAciton> + public int compareTo(RuleAction other) { + if (mSortPriority != other.mSortPriority) { + return mSortPriority - other.mSortPriority; + } + + return mTitle.compareTo(other.mTitle); + } + + @Override + public String toString() { + return "RuleAction [id=" + mId + ", title=" + mTitle + ", priority=" + mSortPriority + "]"; + } + + /** A separator to display between actions */ + public static class Separator extends RuleAction { + /** Construct using the factory {@link #createSeparator(int)} */ + private Separator(int sortPriority, boolean supportsMultipleNodes) { + super("_separator", "", null, sortPriority, //$NON-NLS-1$ //$NON-NLS-2$ + supportsMultipleNodes); + } + } + + /** + * A toggle is a simple on/off action, displayed as an item in a context menu + * with a check mark if the item is checked. + * <p/> + * Two toggles are equal if they have the same id, title and group-id. + * It is expected for the checked state and action callback to be different. + */ + public static class Toggle extends RuleAction { + /** + * True if the item is displayed with a check mark. + */ + private final boolean mIsChecked; + + /** + * Creates a new immutable toggle action. + * + * @param id The unique id of the action. Cannot be null. + * @param title The UI-visible title of the context menu item. Cannot be null. + * @param isChecked Whether the context menu item has a check mark. + * @param callback A callback to execute when the context menu item is + * selected. + */ + private Toggle(String id, String title, boolean isChecked, + IMenuCallback callback, int sortPriority, boolean supportsMultipleNodes) { + super(id, title, callback, sortPriority, supportsMultipleNodes); + mIsChecked = isChecked; + } + + /** + * Returns true if the item is displayed with a check mark. + * + * @return true if the item is displayed with a check mark. + */ + public boolean isChecked() { + return mIsChecked; + } + + /** + * Two toggles are equal if they have the same id and title. + * It is acceptable for the checked state and action callback to be different. + */ + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * Two toggles have the same hash code if they have the same id and title. + */ + @Override + public int hashCode() { + return super.hashCode(); + } + } + + /** + * An ordered list of choices the user can choose between. For choosing between + * actions, there is a {@link NestedAction} class. + */ + public static class Choices extends RuleAction { + protected List<String> mTitles; + protected List<URL> mIconUrls; + protected List<String> mIds; + private boolean mRadio; + + /** + * One or more id for the checked choice(s) that will be check marked. + * Can be null. Can be an id not present in the choices map. + */ + protected final String mCurrent; + + private Choices(String id, String title, IMenuCallback callback, + List<String> titles, List<URL> iconUrls, List<String> ids, String current, + int sortPriority, boolean supportsMultipleNodes) { + super(id, title, callback, sortPriority, supportsMultipleNodes); + mTitles = titles; + mIconUrls = iconUrls; + mIds = ids; + mCurrent = current; + } + + /** + * Returns the list of urls to icons to display for each choice, or null + * + * @return the list of urls to icons to display for each choice, or null + */ + public List<URL> getIconUrls() { + return mIconUrls; + } + + /** + * Returns the list of ids for the menu choices, never null + * + * @return the list of ids for the menu choices, never null + */ + public List<String> getIds() { + return mIds; + } + + /** + * Returns the titles to be displayed for the menu choices, never null + * + * @return the titles to be displayed for the menu choices, never null + */ + public List<String> getTitles() { + return mTitles; + } + + /** + * Returns the current value of the choice + * + * @return the current value of the choice, possibly null + */ + public String getCurrent() { + return mCurrent; + } + + /** + * Set whether this choice list is best visualized as a radio group (instead of a + * dropdown) + * + * @param radio true if this choice list should be visualized as a radio group + */ + public void setRadio(boolean radio) { + mRadio = radio; + } + + /** + * Returns true if this choice list is best visualized as a radio group (instead + * of a dropdown) + * + * @return true if this choice list should be visualized as a radio group + */ + public boolean isRadio() { + return mRadio; + } + } + + /** + * An ordered list of actions the user can choose between. Similar to + * {@link Choices} but for actions instead. + */ + public static class NestedAction extends RuleAction { + /** The provider to produce the list of nested actions when needed */ + private final ActionProvider mProvider; + + private NestedAction(String id, String title, ActionProvider provider, + IMenuCallback callback, int sortPriority, + boolean supportsMultipleNodes) { + super(id, title, callback, sortPriority, supportsMultipleNodes); + mProvider = provider; + } + + /** + * Returns the nested actions available for the given node + * + * @param node the node to look up nested actions for + * @return a list of nested actions + */ + public List<RuleAction> getNestedActions(INode node) { + return mProvider.getNestedActions(node); + } + } + + /** Like {@link Choices}, but the set of choices is computed lazily */ + private static class DelayedChoices extends Choices { + private final ChoiceProvider mProvider; + + private DelayedChoices(String id, String title, + IMenuCallback callback, String current, ChoiceProvider provider, + int sortPriority, boolean supportsMultipleNodes) { + super(id, title, callback, null, null, null, current, sortPriority, + supportsMultipleNodes); + mProvider = provider; + } + + private void ensureInitialized() { + if (mTitles == null) { + mTitles = new ArrayList<String>(); + mIconUrls = new ArrayList<URL>(); + mIds = new ArrayList<String>(); + + mProvider.addChoices(mTitles, mIconUrls, mIds); + } + } + + @Override + public List<URL> getIconUrls() { + ensureInitialized(); + return mIconUrls; + } + + @Override + public List<String> getIds() { + ensureInitialized(); + return mIds; + } + + @Override + public List<String> getTitles() { + ensureInitialized(); + return mTitles; + } + } + + /** + * Provides the set of nested action choices associated with a {@link NestedAction} + * object when they are needed. Useful for lazy initialization of context + * menus and popup menus until they are actually needed. + */ + public interface ActionProvider { + /** + * Returns the nested actions available for the given node + * + * @param node the node to look up nested actions for + * @return a list of nested actions + */ + public List<RuleAction> getNestedActions(INode node); + } + + /** + * Provides the set of choices associated with an {@link Choices} + * object when they are needed. Useful for lazy initialization of context + * menus and popup menus until they are actually needed. + */ + public interface ChoiceProvider { + /** + * Adds in the needed titles, iconUrls (if any) and ids. + * Use {@link RuleAction#SEPARATOR} to create separators. + * + * @param titles a list of titles that the provider should append to + * @param iconUrls a list of icon URLs that the provider should append to + * @param ids a list of ids that the provider should append to + */ + public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids); + } +} diff --git a/rule_api/src/com/android/ide/common/api/Segment.java b/rule_api/src/com/android/ide/common/api/Segment.java new file mode 100644 index 0000000..9668b54 --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/Segment.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** + * A segment is a straight horizontal or vertical line between two points, typically an + * edge of a node but also possibly some internal segment like a baseline or a center + * line, and it can be offset by a margin from the node's visible bounds. + */ +public class Segment { + /** For horizontal lines, the y coordinate; for vertical lines the x */ + public final int at; + + /** The starting coordinate along the line */ + public final int from; + + /** The ending coordinate along the line */ + public final int to; + + /** Whether the edge is a top edge, a baseline edge, a left edge, etc */ + public final SegmentType edgeType; + + /** + * Whether the edge is offset from the node by a margin or not, or whether it has no + * margin + */ + public final MarginType marginType; + + /** The node that contains this edge */ + public final INode node; + + /** + * The id of the node. May be null (in which case id should be generated when + * move/resize is completed + */ + public final String id; + + public Segment(int at, int from, int to, INode node, String id, SegmentType edgeType, + MarginType marginType) { + this.at = at; + this.from = from; + this.to = to; + this.node = node; + this.id = id; + this.edgeType = edgeType; + this.marginType = marginType; + } + + @Override + public String toString() { + String nodeStr = node == null ? "null" : node.getFqcn().substring( + node.getFqcn().lastIndexOf(('.')) + 1); + return "Segment [edgeType=" + edgeType + ", node=" + nodeStr + ", at=" + at + ", id=" + id + + ", from=" + from + ", to=" + to + ", marginType=" + marginType + "]"; + } +} diff --git a/rule_api/src/com/android/ide/common/api/SegmentType.java b/rule_api/src/com/android/ide/common/api/SegmentType.java new file mode 100644 index 0000000..a21247d --- /dev/null +++ b/rule_api/src/com/android/ide/common/api/SegmentType.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.common.api; + +/** A segment type describes the different roles or positions a segment can have in a node */ +public enum SegmentType { + LEFT, TOP, RIGHT, BOTTOM, BASELINE, CENTER_VERTICAL, CENTER_HORIZONTAL, UNKNOWN; + + public boolean isHorizontal() { + return this == TOP || this == BOTTOM || this == BASELINE || this == CENTER_HORIZONTAL; + } + + /** + * Returns the X coordinate for an edge of this type given its bounds + * + * @param node the node containing the edge + * @param bounds the bounds of the node + * @return the X coordinate for an edge of this type given its bounds + */ + public int getX(INode node, Rect bounds) { + // We pass in the bounds rather than look it up via node.getBounds() because + // during a resize or move operation, we call this method to look up proposed + // bounds rather than actual bounds + switch (this) { + case RIGHT: + return bounds.x + bounds.w; + case TOP: + case BOTTOM: + case CENTER_VERTICAL: + return bounds.x + bounds.w / 2; + case UNKNOWN: + assert false; + return bounds.x; + case LEFT: + case BASELINE: + default: + return bounds.x; + } + } + + /** + * Returns the Y coordinate for an edge of this type given its bounds + * + * @param node the node containing the edge + * @param bounds the bounds of the node + * @return the Y coordinate for an edge of this type given its bounds + */ + public int getY(INode node, Rect bounds) { + switch (this) { + case TOP: + return bounds.y; + case BOTTOM: + return bounds.y + bounds.h; + case BASELINE: { + int baseline = node != null ? node.getBaseline() : -1; + if (node == null) { + // This happens when you are dragging an element and we don't have + // a node (only an IDragElement) such as on a palette drag. + // For now just hack it. + baseline = (int) (bounds.h * 0.8f); // HACK + } + return bounds.y + baseline; + } + case UNKNOWN: + assert false; + return bounds.y; + case RIGHT: + case LEFT: + case CENTER_HORIZONTAL: + default: + return bounds.y + bounds.h / 2; + } + } + + @Override + public String toString() { + return name(); + } +} |