~ubuntu-branches/ubuntu/vivid/kate/vivid-updates

« back to all changes in this revision

Viewing changes to part/completion/expandingtree/expandingdelegate.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-12-04 16:49:41 UTC
  • mfrom: (1.6.6)
  • Revision ID: package-import@ubuntu.com-20141204164941-l3qbvsly83hhlw2v
Tags: 4:14.11.97-0ubuntu1
* New upstream release
* Update build-deps and use pkg-kde v3 for Qt 5 build
* kate-data now kate5-data for co-installability

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  This file is part of the KDE libraries and the Kate part.
2
 
 *
3
 
 *  Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
4
 
 *
5
 
 *  This library is free software; you can redistribute it and/or
6
 
 *  modify it under the terms of the GNU Library General Public
7
 
 *  License as published by the Free Software Foundation; either
8
 
 *  version 2 of the License, or (at your option) any later version.
9
 
 *
10
 
 *  This library is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 *  Library General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU Library General Public License
16
 
 *  along with this library; see the file COPYING.LIB.  If not, write to
17
 
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
 
 *  Boston, MA 02110-1301, USA.
19
 
 */
20
 
 
21
 
#include "expandingdelegate.h"
22
 
 
23
 
#include <QtGui/QTextLine>
24
 
#include <QtGui/QPainter>
25
 
#include <QtGui/QBrush>
26
 
#include <QKeyEvent>
27
 
#include <QTreeView>
28
 
#include <QApplication>
29
 
 
30
 
#include <kdebug.h>
31
 
 
32
 
#include "expandingwidgetmodel.h"
33
 
 
34
 
ExpandingDelegate::ExpandingDelegate(ExpandingWidgetModel* model, QObject* parent)
35
 
  : QItemDelegate(parent)
36
 
  , m_model(model)
37
 
{
38
 
}
39
 
 
40
 
//Gets the background-color in the way QItemDelegate does it
41
 
static QColor getUsedBackgroundColor(const QStyleOptionViewItem & option, const QModelIndex& index) {
42
 
if (option.showDecorationSelected && (option.state & QStyle::State_Selected)) {
43
 
        QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
44
 
                                  ? QPalette::Normal : QPalette::Disabled;
45
 
        if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
46
 
            cg = QPalette::Inactive;
47
 
 
48
 
        return option.palette.brush(cg, QPalette::Highlight).color();
49
 
    } else {
50
 
        QVariant value = index.data(Qt::BackgroundRole);
51
 
        if (qVariantCanConvert<QBrush>(value))
52
 
            return qvariant_cast<QBrush>(value).color();
53
 
    }
54
 
    
55
 
    return QApplication::palette().base().color();
56
 
}
57
 
 
58
 
static void dampColors(QColor& col) {
59
 
  //Reduce the colors that are less visible to the eye, because they are closer to black when it comes to contrast
60
 
  //The most significant color to the eye is green. Then comes red, and then blue, with blue _much_ less significant.
61
 
  
62
 
  col.setBlue(0);
63
 
  col.setRed(col.red() / 2);
64
 
}
65
 
 
66
 
//A hack to compute more eye-focused contrast values
67
 
static double readabilityContrast(QColor foreground, QColor background) {
68
 
  dampColors(foreground);
69
 
  dampColors(background);
70
 
  return abs(foreground.green()-background.green()) + abs(foreground.red()-background.red()) + abs(foreground.blue() - background.blue());
71
 
}
72
 
 
73
 
void ExpandingDelegate::paint( QPainter * painter, const QStyleOptionViewItem & optionOld, const QModelIndex & index ) const
74
 
