/***************************************************************************
                          inlineeditlabel.cpp  -  description
                             -------------------
    begin                : Tue Dec 29 2009
    copyright            : (C) 2009 by Valerio Pilo
    email                : valerio@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it 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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "inlineeditlabel.h"

#include "utils/kmessshared.h"
#include "kmessdebug.h"

#include <QKeyEvent>
#include <QToolTip>



/**
 * Constructor
 *
 * @param parent Parent widget
 */
InlineEditLabel::InlineEditLabel( QWidget *parent )
: QWidget( parent )
, Ui::InlineEditLabel()
, maxLength_( 0 )
, mode_( STRING_FORMATTED )
{
  setupUi( this );

  enableEditMode( false );

  // We need to handle some events in a custom way
  installEventFilter( this );
  label_->installEventFilter( this );
  lineEdit_->installEventFilter( this );
}



/**
 * The destructor
 */
InlineEditLabel::~InlineEditLabel()
{
}



/**
 * Switch the widget to the label or the lineedit.
 *
 * @param editMode If true, enable editing the label's text. If false, show the label.
 */
void InlineEditLabel::enableEditMode( bool editMode )
{
  if( editMode )
  {
    // Check if we are already editing
    if( label_->isHidden() )
    {
      return;
    }

    label_->hide();
    lineEdit_->show();
    lineEdit_->setFocus();
  }
  else
  {
    // Check if we are already showing the label
    if( label_->isVisible() )
    {
      return;
    }

    label_->show();
    lineEdit_->hide();

    // Update the label from the line edit text
    const QString &text( lineEdit_->text() );

    // Do nothing when there are no changes to avoid unneeded updates
    if( text == text_.getOriginal() )
    {
      return;
    }

    text_ = text;

    label_->setText( text_.getString( mode_ ) );

    emit changed();
  }
}



/**
 * The label or the lineedit received an event.
 *
 * @param obj Source object of the event
 * @param event Event to handle
 * @return bool Whether or not to continue processing the event.
 */
bool InlineEditLabel::eventFilter( QObject *obj, QEvent *event )
{
  Q_UNUSED( obj );

  QEvent::Type eventType = event->type();

  if( eventType == QEvent::KeyRelease )
  {
    int key = static_cast<QKeyEvent*>( event )->key();

    // Confirm editing on enter key press
    if( key == Qt::Key_Return )
    {
      enableEditMode( false );
    }
    // Cancel editing on esc key press
    else if( key == Qt::Key_Escape )
    {
      // Restore the original text to avoid signaling any change
      lineEdit_->setText( text_.getOriginal() );
      enableEditMode( false );
    }
    else if( maxLength_ > 0 )
    {
      // Check that the size in bytes of the string is within the set limit
      const QString &text( lineEdit_->text() );
      const QByteArray &stringData( text.toUtf8() );
      if( stringData.length() > maxLength_ )
      {
        lineEdit_->setText( KMessShared::fixStringToByteSize( text, maxLength_ ) );
        QToolTip::showText( lineEdit_->mapToGlobal( lineEdit_->rect().bottomLeft() ),
                          i18n( "The text cannot be longer than %1 characters.", maxLength_ ),
                          lineEdit_ );
        return true;
      }
    }

    return true;
  }

  if( eventType == QEvent::MouseButtonRelease && ! hasFocus() )
  {
    // We were clicked
    enableEditMode( true );
  }
  else if( eventType == QEvent::FocusOut || eventType == QEvent::NonClientAreaMouseButtonPress )
  {
    // We lost focus
    enableEditMode( false );
  }

  return false; // don't stop processing.
}



/**
 * Change the text formatting mode for the label.
 *
 * @param mode The new formatting mode
 * @see RichTextEditor and FormattedString
 */
void InlineEditLabel::setFormattingMode( FormattingMode mode )
{
  mode_ = mode;
}



/**
 * Limit the amount of text which can be input.
 *
 * @param length New maximum length in bytes for the field.
 */
void InlineEditLabel::setMaxLength( int length )
{
  maxLength_ = length;
}



/**
 * Set the text to show.
 *
 * @param text The text to set
 * @param labelOnly If true, the text will only be set to the label,
 *                  and the lineedit will be empty
 */
void InlineEditLabel::setText( const QString &text, bool labelOnly )
{
  if( labelOnly )
  {
    text_ = QString();
    label_->setText( FormattedString( text ).getString( mode_ ) );
    lineEdit_->setText( QString() );
  }
  else
  {
    text_ = text;
    label_->setText( text_.getString( mode_ ) );
    lineEdit_->setText( text_.getOriginal() );
  }
}



/**
 * Retrieve the current text.
 *
 * @return QString
 */
const QString &InlineEditLabel::text()
{
  return text_.getOriginal();
}



#include "inlineeditlabel.moc"
