/*
 * Copyright (c) 2004 Nokia. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of Nokia nor the names of its contributors may be
 * used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>

#include "KWQLineEdit.h"
#include "KWQLogging.h"
//#include "KWQTextField.h"

#define LINE_EDIT_HEIGHT_PADDING 3


extern "C" {

static 
void changed(GtkEditable *widget, gpointer data)
{
    QLineEdit* edit = static_cast<QLineEdit*>(data);
    edit->setEdited(true);
    edit->textChanged();
}


static 
gboolean button_press_release_event(GtkWidget *widget, GdkEventButton *event,  gpointer data)
{
    // to get the real button clicked event, need to track event in && event out, 
    // then track button press + release etc.. look at gtkbutton.c in gtk+-2...

    QLineEdit* edit = static_cast<QLineEdit*>(data);
    switch (event->type) {
    case GDK_BUTTON_PRESS:
	edit->buttonPress();
	break;
    case GDK_BUTTON_RELEASE:
	edit->buttonRelease();	
	break;
    default:
	break;
    }
    return FALSE;
}

static 
gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
    QLineEdit* edit = static_cast<QLineEdit*>(data);

    if (event->keyval == GDK_Return)
	edit->returnPressed();
    
    return FALSE;	
}
}

QLineEdit::QLineEdit(Type type, QWidget * parent, const char * name, int f)
    : QWidget(parent,name,f)
    , m_returnPressed(this, SIGNAL(returnPressed()))
    , m_textChanged(this, SIGNAL(textChanged(const QString &)))
    , m_clicked(this, SIGNAL(clicked()))
    , m_performSearch(this, SIGNAL(performSearch()))
    , m_type(type)
{
    GtkWidget *entry = gtk_entry_new();
    setGtkWidget(entry);
    setEdited(false);

    gint hid;
    hid = g_signal_connect(G_OBJECT(entry),
			    "changed",
			    G_CALLBACK(::changed),
			    this);

    hid = g_signal_connect(G_OBJECT(entry),
			   "button-press-event",
			   G_CALLBACK(::button_press_release_event),
			   this);

    hid = g_signal_connect(G_OBJECT(entry),
			   "button-release-event",
			   G_CALLBACK(::button_press_release_event),
			   this);

    hid = g_signal_connect(G_OBJECT(entry),
			   "key-press-event",
			    G_CALLBACK(::key_press_event),
			   this);

    // hide passwords 
    gtk_entry_set_visibility(GTK_ENTRY(getGtkWidget()), type != Password);
}

QLineEdit::~QLineEdit()
{
    
}
 

void QLineEdit::setCursorPosition(int p)
{
    // Don't do anything here.
    //gtk_editable_set_position(GTK_EDITABLE(getGtkWidget()), p);
}

int QLineEdit::cursorPosition() const
{
    // Not needed.  We ignore setCursorPosition()
    //return gtk_editable_get_position(GTK_EDITABLE(getGtkWidget()));
    return 0;
}

void QLineEdit::setFont(const QFont &font)
{
    QWidget::setFont(font);
}

void QLineEdit::setText(const QString &s)
{
    GtkWidget *w = getGtkWidget();
    QCString str = s.utf8();
    gtk_entry_set_text(GTK_ENTRY (w), static_cast<const char*>(str));
    setEdited(false);
}

QString QLineEdit::text()
{
    GtkWidget *w = getGtkWidget();

    return QString::fromUtf8(gtk_entry_get_text(GTK_ENTRY (w)));
}

void QLineEdit::setMaxLength(int len)
{
    GtkWidget *w = getGtkWidget();
    gtk_entry_set_max_length(GTK_ENTRY (w), len);
}

bool QLineEdit::isReadOnly() const
{
    GtkWidget *w = getGtkWidget();
    return !gtk_editable_get_editable(GTK_EDITABLE (w));
}

void QLineEdit::setReadOnly(bool flag)
{
    GtkWidget *w = getGtkWidget();
    gtk_editable_set_editable(GTK_EDITABLE (w), !flag);
}

int QLineEdit::maxLength() const
{
    GtkWidget *w = getGtkWidget();
    return gtk_entry_get_max_length(GTK_ENTRY (w));
}

void QLineEdit::selectAll()
{
    GtkWidget *w = getGtkWidget();
    gtk_editable_select_region(GTK_EDITABLE (w), 0, -1);
}

bool QLineEdit::edited() const
{
    return m_edited;
}

void QLineEdit::setEdited(bool flag)
{
    m_edited = flag;
}

/**
 *  has side effects: sets the width of chars to the desired value
 *  Qt lacks interface to set  (approximate) size according to how many
 *  characters QLineEdit contains.
 *
 *  this doesn't save old width_chars, set new, set old,
 *  because gtk queues resize on set
 */