{
75
 
  QStyleOptionViewItem option(optionOld);
76
 
 
77
 
  m_currentIndex = index;
78
 
  
79
 
  adjustStyle(index, option);
80
 
    
81
 
  if( index.column() == 0 )
82
 
    model()->placeExpandingWidget(index);
83
 
 
84
 
  //Make sure the decorations are painted at the top, because the center of expanded items will be filled with the embedded widget.
85
 
  if( model()->isPartiallyExpanded(index) == ExpandingWidgetModel::ExpandUpwards )
86
 
    m_cachedAlignment = Qt::AlignBottom;
87
 
  else
88
 
    m_cachedAlignment = Qt::AlignTop;
89
 
  
90
 
  option.decorationAlignment = m_cachedAlignment;
91
 
  option.displayAlignment = m_cachedAlignment;
92
 
  
93
 
  //kDebug( 13035 ) << "Painting row " << index.row() << ", column " << index.column() << ", internal " << index.internalPointer() << ", drawselected " << option.showDecorationSelected << ", selected " << (option.state & QStyle::State_Selected);
94
 
 
95
 
  m_cachedHighlights.clear();
96
 
  m_backgroundColor = getUsedBackgroundColor(option, index);
97
 
 
98
 
  if (model()->indexIsItem(index) ) {
99
 
    m_currentColumnStart = 0;
100
 
    m_cachedHighlights = createHighlighting(index, option);
101
 
  }
102
 
 
103
 
  /*kDebug( 13035 ) << "Highlights for line:";
104
 
  foreach (const QTextLayout::FormatRange& fr, m_cachedHighlights)
105
 
    kDebug( 13035 ) << fr.start << " len " << fr.length << " format ";*/
106
 
 
107
 
  QItemDelegate::paint(painter, option, index);
108
 
 
109
 
  ///This is a bug workaround for the Qt raster paint engine: It paints over widgets embedded into the viewport when updating due to mouse events
110
 
  ///@todo report to Qt Software
111
 
  if( model()->isExpanded(index) && model()->expandingWidget( index ) )
112
 
    model()->expandingWidget( index )->update();
113
 
}
114
 
 
115
 
QList<QTextLayout::FormatRange> ExpandingDelegate::createHighlighting(const QModelIndex& index, QStyleOptionViewItem& option) const {
116
 
  Q_UNUSED( index );
117
 
  Q_UNUSED( option );
118
 
  return QList<QTextLayout::FormatRange>();
119
 
}
120
 
 
121
 
QSize ExpandingDelegate::basicSizeHint( const QModelIndex& index ) const {
122
 
  return QItemDelegate::sizeHint( QStyleOptionViewItem(), index );
123
 
}
124
 
 
125
 
QSize ExpandingDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
126
 
{
127
 
  QSize s = QItemDelegate::sizeHint( option, index );
128
 
  if( model()->isExpanded(index) && model()->expandingWidget( index ) )
129
 
  {
130
 
    QWidget* widget = model()->expandingWidget( index );
131
 
    QSize widgetSize = widget->size();
132
 
 
133
 
    s.setHeight( widgetSize.height() + s.height() + 10 ); //10 is the sum that must match exactly the offsets used in ExpandingWidgetModel::placeExpandingWidgets
134
 
  } else if( model()->isPartiallyExpanded( index ) ) {
135
 
    s.setHeight( s.height() + 30 + 10 );
136
 
  }
137
 
  return s;
138
 
}
139
 
 
140
 
void ExpandingDelegate::adjustStyle( const QModelIndex& index, QStyleOptionViewItem & option ) const
141
 
{
142
 
    Q_UNUSED(index)
143
 
    Q_UNUSED(option)
144
 
}
145
 
 
146
 
void ExpandingDelegate::adjustRect(QRect& rect) const {
147
 
  if (!model()->indexIsItem(m_currentIndex) /*&& m_currentIndex.column() == 0*/) {
148
 
    
149
 
    rect.setLeft(model()->treeView()->columnViewportPosition(0));
150
 
    int columnCount = model()->columnCount(m_currentIndex.parent());
151
 
    
152
 
    if(!columnCount)
153
 
      return;
154
 
    rect.setRight(model()->treeView()->columnViewportPosition(columnCount-1) + model()->treeView()->columnWidth(columnCount-1));
155
 
  }
156
 
}
157
 
 
158
 
void ExpandingDelegate::drawDisplay( QPainter * painter, const QStyleOptionViewItem & option, const QRect & _rect, const QString & text ) const
159
 
