com.wit.and.dialog.internal.BaseDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.wit.and.dialog.internal.BaseDialog.java

Source

/*
 * =================================================================================
 * Copyright (C) 2012 Martin Albedinsky [Wolf-ITechnologies]
 * =================================================================================
 * Licensed under the Apache License, Version 2.0 or later (further "License" only);
 * ---------------------------------------------------------------------------------
 * You may use this file only in compliance with the License. More details and copy
 * of this License you may obtain at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * You can redistribute, modify or publish any part of the code written in this
 * file but as it is described in the License, the software distributed under the 
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES or CONDITIONS OF
 * ANY KIND.
 * 
 * See the License for the specific language governing permissions and limitations
 * under the License.
 * =================================================================================
 */
package com.wit.and.dialog.internal;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;

import com.wit.and.dialog.Dialog;
import com.wit.and.dialog.IDialog;
import com.wit.and.dialog.R;
import com.wit.and.dialog.manage.DialogOptions;

/**
 * <h4>Class Overview</h4>
 * <p>
 * Base implementation of customizable instance of {@link DialogFragment}. This implementation
 * allows to create native modal dialog window with title, body and buttons view. Handles base
 * logic of building dialog view, creation of dialog options from arguments, and also handles
 * setting of listeners and firing callbacks for them. See {@link Dialog} for common dialog
 * implementation or its derived classes for specific purpose implementations.
 * </p>
 * <h3>Basic call hierarchy:</h3>
 * <ul>
 * <li><b>1)</b> {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}</li>
 * <li><b>2)</b> {@link #onCreateDialogView(LayoutInflater, ViewGroup, Bundle)}</li>
 * <li><b>3)</b> {@link #onCreateTitleView(LayoutInflater, ViewGroup, Bundle)}</li>
 * <li><b>4)</b> {@link #onCreateBodyView(LayoutInflater, ViewGroup, Bundle)}</li>
 * <li><b>5)</b> {@link #onCreateButtonsView(com.wit.and.dialog.Dialog.Buttons, LayoutInflater, ViewGroup, Bundle)}</li>
 * <li><b>6)</b> {@link #onViewCreated(android.view.View, android.os.Bundle)}</li>
 * <li><b>7)</b> {@link #onInitViews(View)}</li>
 * <li><b>8)</b> {@link #onRestoreInstanceState(Bundle)}</li>
 * <li><b>9)</b> {@link #onStyleDialog(View, TypedArray)}</li>
 * <li><b>10)</b> {@link #onSetUpButtons(View)}</li>
 * <li><b>11)</b> {@link #onBindDialog(View, Bundle)}</li>
 * <li><b>12)</b> {@link #onActivityCreated(android.os.Bundle)}</li>
 * </ul>
 *
 * @author Martin Albedinsky
 * @see DialogFragment
 * @see com.wit.and.dialog.manage.DialogManager
 * @see com.wit.and.dialog.manage.DialogManager.IDialogFactory
 * @see com.wit.and.dialog.manage.DialogFactory
 */
public abstract class BaseDialog extends DialogFragment implements IDialog {

    /**
     * Constants =============================
     */

    /**
     * Bundle identifiers.
     */
    /**
     */
    protected static final String BUNDLE_OPTIONS = "com.wit.and.dialog.internal.BaseDialog.Bundle.Options";

    protected static final String BUNDLE_ID = "com.wit.and.dialog.internal.BaseDialog.Bundle.ID";

    protected static final String BUNDLE_PARENT_FRAGMENT_TAG = "com.wit.and.dialog.internal.BaseDialog.Bundle.ParentFragmentTag";

    protected static final String BUNDLE_DIALOG_THEME = "com.wit.and.dialog.internal.BaseDialog.Bundle.DialogTheme";

    /**
     * Log TAG.
     */
    private static final String TAG = BaseDialog.class.getSimpleName();

    /**
     * Indicates if debug private output trough log-cat is enabled.
     */
    private static final boolean DEBUG = false;

    /**
     * Ids of the dialog views.
     */

    /**
     * Indicates if logging for user output trough log-cat is enabled.
     */
    // private static final boolean USER_LOG = true;

    private static final String BUNDLE_DISMISS_AFTER_RECREATE = "com.wit.and.dialog.internal.BaseDialog.Bundle.DismissAfterRecreate";

    /**
     * Default identifiers for dialog view parts if we build dialog as relative
     * layout.
     */
    /**
     */
    private static final int DIALOG_VIEW_DEFAULT_ID = 0xaa3560f;

    private static final int TITLE_VIEW_DEFAULT_ID = 0xaa3561f;

    private static final int BODY_VIEW_DEFAULT_ID = 0xaa3562f;

    private static final int BUTTONS_VIEW_DEFAULT_ID = 0xaa3563f;

    /**
     * Enums =================================
     */

