/* This file is part of the KDE libraries
   Copyright (C) 2000 Ronny Standtke <Ronny.Standtke@gmx.de>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "ksqueezedtextlabel.h"
#include <kdebug.h>
#include <klocale.h>
#include <QtGui/qevent.h>
#include <kaction.h>
#include <QMenu>
#include <QClipboard>
#include <QApplication>
#include <QMimeData>
#include <QTextDocument>
#include <kglobalsettings.h>

class KSqueezedTextLabelPrivate
{
public:

    void _k_copyFullText() {
        QApplication::clipboard()->setText(fullText);
    }

    QString fullText;
    Qt::TextElideMode elideMode;
};

KSqueezedTextLabel::KSqueezedTextLabel(const QString &text , QWidget *parent)
 : QLabel (parent),
  d(new KSqueezedTextLabelPrivate)
{
  setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
  d->fullText = text;
  d->elideMode = Qt::ElideMiddle;
  squeezeTextToLabel();
}

KSqueezedTextLabel::KSqueezedTextLabel(QWidget *parent)
 : QLabel (parent),
  d(new KSqueezedTextLabelPrivate)
{
  setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
  d->elideMode = Qt::ElideMiddle;
}

KSqueezedTextLabel::~KSqueezedTextLabel()
{
  delete d;
}

void KSqueezedTextLabel::resizeEvent(QResizeEvent *)
{
  squeezeTextToLabel();
}

QSize KSqueezedTextLabel::minimumSizeHint() const
{
  QSize sh = QLabel::minimumSizeHint();
  sh.setWidth(-1);
  return sh;
}

QSize KSqueezedTextLabel::sizeHint() const
{
  int maxWidth = KGlobalSettings::desktopGeometry(this).width() * 3 / 4;
  QFontMetrics fm(fontMetrics());
  int textWidth = fm.width(d->fullText);
  if (textWidth > maxWidth) {
    textWidth = maxWidth;
  }
  return QSize(textWidth, QLabel::sizeHint().height());
}

void KSqueezedTextLabel::setText(const QString &text)
{
  d->fullText = text;
  squeezeTextToLabel();
}

void KSqueezedTextLabel::clear()
{
  d->fullText.clear();
  QLabel::clear();
}

void KSqueezedTextLabel::squeezeTextToLabel()
{
  QFontMetrics fm(fontMetrics());
  int labelWidth = size().width();
  QStringList squeezedLines;
  bool squeezed = false;
  Q_FOREACH(const QString& line, d->fullText.split('\n')) {
    int lineWidth = fm.width(line);
    if (lineWidth > labelWidth) {
      squeezed = true;
      squeezedLines << fm.elidedText(line, d->elideMode, labelWidth);
    } else {
      squeezedLines << line;
    }
  }

  if (squeezed) {
    QLabel::setText(squeezedLines.join("\n"));
    setToolTip(d->fullText);
  } else {
    QLabel::setText(d->fullText);
    setToolTip(QString());
  }
}

void KSqueezedTextLabel::setAlignment(Qt::Alignment alignment)
{
  // save fullText and restore it
  QString tmpFull(d->fullText);
  QLabel::setAlignment(alignment);
  d->fullText = tmpFull;
}

Qt::TextElideMode KSqueezedTextLabel::textElideMode() const
{
  return d->elideMode;
}

void KSqueezedTextLabel::setTextElideMode(Qt::TextElideMode mode)
{
  d->elideMode = mode;
  squeezeTextToLabel();
}

QString KSqueezedTextLabel::fullText() const
{
  return d->fullText;
}

void KSqueezedTextLabel::contextMenuEvent(QContextMenuEvent* ev)
{
    // We want to reimplement "Copy" to include the elided text.
    // But this means reimplementing the full popup menu, so no more
    // copy-link-address or copy-selection support anymore, since we
    // have no access to the QTextDocument.
    // Maybe we should have a boolean flag in KSqueezedTextLabel itself for
    // whether to show the "Copy Full Text" custom popup?
    // For now I chose to show it when the text is squeezed; when it's not, the
    // standard popup menu can do the job (select all, copy).

    const bool squeezed = text() != d->fullText;
    const bool showCustomPopup = squeezed;
    if (showCustomPopup) {
        QMenu menu(this);

        KAction* act = new KAction(i18n("&Copy Full Text"), &menu);
        connect(act, SIGNAL(triggered()), this, SLOT(_k_copyFullText()));
        menu.addAction(act);

        ev->accept();
        menu.exec(ev->globalPos());
    } else {
        QLabel::contextMenuEvent(ev);
    }
}

void KSqueezedTextLabel::mouseReleaseEvent(QMouseEvent* ev)
{
    if (QApplication::clipboard()->supportsSelection() &&
        textInteractionFlags() != Qt::NoTextInteraction &&
        ev->button() == Qt::LeftButton &&
        !d->fullText.isEmpty() &&
        hasSelectedText()) {
        // Expand "..." when selecting with the mouse
        QString txt = selectedText();
        const QChar ellipsisChar(0x2026); // from qtextengine.cpp
        const int dotsPos = txt.indexOf(ellipsisChar);
        if (dotsPos > -1) {
            // Ex: abcde...yz, selecting de...y  (selectionStart=3)
            // charsBeforeSelection = selectionStart = 2 (ab)
            // charsAfterSelection = 1 (z)
            // final selection length= 26 - 2 - 1 = 23
            const int start = selectionStart();
            int charsAfterSelection = text().length() - start - selectedText().length();
            txt = d->fullText;
            // Strip markup tags
            if (textFormat() == Qt::RichText
                || (textFormat() == Qt::AutoText && Qt::mightBeRichText(txt))) {
                txt.replace(QRegExp("<[^>]*>"), "");
                // account for stripped characters
                charsAfterSelection -= d->fullText.length() - txt.length();
            }
            txt = txt.mid(selectionStart(), txt.length() - start - charsAfterSelection);
        }
        QApplication::clipboard()->setText(txt, QClipboard::Selection);
    } else
    {
        QLabel::mouseReleaseEvent(ev);
    }
}

#include "moc_ksqueezedtextlabel.cpp"