{
160
 
  QRect rect(_rect);
161
 
 
162
 
  adjustRect(rect);
163
 
 
164
 
  QTextLayout layout(text, option.font, painter->device());
165
 
 
166
 
  QList<QTextLayout::FormatRange> additionalFormats;
167
 
 
168
 
  int missingFormats = text.length();
169
 
  
170
 
  for (int i = 0; i < m_cachedHighlights.count(); ++i) {
171
 
    if (m_cachedHighlights[i].start + m_cachedHighlights[i].length <= m_currentColumnStart)
172
 
      continue;
173
 
 
174
 
    if (!additionalFormats.count())
175
 
      if (i != 0 && m_cachedHighlights[i - 1].start + m_cachedHighlights[i - 1].length > m_currentColumnStart) {
176
 
        QTextLayout::FormatRange before;
177
 
        before.start = 0;
178
 
        before.length = m_cachedHighlights[i - 1].start + m_cachedHighlights[i - 1].length - m_currentColumnStart;
179
 
        before.format = m_cachedHighlights[i - 1].format;
180
 
        additionalFormats.append(before);
181
 
      }
182
 
 
183
 
      
184
 
    QTextLayout::FormatRange format;
185
 
    format.start = m_cachedHighlights[i].start - m_currentColumnStart;
186
 
    format.length = m_cachedHighlights[i].length;
187
 
    format.format = m_cachedHighlights[i].format;
188
 
 
189
 
    additionalFormats.append(format);
190
 
  }
191
 
  if(!additionalFormats.isEmpty())
192
 
    missingFormats = text.length() - (additionalFormats.back().length + additionalFormats.back().start);
193
 
 
194
 
  if (missingFormats > 0) {
195
 
    QTextLayout::FormatRange format;
196
 
    format.start = text.length() - missingFormats;
197
 
    format.length = missingFormats;
198
 
    QTextCharFormat fm;
199
 
    fm.setForeground(option.palette.text());
200
 
    format.format = fm;
201
 
    additionalFormats.append(format);
202
 
  }
203
 
  
204
 
  if(m_backgroundColor.isValid()) {
205
 
    QColor background = m_backgroundColor;
206
 
//     kDebug() << text << "background:" << background.name();
207
 
    //Now go through the formats, and make sure the contrast background/foreground is readable
208
 
    for(int a = 0; a < additionalFormats.size(); ++a) {
209
 
      QColor currentBackground = background;
210
 
      if(additionalFormats[a].format.hasProperty(QTextFormat::BackgroundBrush))
211
 
               currentBackground = additionalFormats[a].format.background().color();
212
 
      
213
 
      QColor currentColor = additionalFormats[a].format.foreground().color();
214
 
      
215
 
      double currentContrast = readabilityContrast(currentColor, currentBackground);
216
 
      QColor invertedColor(0xffffffff-additionalFormats[a].format.foreground().color().rgb());
217
 
      double invertedContrast = readabilityContrast(invertedColor, currentBackground);
218
 
      
219
 
//       kDebug() << "values:" << invertedContrast << currentContrast << invertedColor.name() << currentColor.name();
220
 
      
221
 
      if(invertedContrast > currentContrast) {
222
 
//         kDebug() << text << additionalFormats[a].length << "switching from" << currentColor.name() << "to" << invertedColor.name();
223
 
        QBrush b(additionalFormats[a].format.foreground());
224
 
        b.setColor(invertedColor);
225
 
        additionalFormats[a].format.setForeground(b);
226
 
      }
227
 
    }
228
 
  }
229
 
  
230
 
  for(int a = additionalFormats.size()-1; a >= 0; --a) {
231
 
      if(additionalFormats[a].length == 0){
232
 
          additionalFormats.removeAt(a);
233
 
      }else{
234
 
          ///For some reason the text-formats seem to be invalid in some way, sometimes
235
 
          ///@todo Fix this properly, it sucks not copying everything over
236
 
          QTextCharFormat fm;
237
 
          fm.setForeground(QBrush(additionalFormats[a].format.foreground().color()));
238
 
          fm.setBackground(additionalFormats[a].format.background());
239
 
          fm.setUnderlineStyle( additionalFormats[a].format.underlineStyle() );
240
 
          fm.setUnderlineColor( additionalFormats[a].format.underlineColor() );
241
 
          fm.setFontWeight( additionalFormats[a].format.fontWeight() );
242
 
          additionalFormats[a].format = fm;
243
 
      }
244
 
  }
245
 
 
246
 
//   kDebug( 13035 ) << "Highlights for text [" << text << "] col start " << m_currentColumnStart << ":";
247
 
//   foreach (const QTextLayout::FormatRange& fr, additionalFormats)
248
 
//     kDebug( 13035 ) << fr.start << " len " << fr.length << "foreground" << fr.format.foreground() << "background" << fr.format.background();
249
 
 
250
 
  layout.setAdditionalFormats(additionalFormats);
251
 
 
252
 
  QTextOption to;
253
 
  
254
 
  to.setAlignment( static_cast<Qt::Alignment>(m_cachedAlignment | option.displayAlignment) );
255
 
  
256
 
  to.setWrapMode(QTextOption::WrapAnywhere);
257
 
  layout.setTextOption(to);
258
 
 
259
 
  layout.beginLayout();
260
 
  QTextLine line = layout.createLine();
261
 
  // Leave some extra space when the text is right-aligned
262
 
  line.setLineWidth(rect.width() - (option.displayAlignment == Qt::AlignRight ? 8 : 0));
263
 
  layout.endLayout();
264
 
 
265
 
  //We need to do some hand layouting here
266
 
  if( to.alignment() & Qt::AlignBottom)
267
 
      layout.draw(painter, QPoint(rect.left(), rect.bottom() - (int)line.height()) );
268
 
  else
269
 
      layout.draw(painter, rect.topLeft() );
270
 
  
271
 
  return;
272
 
 
273
 
  //if (painter->fontMetrics().width(text) > textRect.width() && !text.contains(QLatin1Char('\n')))
274
 
      //str = elidedText(option.fontMetrics, textRect.width(), option.textElideMode, text);
275
 
  //qt_format_text(option.font, textRect, option.displayAlignment, str, 0, 0, 0, 0, painter);
276
 
}
277
 
 
278
 
