/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-6 by Raw Material Software ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the
   GNU General Public License, as published by the Free Software Foundation;
   either version 2 of the License, or (at your option) any later version.

   JUCE is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with JUCE; if not, visit www.gnu.org/licenses or write to the
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
   Boston, MA 02111-1307 USA

  ------------------------------------------------------------------------------

   If you'd like to release a closed-source product which uses JUCE, commercial
   licenses are also available: visit www.rawmaterialsoftware.com/juce for
   more information.

  ==============================================================================
*/

#include "../../../../juce_core/basics/juce_StandardHeader.h"

BEGIN_JUCE_NAMESPACE

#include "juce_SimpleListBox.h"
#include "../mouse/juce_DragAndDropContainer.h"
#include "../../graphics/imaging/juce_Image.h"


//==============================================================================
class SimpleListBoxRowComponent  : public Component
{
private:
    SimpleListBox* owner;
    SimpleListBoxModel* model;
    int row;
    bool selected, isDragging, selectRowOnMouseUp;

    SimpleListBoxRowComponent (const SimpleListBoxRowComponent&);
    const SimpleListBoxRowComponent& operator= (const SimpleListBoxRowComponent&);

public:
    SimpleListBoxRowComponent (SimpleListBox* const owner_)
        : owner (owner_),
          isDragging (false)
    {
    }

    ~SimpleListBoxRowComponent()
    {
    }

    void paint (Graphics& g)
    {
        if (owner->model != 0)
            owner->model->paintListBoxItem (row, g, getWidth(), getHeight(), selected);
    }

    void update (int row_, bool selected_)
    {
        row = row_;
        selected = selected_;
        repaint();
    }

    void mouseDown (const MouseEvent& e)
    {
        isDragging = false;
        selectRowOnMouseUp = false;

        if (! selected)
        {
            owner->selectRowsBasedOnModifierKeys (row, e.mods);

            if (owner->model != 0)
                owner->model->listBoxItemClicked (row, e);
        }
        else
        {
            selectRowOnMouseUp = true;
        }
    }

    void mouseUp (const MouseEvent& e)
    {
        if (selectRowOnMouseUp && ! isDragging)
        {
            owner->selectRowsBasedOnModifierKeys (row, e.mods);

            if (owner->model != 0)
                owner->model->listBoxItemClicked (row, e);
        }
    }

    void mouseDoubleClick (const MouseEvent& e)
    {
        if (owner->model != 0)
            owner->model->listBoxItemDoubleClicked (row, e);
    }

    void mouseDrag (const MouseEvent& e)
    {
        if (owner->model != 0 && ! (e.mouseWasClicked() || isDragging))
        {
            const SparseSet<int> selectedRows (owner->getSelectedRows());

            if (selectedRows.size() > 0)
            {
                const String dragDescription (owner->model->getDragSourceDescription (selectedRows));

                if (dragDescription.isNotEmpty())
                {
                    isDragging = true;

                    DragAndDropContainer* const dragContainer
                        = DragAndDropContainer::findParentDragContainerFor (this);

                    if (dragContainer != 0)
                    {
                        Image* dragImage = owner->createSnapshotOfSelectedRows();
                        dragImage->multiplyAllAlphas (0.6f);

                        dragContainer->startDragging (dragDescription, owner, dragImage);
                    }
                    else
                    {
                        // to be able to do a drag-and-drop operation, the listbox needs to
                        // be inside a component which is also a DragAndDropContainer.
                        jassertfalse
                    }
                }
            }
        }
    }
};


//==============================================================================
SimpleListBox::SimpleListBox (const String& name,
                              SimpleListBoxModel* const model_)
    : ListBox (name),
      model (model_)
{
}

SimpleListBox::~SimpleListBox()
{
}

void SimpleListBox::setModel (SimpleListBoxModel* const newModel)
{
    if (model != newModel)
    {
        model = newModel;
        updateContent();
    }
}

Component* SimpleListBox::createRowComponent()
{
    return new SimpleListBoxRowComponent (this);
}

void SimpleListBox::updateRowComponent (Component* comp, int index, bool isHighlighted)
{
    ((SimpleListBoxRowComponent*)comp)->update (index, isHighlighted);
}

int SimpleListBox::getNumRows()
{
    return (model != 0) ? model->getNumRows() : 0;
}

void SimpleListBox::selectedRowsChanged (int row)
{
    if (model != 0)
        model->selectedRowsChanged (row);
}

void SimpleListBox::returnKeyPressed (int row)
{
    if (model != 0)
        model->returnKeyPressed (row);
}

void SimpleListBox::deleteKeyPressed (int row)
{
    if (model != 0)
        model->deleteKeyPressed (row);
}

//==============================================================================
void SimpleListBoxModel::listBoxItemClicked (int, const MouseEvent&)
{
}

void SimpleListBoxModel::listBoxItemDoubleClicked (int, const MouseEvent&)
{
}

void SimpleListBoxModel::selectedRowsChanged (int)
{
}

void SimpleListBoxModel::deleteKeyPressed (int)
{
}

void SimpleListBoxModel::returnKeyPressed (int)
{
}

const String SimpleListBoxModel::getDragSourceDescription (const SparseSet<int>&)
{
    return String::empty;
}


END_JUCE_NAMESPACE