    /**
     * <p>
     * Dialog button.
     * </p>
     */
    public enum DialogButton {
        /**
         * <p>
         * </p>
         */
        POSITIVE,
        /**
         * <p>
         * </p>
         */
        NEGATIVE,
        /**
         * <p>
         * </p>
         */
        NEUTRAL,
        /**
         * <p>
         * </p>
         */
        UNDEFINED
    }

    /**
     * <p>
     * </p>
     */
    protected enum DialogLayoutCorrection {
        /**
         * <p>
         * </p>
         */
        WITH_TITLE_AND_BUTTONS,
        /**
         * <p>
         * </p>
         */
        WITH_TITLE,
        /**
         * <p>
         * </p>
         */
        WITHOUT_TITLE,
        /**
         * <p>
         * </p>
         */
        WITH_BUTTONS,
        /**
         * <p>
         * </p>
         */
        WITHOUT_BUTTONS,
        /**
         * <p>
         * </p>
         */
        WITHOUT_BOTH
    }

    /**
     * Static members ========================
     */

    /**
     * Members ===============================
     */

    /**
     * Id of the dialog view.
     */
    private int mDialogViewID = DIALOG_VIEW_DEFAULT_ID;

    /**
     * Id of the dialog to identify different instances of the dialogs. Default
     * set to random <code>-1</code>.
     */
    private int mDialogID = -1;

    /**
     * FastOptions for this dialog. Like dialog title, message text and so on.
     */
    private DialogOptions mOptions = null;

    /**
     * Actual correction for the dialog layout (only relative layout is
     * corrected).
     */
    private DialogLayoutCorrection mLayoutCorrection = DialogLayoutCorrection.WITHOUT_BOTH;

    /**
     * Dialog theme.
     */
    private int mDialogTheme = R.style.And_Theme_Dialog;

    /**
     * Layout inflater to later handling of inflating some changed layouts (like
     * buttons view).
     */
    private LayoutInflater mInflater;

    /**
     * Tag of the fragment if this dialog was showed by dialog manger
     * initialized in the fragment.
     */
    private String mParentFragmentTag = null;

    /**
     * Dialog view.
     */
    private View mTitleView, mBodyView, mButtonsView, mDialogView;

    /**
     * Listeners -----------------------------
     */

    /**
     * Base dialog listener.
     */
    private OnDialogListener iListener, iParentListener;

    /**
     * Dialog listener to receive cancel action.
     */
    private OnDialogCancelListener iCancelListener, iParentCancelListener;

    /**
     * Arrays --------------------------------
     */

    /**
     * Booleans ------------------------------
     */

    /**
     * Indicates if the dialog view is already binded with dialog data.
     */
    private boolean bViewBinded = false;

    /**
     * Indicates if the whole dialog view is already inflated.
     */
    private boolean bViewInflated = false;

    /**
     * Indicates if the style should be parsed from the theme.
     */
    private boolean bObtainOuterStyle = true;

    private boolean bCalled = false;

    /**
     * Constructors ==========================
     */

    /**
     * <p>
     * </p>
     */
    protected BaseDialog() {
    }

    /**
     * Methods ===============================
     */

    /**
     * Public --------------------------------
     */