void ExpandingDelegate::drawDecoration(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QPixmap& pixmap) const {
279
 
  if (model()->indexIsItem(m_currentIndex) )
280
 
    QItemDelegate::drawDecoration(painter, option, rect, pixmap);
281
 
}
282
 
 
283
 
void ExpandingDelegate::drawBackground ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
284
 
    Q_UNUSED(index)
285
 
    QStyleOptionViewItemV4 opt = option;
286
 
    //initStyleOption(&opt, index);
287
 
    //Problem: This isn't called at all, because drawBrackground is not virtual :-/
288
 
    QStyle *style = model()->treeView()->style() ? model()->treeView()->style() : QApplication::style();
289
 
    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
290
 
}
291
 
 
292
 
ExpandingWidgetModel* ExpandingDelegate::model() const {
293
 
  return m_model;
294
 
}
295
 
 
296
 
void ExpandingDelegate::heightChanged() const {
297
 
}
298
 
 
299
 
bool ExpandingDelegate::editorEvent ( QEvent * event, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & index )
300
 
{
301
 
  if( event->type() == QEvent::MouseButtonRelease )
302
 
  {
303
 
    event->accept();
304
 
    model()->setExpanded(index, !model()->isExpanded( index ));
305
 
    heightChanged();
306
 
 
307
 
    return true;
308
 
  } else {
309
 
    event->ignore();
310
 
  }
311
 
  
312
 
  return false;
313
 
}
314
 
 
315
 
QList<QTextLayout::FormatRange> ExpandingDelegate::highlightingFromVariantList(const QList<QVariant>& customHighlights) const
316
 
{
317
 
    QList<QTextLayout::FormatRange> ret;
318
 
 
319
 
    for (int i = 0; i + 2 < customHighlights.count(); i += 3) {
320
 
      if (!customHighlights[i].canConvert(QVariant::Int) || !customHighlights[i+1].canConvert(QVariant::Int) || !customHighlights[i+2].canConvert<QTextFormat>()) {
321
 
        kWarning() << "Unable to convert triple to custom formatting.";
322
 
        continue;
323
 
      }
324
 
 
325
 
      QTextLayout::FormatRange format;
326
 
      format.start = customHighlights[i].toInt();
327
 
      format.length = customHighlights[i+1].toInt();
328
 
      format.format = customHighlights[i+2].value<QTextFormat>().toCharFormat();
329
 
 
330
 
      if(!format.format.isValid())
331
 
        kWarning() << "Format is not valid";
332
 
 
333
 
      ret << format;
334
 
    }
335
 
    return ret;
336
 
}
337
 
 
338
 
#include "expandingdelegate.moc"