001package org.gwtbootstrap3.client.ui.base;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2016 GwtBootstrap3
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
024import org.gwtbootstrap3.client.ui.base.mixin.IdMixin;
025import org.gwtbootstrap3.client.ui.base.mixin.PullMixin;
026import org.gwtbootstrap3.client.ui.constants.DeviceSize;
027import org.gwtbootstrap3.client.ui.constants.Pull;
028import org.gwtbootstrap3.client.ui.html.Text;
029
030import com.google.gwt.dom.client.Element;
031import com.google.gwt.dom.client.Style;
032import com.google.gwt.user.client.DOM;
033import com.google.gwt.user.client.ui.ComplexPanel;
034import com.google.gwt.user.client.ui.Widget;
035
036/**
037 * Base class for widgets that contain further widgets.
038 *
039 * @author Sven Jacobs
040 */
041public class ComplexWidget extends ComplexPanel implements HasId, HasResponsiveness, HasInlineStyle, HasPull {
042    private final IdMixin<ComplexWidget> idMixin = new IdMixin<ComplexWidget>(this);
043    private final PullMixin<ComplexWidget> pullMixin = new PullMixin<ComplexWidget>(this);
044
045    /**
046     * {@inheritDoc}
047     */
048    @Override
049    public void add(final Widget child) {
050        add(child, (Element) getElement());
051    }
052
053    /**
054     * Inserts a widget at a specific index
055     *
056     * @param child       - widget to be inserted
057     * @param beforeIndex - index for the widget
058     */
059    public void insert(final Widget child, final int beforeIndex) {
060        insert(child, (Element) getElement(), beforeIndex, true);
061    }
062
063    @Override
064    @Deprecated
065    protected void insert(Widget child, com.google.gwt.user.client.Element container,
066        int beforeIndex, boolean domInsert) {
067        // Validate index; adjust if the widget is already a child of this panel.
068        beforeIndex = adjustIndex(child, beforeIndex);
069
070        // Detach new child.
071        child.removeFromParent();
072
073        // Logical attach.
074        getChildren().insert(child, beforeIndex);
075
076        // Physical attach.
077        if (domInsert) {
078            // NOTE (issue #477): DO NOT call DOM.insertChild() to correctly handle
079            // text nodes insertion according to the logical child widgets order.
080            // Calling DOM.insertChild(container, TEXT_NODE, beforeIndex) will
081            // always append the text node at the last position.
082            //DOM.insertChild(container, child.getElement(), beforeIndex);
083            Widget beforeWidget = getChildren().size() > beforeIndex + 1 ?
084                    getChildren().get(beforeIndex + 1) : null;
085            if (beforeWidget == null) {
086                // Append to last position
087                DOM.appendChild(container, child.getElement());
088            } else {
089                // Insert before the node of beforeWidget
090                container.insertBefore(child.getElement(), beforeWidget.getElement());
091            }
092        } else {
093            DOM.appendChild(container, child.getElement());
094        }
095
096        // Adopt.
097        adopt(child);
098    }
099
100    /**
101     * <p><b>
102     * Overrides the remove(Widget) method to avoid potential NPE when
103     * removing a {@link Text} node which is not supposed to be a
104     * "widget" in GWT.
105     * </b></p>
106     * {@inheritDoc}
107     */
108    @Override
109    public boolean remove(Widget w) {
110        // Validate.
111        if (w.getParent() != this) {
112            return false;
113        }
114        // Orphan.
115        try {
116            orphan(w);
117        } finally {
118            // Physical detach.
119            Element elem = w.getElement();
120            // NOTE (issue #486): DO NOT call DOM.getParent() to correctly handle
121            // text node removing. Calling DOM.getParent(TEXT_NODE) will throw a
122            // NPE exception.
123            //DOM.getParent(elem).removeChild(elem);
124            elem.removeFromParent();
125
126            // Logical detach.
127            getChildren().remove(w);
128        }
129        return true;
130    }
131
132    /**
133     * {@inheritDoc}
134     */
135    @Override
136    public void setId(final String id) {
137        idMixin.setId(id);
138    }
139
140    /**
141     * {@inheritDoc}
142     */
143    @Override
144    public String getId() {
145        return idMixin.getId();
146    }
147
148    /**
149     * {@inheritDoc}
150     */
151    @Override
152    public void setVisibleOn(final DeviceSize deviceSize) {
153        StyleHelper.setVisibleOn(this, deviceSize);
154    }
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public void setHiddenOn(final DeviceSize deviceSize) {
161        StyleHelper.setHiddenOn(this, deviceSize);
162    }
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public void setMarginTop(final double margin) {
169        getElement().getStyle().setMarginTop(margin, Style.Unit.PX);
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public void setMarginLeft(final double margin) {
177        getElement().getStyle().setMarginLeft(margin, Style.Unit.PX);
178    }
179
180    /**
181     * {@inheritDoc}
182     */
183    @Override
184    public void setMarginRight(final double margin) {
185        getElement().getStyle().setMarginRight(margin, Style.Unit.PX);
186    }
187
188    /**
189     * {@inheritDoc}
190     */
191    @Override
192    public void setMarginBottom(final double margin) {
193        getElement().getStyle().setMarginBottom(margin, Style.Unit.PX);
194    }
195
196    /**
197     * {@inheritDoc}
198     */
199    @Override
200    public void setPaddingTop(final double padding) {
201        getElement().getStyle().setPaddingTop(padding, Style.Unit.PX);
202    }
203
204    /**
205     * {@inheritDoc}
206     */
207    @Override
208    public void setPaddingLeft(final double padding) {
209        getElement().getStyle().setPaddingLeft(padding, Style.Unit.PX);
210    }
211
212    /**
213     * {@inheritDoc}
214     */
215    @Override
216    public void setPaddingRight(final double padding) {
217        getElement().getStyle().setPaddingRight(padding, Style.Unit.PX);
218    }
219
220    /**
221     * {@inheritDoc}
222     */
223    @Override
224    public void setPaddingBottom(final double padding) {
225        getElement().getStyle().setPaddingBottom(padding, Style.Unit.PX);
226    }
227
228    /**
229     * {@inheritDoc}
230     */
231    @Override
232    public void setColor(String color) {
233        getElement().getStyle().setColor(color);
234    }
235
236    /**
237     * {@inheritDoc}
238     */
239    @Override
240    public void setPull(final Pull pull) {
241        pullMixin.setPull(pull);
242    }
243
244    /**
245     * {@inheritDoc}
246     */
247    @Override
248    public Pull getPull() {
249        return pullMixin.getPull();
250    }
251}