    /**
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Check bundle.
        if (savedInstanceState != null) {
            // Check if we should dismiss the dialog.
            if (savedInstanceState.getBoolean(BUNDLE_DISMISS_AFTER_RECREATE, false)) {
                this.dismissAllowingStateLoss();
            }

            // Recreate dialog options.
            this.createOptions(savedInstanceState);

            // Restore dialog theme.
            if (savedInstanceState.containsKey(BUNDLE_DIALOG_THEME)) {
                mDialogTheme = savedInstanceState.getInt(BUNDLE_DIALOG_THEME);
            }
        } else {
            // Create dialog options from arguments.
            this.createOptions(this.getArguments());

            /**
             * Dialog theme priority (from the highest to the lowest):
             * <ul>
             * <li>1) Custom theme (set by setStyle())</li>
             * <li>2) Custom theme (obtained form dialog options)</li>
             * <li>3) Custom theme (obtained from the activity/application theme)</li>
             * <li>4) Default theme</li>
             * </ul>
             */
            if (bObtainOuterStyle) {
                // Style wasn't set by setStyle() method, check for theme in dialog options.
                mDialogTheme = mOptions.getDialogTheme();

                if (mDialogTheme <= 0) {
                    // Dialog options doesn't contains valid dialog theme.
                    mDialogTheme = R.style.And_Theme_Dialog;
                    // Get dialog theme from application theme.
                    final Context context = getActivity();
                    final Resources.Theme theme = context.getTheme();
                    if (theme != null) {
                        final TypedArray styleArray = theme
                                .obtainStyledAttributes(new int[] { R.attr.dialogTheme });
                        if (styleArray != null) {
                            mDialogTheme = styleArray.getResourceId(0, mDialogTheme);
                            styleArray.recycle();
                        }
                    }
                }
            }
        }

        // Set super theme.
        super.setStyle(Dialog.STYLE_NO_FRAME, mDialogTheme);
        this.bObtainOuterStyle = false;
    }

    /**
     */
    @Override
    public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the dialog main view.
        View dialogView = onCreateDialogView(inflater, container, savedInstanceState);

        // Check valid dialog view.
        if (dialogView == null) {
            Log.e(TAG, "Dialog layout or dialog view not inflated correctly.");

            return super.onCreateView(inflater, container, savedInstanceState);
        } else {
            // Save inflater for later usage.
            this.mInflater = inflater;

            // Build dialog view.
            this.buildDialogView(dialogView, inflater, savedInstanceState);

            // Mark our created view.
            if (dialogView.getId() != View.NO_ID) {
                this.mDialogViewID = dialogView.getId();
            } else {
                dialogView.setId(mDialogViewID);
            }

            // Return inflated dialog view.
            return dialogView;
        }
    }

    /**
     */
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This resolves dialog listener even, when any listener wasn't set, but
        // if this dialog was showed in the context of activity (fragment) which is
        // currently implementing OnDialogListener or OnDialogNeutralListener or
        // OnDialogCancelListener, we take that as that activity (fragment) want
        // to be informed about dialog callback.
        Fragment fragment = getCurrentFragment();

        // Resolve parent listener.
        boolean resolved = false;
        if (fragment != null) {
            if (fragment instanceof OnDialogListener) {
                this.iParentListener = (OnDialogListener) fragment;
                resolved = true;
            }
            if (fragment instanceof OnDialogCancelListener) {
                this.iParentCancelListener = (OnDialogCancelListener) fragment;
                resolved = true;
            }
        }
        if (!resolved && activity != null) {
            if (activity instanceof OnDialogListener) {
                this.iParentListener = (OnDialogListener) activity;
            }
            if (activity instanceof OnDialogCancelListener) {
                this.iParentCancelListener = (OnDialogCancelListener) activity;
            }
        }
    }

    @Override
    public final void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // Save dialog view.
        this.mDialogView = view.findViewById(mDialogViewID);

        // Inflate dialog view objects.
        this.performInitViews();

        if (savedInstanceState != null) {
            // Recreate all dialog necessary data.
            performRestoreInstanceState(savedInstanceState);
        }

        // Update style.
        this.performStyleDialog();

        // Reset layout correction and perform dialog binding.
        this.mLayoutCorrection = DialogLayoutCorrection.WITHOUT_BOTH;
        this.performBindDialog(savedInstanceState);
    }

    /**
     */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // Save dialog options data.
        this.fillBundleWithOptions(outState);

        // Save dialog tag and id.
        outState.putString(BUNDLE_PARENT_FRAGMENT_TAG, mParentFragmentTag);
        // Secure save the parent fragment tag. In some cases maybe the
        // onAttachToAdapter() called before onCreateView() where is the parent
        // tag restored in the onRestoreInstanceState().
        getArguments().putString(BUNDLE_PARENT_FRAGMENT_TAG, mParentFragmentTag);

        // Save dialog id.
        outState.putInt(BUNDLE_ID, mDialogID);

        // Internal state.
        outState.putBoolean(BUNDLE_DISMISS_AFTER_RECREATE, mOptions.shouldDismissOnRestore());

        // Save dialog theme.
        if (!bObtainOuterStyle) {
            outState.putInt(BUNDLE_DIALOG_THEME, mDialogTheme);
        }

        // Save persistent listeners.
        if (iListener != null && iListener instanceof OnDialogPersistentListener) {
            ((OnDialogPersistentListener) iListener).saveIntoState(outState);
        }
        if (iCancelListener != null && iCancelListener instanceof OnDialogPersistentListener) {
            ((OnDialogPersistentListener) iCancelListener).saveIntoState(outState);
        }
    }

    /**
     */
    @Override
    public void cancel() {
        this.dismiss();
    }

    /**
     * Getters + Setters ---------------------
     */

    /**
     * <h5><i>public void setOnDialogListener(OnDialogListener
     * listener)</i></h5>
     * <p>
     * Registers a callback to be invoked when some of the dialog buttons
     * is being clicked.
     * </p>
     *
     * @param listener Listener callback.
     */
    public void setOnDialogListener(OnDialogListener listener) {
        this.iListener = listener;
    }

    /**
     * <h5><i>public void setOnCancelListener(OnDialogCancelListener
     * listener)</i></h5>
     * <p>
     * Registers a callback to be invoked when the dialog is being canceled by
     * the user.
     * </p>
     *
     * @param listener Listener callback.
     */
    public void setOnCancelListener(OnDialogCancelListener listener) {
        this.iCancelListener = listener;
    }

    /**
     */
    @Override
    public final void setDialogID(int dialogID) {
        this.mDialogID = dialogID;
    }

    /**
     * <p>
     * Sets the tag of the parent fragment.
     * </p>
     *
     * @param tag Tag of the fragment which use the dialog manager to show this
     *            dialog.
     */
    public final void setParentFragmentTag(String tag) {
        this.mParentFragmentTag = tag;
    }

    /**
     * <p>
     * Returns the tag of the parent fragment.
     * </p>
     *
     * @return Parent fragment tag if this dialog was showed by
     * {@link com.wit.and.dialog.manage.DialogManager} from fragment context,
     * <code>null</code> otherwise.
     */
    public final String getParentFragmentTag() {
        return mParentFragmentTag;
    }

    /**
     */
    @Override
    public final int getDialogID() {
        return mDialogID;
    }

    /**
     * <p>
     * Returns actual dialog options with all dialog data (title, message, icon
     * resource id, ...). You can modify this data trough this options.
     * </p>
     */
    public DialogOptions getOptions() {
        return (mOptions == null) ? getArguments().<DialogOptions>getParcelable(BUNDLE_OPTIONS) : mOptions;
    }

    /**
     * <p>
     * Returns whole dialog view in which are all dialog views (title, body, buttons) placed.
     * Note that this can be {@link android.widget.LinearLayout} or {@link android.widget.RelativeLayout}.
     * </p>
     *
     * @return Dialog view created inside {@link #onCreateDialogView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)}.
     */
    public View getDialogView() {
        return mDialogView;
    }

    /**
     */
    @Override
    public final void setStyle(int style, int theme) {
        super.setStyle(style, theme);
        this.mDialogTheme = theme;

        // Save state.
        this.bObtainOuterStyle = false;

        // Refresh dialog style.
        if (bViewBinded) {
            performStyleDialog();
        }
    }

    /**
     * <p>
     * Sets dialog theme for this dialog. Theme will be applied only
     * to this dialog instance.
     * </p>
     * <p>
     * Theme should have as its parent set to {@link com.wit.and.dialog.R.style#And_Theme_Dialog} or related
     * (colored) dialog themes like {@link com.wit.and.dialog.R.style#And_Theme_Dialog_Lime}.
     * </p>
     *
     * @param theme Theme to apply.
     */
    public final void setDialogTheme(int theme) {
        setStyle(Dialog.STYLE_NO_FRAME, theme);
    }

    /**
     * <p>
     * Returns current dialog theme resource id.
     * </p>
     *
     * @return Dialog theme.
     */
    public int getDialogTheme() {
        return mDialogTheme;
    }

    /**
     */
    @Override
    public void onCancel(DialogInterface dialog) {
        super.onCancel(dialog);

        // Invoke for listener.
        if (this.iCancelListener != null) {
            this.iCancelListener.onDialogCancelled(this);
        }

        // Invoke for parent listener.
        if (iParentCancelListener != null) {
            this.iParentCancelListener.onDialogCancelled(this);
        }
    }

    /**
     * Protected -----------------------------
     */

    /**
     * <h5><i>protected static Bundle createArguments(DialogOptions
     * options)</i></h5>
     * <p>
     * Creates dialog arguments from the given dialog options.
     * </p>
     *
     * @param options Dialog options from which will be arguments created.
     * @return Dialog arguments as Bundle.
     */
    protected static Bundle createArguments(DialogOptions options) {
        Bundle args = new Bundle();
        // Fill dialog arguments.
        if (options != null) {
            fillBundleWithOptions(args, options);
        }
        return args;
    }

    /**
     *
     */
    protected final void performInitViews() {
        onInitViews(mDialogView);
    }

    /**
     *
     */
    protected final void performSetUpButtons() {
        onSetUpButtons(mDialogView);
    }

    /**
     * <p>
     * Dispatches message that dialog layout should be corrected. Correction is performed only
     * in case that the given dialog view isn't instance of {@link LinearLayout}.
     * </p>
     *
     * @param requestedCorrection Requested correction to be applied to the dialog layout.
     * @param dialogView          Currently inflated or actual dialog main view.
     */
    protected final void dispatchCorrectLayout(DialogLayoutCorrection requestedCorrection, View dialogView) {
        // Correct only if main dialog view is not an RelativeLayout.
        if (!(dialogView instanceof LinearLayout)) {
            performCorrectLayout(requestedCorrection, dialogView);
        }
    }

    /**
     * <p>
     * Returns the layout inflater initialized when this dialog was created.
     * </p>
     *
     * @return Actual layout inflater.
     */
    protected final LayoutInflater getLayoutInflater() {
        return mInflater;
    }

    /**
     * <p>
     * Returns actual merged layout correction if you call this after
     * <code>super.onCorrectRelativeLayout()</code> or last merged correction if
     * you call <code>super</code> after your custom layout correction.
     * </p>
     *
     * @return Merged layout correction state.
     */
    protected final DialogLayoutCorrection getMergedLayoutCorrection() {
        return mLayoutCorrection;
    }

    /**
     * <p>
     * Checks if the dialog view is binded.
     * </p>
     *
     * @return True if the dialog view is already binded otherwise false.
     */
    protected final boolean isViewBinded() {
        return bViewBinded;
    }

    /**
     * <p>
     * Returns flag indicating if dialog view is inflated.
     * </p>
     *
     * @return <code>True</code> if dialog view is already infalted, <code>false</code> otherwise.
     */
    protected final boolean isViewInflated() {
        return bViewInflated;
    }

    /**
     * <p>
     * Returns the view depends on the given id.
     * </p>
     * <p>
     * <b>Note: </b> This can be called only in the {@link #onInitViews(View)}
     * method or after it. Earlier calling this method will return null.
     * </p>
     *
     * @param viewID Dialog view id.
     * @return The view which has the given id, or <code>null</code> if there is
     * no view with the given id.
     */
    protected View findViewByID(int viewID) {
        return (mDialogView != null) ? mDialogView.findViewById(viewID) : null;
    }

    /**
     * <h5><i>protected View onCreateDialogView(LayoutInflater inflater,
     * ViewGroup container, Bundle savedInstanceState)</i></h5>
     * <p>
     * Create the dialog main view into which will be placed title, body and
     * buttons view.
     * </p>
     *
     * @param inflater           Layout inflater.
     * @param container          Inflated dialog main view.
     * @param savedInstanceState Saved state.
     * @return Inflated dialog view.
     */
    protected View onCreateDialogView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        LinearLayout layout = new LinearLayout(inflater.getContext());
        layout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        layout.setOrientation(LinearLayout.VERTICAL);
        return layout;
    }

    /**
     * <p>
     * Performs invocation of styling methods to style dialog view.
     * {@link #onStyleDialog(android.view.View, android.content.res.TypedArray)} is
     * invoked immediately if parsed typed array is valid.
     * </p>
     */
    protected final void performStyleDialog() {
        TypedArray parsedArray = getActivity().obtainStyledAttributes(mDialogTheme, R.styleable.And_Theme_Dialog);

        if (parsedArray != null) {
            // Style.
            onStyleDialog(mDialogView, parsedArray);
            parsedArray.recycle();
        }
    }

    /**
     * <p>
     * Invoked when some of the buttons in the base dialog view was clicked.
     * </p>
     *
     * @param button Dialog button identifier.
     */
    protected void onButtonClick(DialogButton button) {
        // Fire for listener.
        if (iListener != null) {
            iListener.onDialogButtonClick(this, button);
        }

        // Fire for parent listener.
        if (iParentListener != null) {
            iParentListener.onDialogButtonClick(this, button);
        }
    }

    /**
     * <p>
     * Corrects the dialog view (if is instance of <code>RelativeLayout</code>).
     * This actually place the dialog main views (title, body, buttons) into
     * correct place. If you decide override this for better dialog view
     * performance it is necessary to call <code>super</code> here.
     * </p>
     *
     * @param requestedCorrection Requested operation for correction in the dialog view as
     *                            relative layout.
     * @param dialogView          Inflated dialog view.
     */
    protected void onCorrectLayout(DialogLayoutCorrection requestedCorrection, View dialogView) {
        // Save call state.
        this.bCalled = true;

        // Perform only if we have valid body view.
        if (mBodyView == null || mLayoutCorrection == requestedCorrection
                || !(dialogView instanceof RelativeLayout))
            return;

        // Create layout parameters for body and buttons view.
        RelativeLayout.LayoutParams bodyParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        RelativeLayout.LayoutParams buttonsParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        if (mBodyView.getLayoutParams() != null) {
            bodyParams = new RelativeLayout.LayoutParams(mBodyView.getLayoutParams());
        }
        if (mButtonsView != null && mButtonsView.getLayoutParams() != null) {
            buttonsParams = new RelativeLayout.LayoutParams(mButtonsView.getLayoutParams());
        }

        // Default merge.
        DialogLayoutCorrection helper = this.mLayoutCorrection;
        this.mLayoutCorrection = requestedCorrection;

        // Merge actual state of the relative layout correction.
        switch (requestedCorrection) {
        case WITH_TITLE_AND_BUTTONS:
        case WITHOUT_BOTH:
            break;
        case WITH_TITLE:
            if (helper == DialogLayoutCorrection.WITH_BUTTONS) {
                this.mLayoutCorrection = DialogLayoutCorrection.WITH_TITLE_AND_BUTTONS;
            }
            break;
        case WITHOUT_TITLE:
            if (helper == DialogLayoutCorrection.WITH_BUTTONS) {
                this.mLayoutCorrection = DialogLayoutCorrection.WITH_TITLE_AND_BUTTONS;
            } else if (helper == DialogLayoutCorrection.WITHOUT_BUTTONS) {
                this.mLayoutCorrection = DialogLayoutCorrection.WITHOUT_BOTH;
            }
            break;
        case WITH_BUTTONS:
            if (helper == DialogLayoutCorrection.WITH_TITLE_AND_BUTTONS) {
                return;
            } else if (helper == DialogLayoutCorrection.WITH_TITLE) {
                this.mLayoutCorrection = DialogLayoutCorrection.WITH_TITLE_AND_BUTTONS;
            }
            break;
        case WITHOUT_BUTTONS:
            if (helper == DialogLayoutCorrection.WITHOUT_TITLE) {
                this.mLayoutCorrection = DialogLayoutCorrection.WITHOUT_BOTH;
            }
            break;
        }

        // We just will set new parameters to the body view, which can depends
        // on the title or buttons view existence in the layout but in some
        // situations we don't have for example title view in the dialog view
        // (if the title text is empty).
        switch (mLayoutCorrection) {
        case WITH_TITLE_AND_BUTTONS:
            if (mTitleView != null) {
                bodyParams.addRule(RelativeLayout.BELOW, mTitleView.getId());
            }
            buttonsParams.addRule(RelativeLayout.BELOW, mBodyView.getId());
            break;
        case WITHOUT_TITLE:
        case WITH_BUTTONS:
            bodyParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
            buttonsParams.addRule(RelativeLayout.BELOW, mBodyView.getId());
            break;
        case WITHOUT_BUTTONS:
        case WITH_TITLE:
            if (mTitleView != null) {
                bodyParams.addRule(RelativeLayout.BELOW, mTitleView.getId());
            }
            break;
        case WITHOUT_BOTH:
            bodyParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
            break;
        }

        if (DEBUG)
            Log.d(TAG, "Dialog layout corrected to state " + mLayoutCorrection);

        // Set new parameters to the body view.
        mBodyView.setLayoutParams(bodyParams);
        // Set new parameters to the buttons view if we have it.
        if (mButtonsView != null) {
            mButtonsView.setLayoutParams(buttonsParams);
        }
    }

    /**
     * <p>
     * Adds the given inflated child view into inflated main dialog view.
     * </p>
     *
     * @param dialogView Inflated dialog view.
     * @param childView  Inflated dialog child view.
     */
    protected final void addView(View dialogView, View childView) {
        this.addView(dialogView, childView, null);
    }

    /**
     * <p>
     * Adds the given inflated child view into inflated main dialog view.
     * </p>
     *
     * @param dialogView  Inflated dialog view.
     * @param childView   Inflated dialog child view.
     * @param childParams Layout parameters to set to child view.
     */
    protected final void addView(View dialogView, View childView, LayoutParams childParams) {
        // Check valid child view.
        if (childView == null)
            return;

        // Check dialog view layout instance.
        if (dialogView instanceof LinearLayout) {
            // Check for layout parameters.
            if (childParams == null) {
                ((LinearLayout) dialogView).addView(childView);
            } else {
                ((LinearLayout) dialogView).addView(childView, childParams);
            }
        } else if (dialogView instanceof RelativeLayout) {
            // Check for layout parameters.
            if (childParams == null) {
                ((RelativeLayout) dialogView).addView(childView);
            } else {
                ((RelativeLayout) dialogView).addView(childView, childParams);
            }
        }

        if (DEBUG)
            Log.d(TAG, "addView() id = " + childView.getId());
    }

    /**
     * <p>
     * Restores the dialog from the saved bundle. Invoked between
     * {@link #onInitViews(android.view.View)} and
     * {@link #onStyleDialog(android.view.View, android.content.res.TypedArray)}.
     * </p>
     *
     * @param savedInstanceState Saved dialog instance state.
     * @see #onBindDialog(View, Bundle)
     */
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        // Save call state.
        this.bCalled = true;

        // Restore dialog tag id.
        this.mParentFragmentTag = savedInstanceState.getString(BUNDLE_PARENT_FRAGMENT_TAG);
        this.mDialogID = savedInstanceState.getInt(BUNDLE_ID);

        // Restore persistent listeners.
        if (savedInstanceState.containsKey(OnDialogPersistentListener.BUNDLE_TAG)) {
            this.iListener = OnDialogPersistentListener.fromSavedState(savedInstanceState);
        }
        if (savedInstanceState.containsKey(OnDialogPersistentCancelListener.BUNDLE_TAG)) {
            this.iCancelListener = OnDialogPersistentCancelListener.fromSavedState(savedInstanceState);
        }
    }

    /**
     * <p>
     * Returns the current fragment which is showed under this dialog and is
     * also responsible for the showing of this dialog.
     * </p>
     *
     * @return Current visible fragment or <code>null</code> if the parent
     * fragment tag isn't valid.
     */
    protected Fragment getCurrentFragment() {
        if (mParentFragmentTag == null && getArguments() != null) {
            // Try to get tag from the arguments.
            mParentFragmentTag = getArguments().getString(BUNDLE_PARENT_FRAGMENT_TAG);
        }

        return this.getFragmentManager().findFragmentByTag(this.mParentFragmentTag);
    }

    /**
     * <p>
     * Checks if dialog should be dismissed.
     * </p>
     */
    protected final void checkIfDismiss() {
        // Check if we should let this dialog showing.
        if (!mOptions.shouldRemain()) {
            this.dismiss();
        }
    }

    /**
     * Private -------------------------------
     */

    /**
     * Fills the given bundle with the given dialog options data to save them
     * because of later usage to recreate them after it was this dialog
     * destroyed (after orientation change).
     *
     * @param bundle  The bundle to fill with dialog options.
     * @param options Dialog options to save.
     */
    private static void fillBundleWithOptions(Bundle bundle, DialogOptions options) {
        // Dialog options object implements parcel-able so we can just put it
        // into bundle and then restore it.
        bundle.putParcelable(BUNDLE_OPTIONS, options);
    }

    /**
     * Builds whole dialog view.
     */
    private void buildDialogView(View dialogView, LayoutInflater inflater, Bundle savedInstanceState) {
        if (((ViewGroup) dialogView).getChildCount() > 0)
            // Do not build dialog view if it is already binded with some views.
            return;

        // Check if the main dialog view doesn't contain any view.
        if (dialogView instanceof LinearLayout) {
            // Build dialog view as linear layout.
            this.buildAsLinearLayout(dialogView, inflater, (ViewGroup) dialogView, savedInstanceState);
        } else if (dialogView instanceof RelativeLayout) {
            // Build dialog view as relative layout.
            this.buildAsRelativeLayout(dialogView, inflater, (ViewGroup) dialogView, savedInstanceState);
        }

        // Save state.
        this.bViewInflated = true;
    }

    /**
     * Builds dialog view as linear layout. This only adds the base dialog views
     * (title, body, buttons) in correct order into dialog view.
     */
    private void buildAsLinearLayout(View dialogView, LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Build the dialog from the base dialog views (title, body, buttons).
        this.addView(dialogView, this.mTitleView = performCreateTitleView(inflater, container, savedInstanceState));
        this.addView(dialogView, this.mBodyView = performCreateBodyView(inflater, container, savedInstanceState));
        this.addView(dialogView, this.mButtonsView = performCreateButtonsView(mOptions.getButtonsType(), inflater,
                container, savedInstanceState));

        // Check valid body view.
        if (mBodyView == null)
            throw new IllegalStateException("Missing body view. Dialog must have at least body view.");
    }

    /**
     * Builds dialog view as relative layout. This adds the base dialog views
     * (title, body, buttons) in correct order into dialog view. Adding views
     * into relative layout is a little bit more complicated as into linear
     * layout so we need to create some layout parameters and use vies
     * identifiers to place them correctly.
     */
    private void buildAsRelativeLayout(View dialogView, LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        this.mTitleView = performCreateTitleView(inflater, container, savedInstanceState);
        this.mButtonsView = performCreateButtonsView(mOptions.getButtonsType(), inflater, container,
                savedInstanceState);
        this.mBodyView = performCreateBodyView(inflater, container, savedInstanceState);

        // Check valid body view.
        if (mBodyView == null)
            throw new IllegalStateException("Missing body view. Dialog must have at least body view.");

        // Check if the view has the id to identify it in relative layout
        // hierarchy.
        if (mTitleView != null && mTitleView.getId() == View.NO_ID) {
            mTitleView.setId(TITLE_VIEW_DEFAULT_ID);
        }
        if (mBodyView.getId() == View.NO_ID) {
            mBodyView.setId(BODY_VIEW_DEFAULT_ID);
        }
        if (mButtonsView != null && mButtonsView.getId() == View.NO_ID) {
            mButtonsView.setId(BUTTONS_VIEW_DEFAULT_ID);
        }

        // Correct layout parameters.
        performCorrectLayout(DialogLayoutCorrection.WITH_TITLE_AND_BUTTONS, dialogView);

        // Build dialog view.
        this.addView(dialogView, mTitleView);
        this.addView(dialogView, mButtonsView);
        this.addView(dialogView, mBodyView);
    }

    /**
     * Creates new dialog options from the saved bundle or dialog arguments.
     *
     * @param arguments Dialog arguments.
     */
    private void createOptions(Bundle arguments) {
        // Check valid arguments.
        if (arguments == null)
            return;

        // Restore data.
        if (arguments.getParcelable(BUNDLE_OPTIONS) != null) {
            // Dialog options object implements parcelable so we can just
            // restore it as it was saved in the bundle.
            this.mOptions = arguments.getParcelable(BUNDLE_OPTIONS);
        }
    }

    /**
     * Fills the given bundle with the actual dialog options data to save them
     * because of later usage to recreate them after it was this dialog
     * destroyed (after orientation change).
     *
     * @param bundle The bundle to fill with dialog options.
     */
    private void fillBundleWithOptions(Bundle bundle) {
        fillBundleWithOptions(bundle, this.mOptions);
    }

    /**
     * Performs dialog binding.
     *
     * @param savedInstanceState Saved dialog instance state.
     */
    private void performBindDialog(Bundle savedInstanceState) {
        // Bind dialog buttons and set its listeners.
        performSetUpButtons();

        // Bind with content.
        onBindDialog(mDialogView, savedInstanceState);

        // Save state.
        this.bViewBinded = true;
    }

    /**
     * Performs initialization of title view.
     */
    private View performCreateTitleView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return onCreateTitleView(inflater, container, savedInstanceState);
    }

    /**
     * Performs initialization of body view.
     */
    private View performCreateBodyView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return onCreateBodyView(inflater, container, savedInstanceState);
    }

    /**
     * Performs initialization of buttons view.
     */
    private View performCreateButtonsView(Dialog.Buttons buttonsType, LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return onCreateButtonsView(buttonsType, inflater, container, savedInstanceState);
    }

    /**
     * Performs restoring of dialog saved state.
     *
     * @param savedState Dialog saved state.
     */
    private void performRestoreInstanceState(Bundle savedState) {
        this.bCalled = false;
        onRestoreInstanceState(savedState);
        if (!bCalled) {
            throw new IllegalStateException(
                    "DialogFragment " + this + " did not call trough to super.onRestoreInstanceState()");
        }
    }

    /**
     * Performs correction of dialog layout.
     *
     * @param correction Requested correction.
     * @param dialogView Current dialog view.
     */
    private void performCorrectLayout(DialogLayoutCorrection correction, View dialogView) {
        this.bCalled = false;
        onCorrectLayout(correction, dialogView);
        if (!bCalled) {
            throw new IllegalStateException(
                    "DialogFragment " + this + " did not call trough to super.onCorrectLayout()");
        }
    }

    /**
     * Abstract methods ----------------------
     */

    /**
     * <h5><i>protected View onCreateTitleView(LayoutInflater inflater,
     * ViewGroup container, Bundle savedInstanceState)</i></h5>
     * <p>
     * Invoked to create title view. Created view should contain only views specific for dialog title.
     * </p>
     * <p>
     * <b>Note: </b>This method is called only if the inflated main dialog view
     * doesn't contain any views.
     * </p>
     *
     * @param inflater           Valid layout inflater.
     * @param container          Inflated dialog main layout.
     * @param savedInstanceState Saved dialog instance state. May be <code>null</code>.
     * @return Inflated dialog title view.
     */
    protected abstract View onCreateTitleView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState);

    /**
     * <h5><i>protected View onCreateBodyView(LayoutInflater inflater, ViewGroup
     * container, Bundle savedInstanceState)</i></h5>
     * <p>
     * Invoked to create body view. Created view should contain only views specific for dialog body, like
     * just simple {@link android.widget.TextView} or more complex layout.
     * </p>
     * <p>
     * <b>Note: </b>This method is called only if the inflated main dialog view
     * doesn't contain any views.
     * </p>
     *
     * @param inflater           Valid layout inflater.
     * @param container          Inflated dialog main layout.
     * @param savedInstanceState Saved dialog instance state. May be <code>null</code>.
     * @return Inflated dialog body view.
     */
    protected abstract View onCreateBodyView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState);

    /**
     * <h5><i>protected View onCreateButtonsView(Buttons buttonsType,
     * LayoutInflater inflater, ViewGroup container, Bundle
     * savedInstanceState)</i></h5>
     * <p>
     * Invoked to create buttons view. Created view should contain only views specific for dialog title like
     * some buttons with dividers.
     * </p>
     * <p>
     * <b>Note: </b>This method is called only if the inflated main dialog view
     * doesn't contain any views.
     * </p>
     *
     * @param buttonsType        Type of buttons to show in dialog.
     * @param inflater           Valid layout inflater.
     * @param container          Inflated dialog main layout.
     * @param savedInstanceState Saved dialog instance state. May be <code>null</code>.
     * @return Inflated dialog buttons view.
     */
    protected abstract View onCreateButtonsView(Dialog.Buttons buttonsType, LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState);

    /**
     * <p>
     * Invoked to initialize dialog views.
     * </p>
     *
     * @param dialogView Inflated dialog view.
     */
    protected abstract void onInitViews(View dialogView);

    /**
     * <p>
     * Invoked to set up buttons. Dialog listeners should be assigned to buttons click here.
     * </p>
     *
     * @param dialogView Inflated dialog view.
     */
    protected abstract void onSetUpButtons(View dialogView);

    /**
     * <h5><i>protected void onBindDialog(View dialogView, Bundle
     * savedInstanceState)</i></h5>
     * <p>
     * Invoked to bind dialog view with data from dialog options.
     * </p>
     *
     * @param dialogView         Inflated dialog view.
     * @param savedInstanceState Saved instance state.
     * @see #getOptions()
     */
    protected abstract void onBindDialog(View dialogView, Bundle savedInstanceState);

    /**
     * Invoked to apply style to dialog view. Note, that here passed typed array
     * will be automatically recycled after successful calls of this method inside
     * all derived classes, so don't recycle it.
     * </p>
     *
     * @param dialogView  Inflated dialog view.
     * @param parsedArray Parsed dialog style typed array. Can be immediately used.
     */
    protected abstract void onStyleDialog(View dialogView, TypedArray parsedArray);

    /**
     * Inner classes =========================
     */

    /**
     * Interface =============================
     */
}