diff options
author | Tor Norbye <tnorbye@google.com> | 2011-08-15 15:02:28 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-08-15 15:02:28 -0700 |
commit | a0bccbddc52575255c5ce19c9d2c96d9639d26ca (patch) | |
tree | 1b18c9529663f01158865c0768449dee18c38811 /rule_api | |
parent | 47d72b010e64bf0aa231895dd70a59ba3fde3630 (diff) | |
download | sdk-a0bccbddc52575255c5ce19c9d2c96d9639d26ca.zip sdk-a0bccbddc52575255c5ce19c9d2c96d9639d26ca.tar.gz sdk-a0bccbddc52575255c5ce19c9d2c96d9639d26ca.tar.bz2 |
Pull View Rules API into a separate library
This changeset pulls out the API classes from the plugin sources and
into a separate standalone .jar library. The library depends on the
common.jar library.
With the separate view API it should be possible to build designtime
helpers (view rules) for custom views to improve editing behavior in
the layout editor.
Change-Id: I20bb511668de2fe52910e5fe0bbd3ec2a18b5a08
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(); + } +} |