1d6124a176326169bc87cb29823ca2dc906689680Tor Norbye/*
2d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * Copyright (C) 2012 The Android Open Source Project
3d6124a176326169bc87cb29823ca2dc906689680Tor Norbye *
4d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * you may not use this file except in compliance with the License.
6d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * You may obtain a copy of the License at
7d6124a176326169bc87cb29823ca2dc906689680Tor Norbye *
8d6124a176326169bc87cb29823ca2dc906689680Tor Norbye *      http://www.eclipse.org/org/documents/epl-v10.php
9d6124a176326169bc87cb29823ca2dc906689680Tor Norbye *
10d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * Unless required by applicable law or agreed to in writing, software
11d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
12d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * See the License for the specific language governing permissions and
14d6124a176326169bc87cb29823ca2dc906689680Tor Norbye * limitations under the License.
15d6124a176326169bc87cb29823ca2dc906689680Tor Norbye */
16d6124a176326169bc87cb29823ca2dc906689680Tor Norbyepackage com.android.ide.eclipse.adt.internal.lint;
17d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
1812d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ANDROID_URI;
19d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
20d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin;
21d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport com.android.ide.eclipse.adt.AdtUtils;
22d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
2385e4a1a9dd133abb879ec211ce8dd385004edf22Xavier Ducrohetimport com.android.utils.XmlUtils;
24d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
25d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.core.resources.IFile;
26d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.core.resources.IMarker;
27d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.jface.text.IDocument;
28d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.jface.text.Region;
29d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.swt.graphics.Image;
30d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.ui.IEditorPart;
31d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.ui.ISharedImages;
32d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.ui.PartInitException;
33d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.ui.PlatformUI;
34d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
35d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
36d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.w3c.dom.Attr;
37d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.w3c.dom.Element;
38d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeimport org.w3c.dom.Node;
39d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
40d6124a176326169bc87cb29823ca2dc906689680Tor Norbye@SuppressWarnings("restriction") // DOM model
41d6124a176326169bc87cb29823ca2dc906689680Tor Norbyeabstract class SetPropertyFix extends DocumentFix {
42d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    private Region mSelect;
43d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
44d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    protected SetPropertyFix(String id, IMarker marker) {
45d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        super(id, marker);
46d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
47d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
48d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    /** Attribute to be added */
49d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    protected abstract String getAttribute();
50d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
519a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye    /** Whether it's in the android: namespace */
529a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye    protected abstract boolean isAndroidAttribute();
539a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye
5417f39d1945df1ec1d8eb6dee329aa6403c9e8b99Tor Norbye    protected String getProposal(Element element) {
55d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        return invokeCodeCompletion() ? "" : "TODO"; //$NON-NLS-1$
56d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
57d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
58d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    protected boolean invokeCodeCompletion() {
59d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        return false;
60d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
61d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
62d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    @Override
63d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    public boolean isCancelable() {
64d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        return false;
65d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
66d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
67d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    @Override
68d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    protected void apply(IDocument document, IStructuredModel model, Node node, int start,
69d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            int end) {
70d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        mSelect = null;
71d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
72d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        if (node instanceof Element) {
73d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            Element element = (Element) node;
7417f39d1945df1ec1d8eb6dee329aa6403c9e8b99Tor Norbye            String proposal = getProposal(element);
75d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            String localAttribute = getAttribute();
769a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            String prefix = null;
779a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            if (isAndroidAttribute()) {
789a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                prefix = XmlUtils.lookupNamespacePrefix(node, ANDROID_URI);
799a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            }
80d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            String attribute = prefix != null ? prefix + ':' + localAttribute : localAttribute;
81d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
82d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            // This does not work even though it should: it does not include the prefix
83d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            //element.setAttributeNS(ANDROID_URI, localAttribute, proposal);
84d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            // So workaround instead:
85d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            element.setAttribute(attribute, proposal);
86d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
879a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            Attr attr = null;
889a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            if (isAndroidAttribute()) {
899a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                attr = element.getAttributeNodeNS(ANDROID_URI, localAttribute);
909a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            } else {
919a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                attr = element.getAttributeNode(localAttribute);
929a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye            }
93d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            if (attr instanceof IndexedRegion) {
94d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                IndexedRegion region = (IndexedRegion) attr;
95d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                int offset = region.getStartOffset();
96d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                // We only want to select the value part inside the quotes,
97d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                // so skip the attribute and =" parts added by WST:
98d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                offset += attribute.length() + 2;
999a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                if (selectValue()) {
1009a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                    mSelect = new Region(offset, proposal.length());
1019a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye                }
102d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            }
103d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        }
104d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
105d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
1069a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye    protected boolean selectValue() {
1079a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye        return true;
1089a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye    }
1099a666a7cf24a78455482b79b4fbe4c1eba0481ceTor Norbye
110d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    @Override
111d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    public void apply(IDocument document) {
112d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        try {
113d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            IFile file = (IFile) mMarker.getResource();
114d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            super.apply(document);
115d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            AdtPlugin.openFile(file, mSelect, true);
116d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        } catch (PartInitException e) {
117d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            AdtPlugin.log(e, null);
118d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        }
119d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
120d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        // Invoke code assist
121d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        if (invokeCodeCompletion()) {
122d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            IEditorPart editor = AdtUtils.getActiveEditor();
123d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            if (editor instanceof AndroidXmlEditor) {
124d6124a176326169bc87cb29823ca2dc906689680Tor Norbye                ((AndroidXmlEditor) editor).invokeContentAssist(-1);
125d6124a176326169bc87cb29823ca2dc906689680Tor Norbye            }
126d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        }
127d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
128d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
129d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    @Override
130d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    public boolean needsFocus() {
131d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        // Because we need to show the editor with text selected
132d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        return true;
133d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
134d6124a176326169bc87cb29823ca2dc906689680Tor Norbye
135d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    @Override
136d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    public Image getImage() {
137d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
138d6124a176326169bc87cb29823ca2dc906689680Tor Norbye        return sharedImages.getImage(ISharedImages.IMG_OBJ_ADD);
139d6124a176326169bc87cb29823ca2dc906689680Tor Norbye    }
140a881b0b34678ad76c9f5eba62fac7a00a22ac606Tor Norbye}
141