QSize QLineEdit::sizeForCharacterWidth(int numCharacters) const
{
    ASSERT(numCharacters > 0);

    GtkWidget *w;
    GtkRequisition req;
    w = getGtkWidget();
    gtk_entry_set_width_chars(GTK_ENTRY (w), numCharacters);
    
    gtk_widget_size_request(w, &req);
    return QSize(req.width, req.height);
}

int QLineEdit::baselinePosition(int height) const
{
    return QWidget::baselinePosition(height);
}

void QLineEdit::clicked()
{
    m_clicked.call();
}

void QLineEdit::setAlignment(AlignmentFlags alignment)
{
#if 0
    KWQ_BLOCK_EXCEPTIONS;

    NSTextField *textField = (NSTextField *)getView();
    [textField setAlignment:KWQNSTextAlignmentForAlignmentFlags(alignment)];

    KWQ_UNBLOCK_EXCEPTIONS;
#endif
}

void QLineEdit::setWritingDirection(QPainter::TextDirection direction)
{
    QWidget::setWritingDirection(direction);
}

QWidget::FocusPolicy QLineEdit::focusPolicy() const
{
    FocusPolicy policy = QWidget::focusPolicy();
    return policy == TabFocus ? StrongFocus : policy;
}

bool QLineEdit::checksDescendantsForFocus() const
{
    return true;
}

#if 0
NSTextAlignment KWQNSTextAlignmentForAlignmentFlags(Qt::AlignmentFlags a)
{
    switch (a) {
        default:
            ERROR("unsupported alignment");
        case Qt::AlignLeft:
            return NSLeftTextAlignment;
        case Qt::AlignRight:
            return NSRightTextAlignment;
        case Qt::AlignHCenter:
            return NSCenterTextAlignment;
    }
}
#endif

void QLineEdit::setLiveSearch(bool liveSearch)
{
    if (m_type != Search)
        return;

    LOG(KwiqLog, "void QLineEdit::setLiveSearch(bool) Not implemented");

//     NSSearchField *searchField = (NSSearchField *)getView();
//     [[searchField cell] setSendsWholeSearchString:!liveSearch];
}

void QLineEdit::setAutoSaveName(const QString& name)
{
    if (m_type != Search)
        return;
    
    LOG(KwiqLog,"void QLineEdit::setAutoSaveName(QString&) Not implemented");

//     QString autosave;
//     if (!name.isEmpty())
//         autosave = "com.apple.WebKit.searchField:" + name;
    
//     NSSearchField *searchField = (NSSearchField *)getView();
//     [searchField setRecentsAutosaveName:autosave.getNSString()];
}

void QLineEdit::setMaxResults(int maxResults)
{
    if (m_type != Search)
        return;

    LOG(KwiqLog,"void QLineEdit::setMaxResults(int) Not implemented");
        
//     NSSearchField *searchField = (NSSearchField *)getView();
//     id searchCell = [searchField cell];
//     if (!maxResults) {
//         [searchCell setSearchButtonCell:nil];
//         [searchCell setSearchMenuTemplate:nil];
//     }
//     else {
//         NSMenu* cellMenu = [searchCell searchMenuTemplate];
//         NSButtonCell* buttonCell = [searchCell searchButtonCell];
//         if (!buttonCell)
//             [searchCell resetSearchButtonCell];
//         if (!cellMenu)
//             [searchCell setSearchMenuTemplate:[[WebCoreViewFactory sharedFactory] cellMenuForSearchField]];
//     }
    
//     [searchCell setMaximumRecents:maxResults];
}

void QLineEdit::setPlaceholderString(const QString& placeholder)
{
    if (m_type != Search)
        return;

    LOG(KwiqLog,"void QLineEdit::setPlaceholderString(QString&) Not implemented");

//     NSSearchField *searchField = (NSSearchField *)getView();
//     [[searchField cell] setPlaceholderString:placeholder.getNSString()];
}

void QLineEdit::addSearchResult()
{
    if (m_type != Search)
        return;

    LOG(KwiqLog,"void QLineEdit::addSearchResult() Not implemented");

//     NSSearchField *searchField = (NSSearchField *)getView();
//     [[searchField cell] _addStringToRecentSearches:[searchField stringValue]];
}

void QLineEdit::buttonPress()
{
    m_pressed = true;
}

void QLineEdit::buttonRelease()
{
    if (m_pressed)
	clicked();
    m_pressed = false;
}
