1 //=============================================================================
2 //
3 //   File : KviTreeWindowList.cpp
4 //   Creation date : Thu Jan 7 1999 03:56:50 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 1999 Szymon Stefanek (pragma at kvirc dot net)
8 //   Copyright (C) 2008 Fabio Bas (ctrlaltca at gmail dot com)
9 //
10 //   This program is FREE software. You can redistribute it and/or
11 //   modify it under the terms of the GNU General Public License
12 //   as published by the Free Software Foundation; either version 2
13 //   of the License, or (at your option) any later version.
14 //
15 //   This program is distributed in the HOPE that it will be USEFUL,
16 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 //   See the GNU General Public License for more details.
19 //
20 //   You should have received a copy of the GNU General Public License
21 //   along with this program. If not, write to the Free Software Foundation,
22 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=============================================================================
25 
26 #include "KviChannelWindow.h"
27 #include "KviConsoleWindow.h"
28 #include "KviDynamicToolTip.h"
29 #include "KviMainWindow.h"
30 #include "KviLocale.h"
31 #include "KviOptions.h"
32 #include "KviWindow.h"
33 #include "KviTreeWindowList.h"
34 #include "KviPixmapUtils.h"
35 #include "KviTrayIcon.h"
36 
37 #include <QHeaderView>
38 #include <QMouseEvent>
39 #include <QWheelEvent>
40 #include <QPainter>
41 #include <QTimer>
42 #include <QScrollBar>
43 #include <QStyleOptionViewItem>
44 #include <QStyle>
45 #include <QMenu>
46 
47 #ifdef COMPILE_PSEUDO_TRANSPARENCY
48 extern QPixmap * g_pShadedChildGlobalDesktopBackground;
49 #endif
50 
51 extern QPixmap * g_pActivityMeterPixmap;
52 
53 // KviTreeWindowListItem
54 
KviTreeWindowListItem(QTreeWidget * par,KviWindow * wnd)55 KviTreeWindowListItem::KviTreeWindowListItem(QTreeWidget * par, KviWindow * wnd)
56     : QTreeWidgetItem(par), KviWindowListItem(wnd)
57 {
58 	applyOptions();
59 	captionChanged();
60 }
61 
KviTreeWindowListItem(KviTreeWindowListItem * par,KviWindow * wnd)62 KviTreeWindowListItem::KviTreeWindowListItem(KviTreeWindowListItem * par, KviWindow * wnd)
63     : QTreeWidgetItem(par), KviWindowListItem(wnd)
64 {
65 	applyOptions();
66 	captionChanged();
67 }
68 
69 KviTreeWindowListItem::~KviTreeWindowListItem()
70     = default;
71 
applyOptions()72 void KviTreeWindowListItem::applyOptions()
73 {
74 	//sort the widget [FIXME: expensive?]
75 	treeWidget()->sortItems(0, ((KviTreeWindowListTreeWidget *)treeWidget())->isReverseSort() ? Qt::DescendingOrder : Qt::AscendingOrder);
76 }
77 
captionChanged()78 void KviTreeWindowListItem::captionChanged()
79 {
80 	QString szText;
81 
82 	switch(m_pWindow->type())
83 	{
84 		case KviWindow::Console:
85 		{
86 			KviWindowListBase::getTextForConsole(szText, (KviConsoleWindow *)m_pWindow);
87 		}
88 		break;
89 		case KviWindow::Channel:
90 		case KviWindow::DeadChannel:
91 			if(KVI_OPTION_BOOL(KviOption_boolShowUserFlagForChannelsInWindowList))
92 				szText = ((KviChannelWindow *)m_pWindow)->nameWithUserFlag();
93 			else
94 				szText = ((KviChannelWindow *)m_pWindow)->target();
95 			break;
96 		case KviWindow::Query:
97 		case KviWindow::DeadQuery:
98 			szText = m_pWindow->windowName();
99 			break;
100 		default:
101 			szText = m_pWindow->plainTextCaption();
102 			break;
103 	}
104 
105 	if(m_pWindow->isMinimized())
106 		szText.prepend('(').append(')');
107 
108 	//sort the widget
109 	treeWidget()->sortItems(0, ((KviTreeWindowListTreeWidget *)treeWidget())->isReverseSort() ? Qt::DescendingOrder : Qt::AscendingOrder);
110 
111 	setData(0, Qt::DisplayRole, szText);
112 }
113 
unhighlight()114 void KviTreeWindowListItem::unhighlight()
115 {
116 	if(m_iHighlightLevel < 1)
117 		return;
118 	m_iHighlightLevel = 0;
119 	setData(0, KVI_TTBID_HIGHLIGHT, m_iHighlightLevel);
120 
121 	if(g_pMainWindow->trayIcon())
122 		g_pMainWindow->trayIcon()->refresh();
123 }
124 
highlight(int iLevel)125 void KviTreeWindowListItem::highlight(int iLevel)
126 {
127 	if(iLevel <= m_iHighlightLevel)
128 		return;
129 	if(treeWidget()->currentItem() == this && g_pMainWindow->isActiveWindow())
130 		return;
131 	m_iHighlightLevel = iLevel;
132 	setData(0, KVI_TTBID_HIGHLIGHT, m_iHighlightLevel);
133 
134 	if(g_pMainWindow->trayIcon())
135 		g_pMainWindow->trayIcon()->refresh();
136 }
137 
setProgress(int progress)138 void KviTreeWindowListItem::setProgress(int progress)
139 {
140 	if(progress == m_iProgress)
141 		return;
142 	m_iProgress = progress;
143 	setData(0, KVI_TTBID_PROGRESS, m_iProgress);
144 }
145 
setActive(bool bActive)146 void KviTreeWindowListItem::setActive(bool bActive)
147 {
148 	if(bActive)
149 	{
150 		unhighlight();
151 		treeWidget()->setCurrentItem(this);
152 		// 		treeWidget()->scrollToItem(this);
153 	}
154 }
155 
key() const156 QString KviTreeWindowListItem::key() const
157 {
158 	// This is the sorting function for KviTreeTaskBarItem
159 	// 1) window type (console, other window..) 2) unique id [to avoid bug #9] 3) windowname (for alphabetical sorting of children)
160 	QString ret;
161 	int iType = m_pWindow->type();
162 
163 	// ensure dead/alive channels and queries stay in the same position
164 	if(iType == KviWindow::DeadChannel)
165 		iType = KviWindow::Channel;
166 	if(iType == KviWindow::DeadQuery)
167 		iType = KviWindow::Query;
168 
169 	if(KVI_OPTION_BOOL(KviOption_boolSortWindowListItemsByName))
170 	{
171 		if(iType == KviWindow::Console)
172 		{
173 			QString szText;
174 			KviWindowListBase::getTextForConsole(szText, (KviConsoleWindow *)m_pWindow);
175 
176 			ret.sprintf("%2d%s", iType, szText.toLower().toUtf8().data());
177 		}
178 		else
179 		{
180 			ret.sprintf("%2d%s", iType, m_pWindow->windowName().toLower().toUtf8().data());
181 		}
182 	}
183 	else
184 	{
185 		if(iType == KviWindow::Console)
186 		{
187 			ret.sprintf("%2d%4u", iType, ((KviConsoleWindow *)m_pWindow)->context() ? ((KviConsoleWindow *)m_pWindow)->context()->id() : 9999);
188 		}
189 		else
190 		{
191 			ret.sprintf("%2d%4d", iType, parent() ? parent()->indexOfChild((QTreeWidgetItem *)this) : 9999);
192 		}
193 	}
194 	return ret;
195 }
196 
197 // KviTreeWindowListTreeWidget
198 
KviTreeWindowListTreeWidget(QWidget * par)199 KviTreeWindowListTreeWidget::KviTreeWindowListTreeWidget(QWidget * par)
200     : QTreeWidget(par)
201 {
202 	setObjectName("tree_windowlist");
203 	bReverseSort = false;
204 	setRootIsDecorated(true);
205 	setSelectionMode(QAbstractItemView::NoSelection);
206 	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
207 	setFont(KVI_OPTION_FONT(KviOption_fontTreeWindowList));
208 	setFocusPolicy(Qt::NoFocus);
209 	setAutoFillBackground(false);
210 	viewport()->setAutoFillBackground(false);
211 	setFrameShape(QFrame::Box);
212 	setFrameStyle(QFrame::Panel | QFrame::Sunken);
213 }
214 
215 KviTreeWindowListTreeWidget::~KviTreeWindowListTreeWidget()
216     = default;
217 
mouseMoveEvent(QMouseEvent *)218 void KviTreeWindowListTreeWidget::mouseMoveEvent(QMouseEvent *)
219 {
220 	// dummy just to avoid bug #581:
221 	//   Clicking on item A and moving the mouse to item B selects item A first and then item B
222 	//   Hovewer item A remains current
223 }
224 
wheelEvent(QWheelEvent * e)225 void KviTreeWindowListTreeWidget::wheelEvent(QWheelEvent * e)
226 {
227 	// Mitigate bug #488:
228 	//   When there is a scroll bar the wheel scrolls up and down
229 	//   When there is no scroll bar the wheel changes selection in the tree
230 
231 	if(KVI_OPTION_BOOL(KviOption_boolWheelScrollsWindowsList))
232 	{
233 		if(e->delta() < 0)
234 			((KviTreeWindowList *)parent())->switchWindow(true, false);
235 		else if(e->delta() > 0)
236 			((KviTreeWindowList *)parent())->switchWindow(false, false);
237 	}
238 	else
239 	{
240 		QScrollBar * pBar = verticalScrollBar();
241 
242 		if(!pBar)
243 			return;
244 		if(!pBar->isVisible())
245 			return;
246 
247 		if(
248 		    ((e->delta() < 0) && (pBar->value() < pBar->maximum())) || ((e->delta() > 0) && (pBar->value() > pBar->minimum())))
249 			QApplication::sendEvent(pBar, e);
250 	}
251 }
252 
mousePressEvent(QMouseEvent * e)253 void KviTreeWindowListTreeWidget::mousePressEvent(QMouseEvent * e)
254 {
255 	KviTreeWindowListItem * it = (KviTreeWindowListItem *)itemAt(e->pos());
256 	if(it)
257 	{
258 		//clicked over an item
259 		KviWindow * wnd = it->kviWindow();
260 		if(e->button() & Qt::LeftButton)
261 		{
262 			if(e->modifiers() & Qt::ShiftModifier)
263 			{
264 				//shitf+left click: close window
265 				wnd->delayedClose();
266 			}
267 			else
268 			{
269 				//left click activate/deactivate window
270 				if(g_pActiveWindow != wnd)
271 					g_pMainWindow->setActiveWindow(wnd);
272 
273 				// let our parent handle clicks on branches, etc
274 				QStyleOption option;
275 				option.initFrom(this);
276 				option.rect = visualItemRect(it);
277 				if(!style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &option, this).contains(e->pos()))
278 					QTreeWidget::mousePressEvent(e);
279 			}
280 		}
281 		else if(e->button() & Qt::RightButton)
282 		{
283 			//right click: open popup
284 			wnd->contextPopup();
285 		}
286 		else if(e->button() & Qt::MidButton)
287 		{
288 			//mid click: close window
289 			wnd->delayedClose();
290 		}
291 	}
292 	else
293 	{
294 		//clicked on empty space
295 		if(e->button() & Qt::RightButton)
296 		{
297 			QMenu * pPopup = new QMenu();
298 			pPopup->addAction(__tr2qs("Sort"), this, SLOT(sort()));
299 			pPopup->addAction(__tr2qs("Reverse Sort"), this, SLOT(reverseSort()));
300 			pPopup->popup(QCursor::pos());
301 		}
302 	}
303 }
304 
mouseDoubleClickEvent(QMouseEvent * e)305 void KviTreeWindowListTreeWidget::mouseDoubleClickEvent(QMouseEvent * e)
306 {
307 	QTreeWidgetItem * it = itemAt(e->pos());
308 	if(it)
309 	{
310 		if(e->button() & Qt::LeftButton)
311 		{
312 			it->setExpanded(!(it->isExpanded()));
313 		}
314 	}
315 }
316 
sort()317 void KviTreeWindowListTreeWidget::sort()
318 {
319 	bReverseSort = false;
320 	sortItems(0, Qt::AscendingOrder);
321 }
322 
reverseSort()323 void KviTreeWindowListTreeWidget::reverseSort()
324 {
325 	bReverseSort = true;
326 	sortItems(0, Qt::DescendingOrder);
327 }
328 
paintEvent(QPaintEvent * event)329 void KviTreeWindowListTreeWidget::paintEvent(QPaintEvent * event)
330 {
331 	QPainter * p = new QPainter(viewport());
332 	QStyleOptionViewItem option = viewOptions();
333 	QRect rect = event->rect();
334 
335 #ifdef COMPILE_PSEUDO_TRANSPARENCY
336 	if(KVI_OPTION_BOOL(KviOption_boolUseCompositingForTransparency) && g_pApp->supportsCompositing())
337 	{
338 		p->save();
339 		p->setCompositionMode(QPainter::CompositionMode_Source);
340 		QColor col = KVI_OPTION_COLOR(KviOption_colorGlobalTransparencyFade);
341 		col.setAlphaF((float)((float)KVI_OPTION_UINT(KviOption_uintGlobalTransparencyChildFadeFactor) / (float)100));
342 		p->fillRect(rect, col);
343 		p->restore();
344 	}
345 	else if(g_pShadedChildGlobalDesktopBackground)
346 	{
347 		QPoint pnt = mapTo(g_pMainWindow, rect.topLeft());
348 		p->drawTiledPixmap(rect, *(g_pShadedChildGlobalDesktopBackground), pnt);
349 	}
350 	else
351 	{
352 #endif
353 		QPixmap * pix = KVI_OPTION_PIXMAP(KviOption_pixmapTreeWindowListBackground).pixmap();
354 		if(pix)
355 		{
356 			KviPixmapUtils::drawPixmapWithPainter(p, pix, KVI_OPTION_UINT(KviOption_uintTreeWindowListPixmapAlign), rect, viewport()->width(), viewport()->height());
357 		}
358 		else
359 		{
360 			p->fillRect(rect, KVI_OPTION_COLOR(KviOption_colorTreeWindowListBackground));
361 		}
362 #ifdef COMPILE_PSEUDO_TRANSPARENCY
363 	}
364 #endif
365 
366 	delete p;
367 
368 	//call paint on all childrens
369 	QTreeWidget::paintEvent(event);
370 }
371 
372 // KviTreeWindowList
373 
KviTreeWindowList()374 KviTreeWindowList::KviTreeWindowList()
375     : KviWindowListBase()
376 {
377 	m_pTreeWidget = new KviTreeWindowListTreeWidget(this);
378 	m_pTreeWidget->setColumnWidth(0, 135);
379 	m_pTreeWidget->header()->hide();
380 	setWidget(m_pTreeWidget);
381 
382 	//ad-hoc itemdelegate for this view
383 	m_pItemDelegate = new KviTreeWindowListItemDelegate(m_pTreeWidget);
384 	m_pTreeWidget->setItemDelegate(m_pItemDelegate);
385 
386 	//minimun and maximun width of the treeview
387 	if(KVI_OPTION_UINT(KviOption_uintTreeWindowListMinimumWidth) < 48)
388 		KVI_OPTION_UINT(KviOption_uintTreeWindowListMinimumWidth) = 48;
389 	int iMin = m_pTreeWidget->minimumSize().width() + 4;
390 	if(((unsigned int)iMin) < KVI_OPTION_UINT(KviOption_uintTreeWindowListMinimumWidth))
391 		iMin = KVI_OPTION_UINT(KviOption_uintTreeWindowListMinimumWidth);
392 	setMinimumWidth(iMin);
393 
394 	//tooltips
395 	m_pToolTip = new KviDynamicToolTip(m_pTreeWidget->viewport(), "tree_windowlist_tooltip");
396 	connect(m_pToolTip, SIGNAL(tipRequest(KviDynamicToolTip *, const QPoint &)), this, SLOT(tipRequest(KviDynamicToolTip *, const QPoint &)));
397 
398 	applyOptions();
399 }
400 
401 KviTreeWindowList::~KviTreeWindowList()
402     = default;
403 
updatePseudoTransparency()404 void KviTreeWindowList::updatePseudoTransparency()
405 {
406 #ifdef COMPILE_PSEUDO_TRANSPARENCY
407 	m_pTreeWidget->viewport()->update();
408 #endif
409 }
410 
moveEvent(QMoveEvent *)411 void KviTreeWindowList::moveEvent(QMoveEvent *)
412 {
413 #ifdef COMPILE_PSEUDO_TRANSPARENCY
414 	updatePseudoTransparency();
415 #endif
416 }
417 
tipRequest(KviDynamicToolTip *,const QPoint & pnt)418 void KviTreeWindowList::tipRequest(KviDynamicToolTip *, const QPoint & pnt)
419 {
420 	if(KVI_OPTION_BOOL(KviOption_boolShowWindowListToolTips))
421 	{
422 		QTreeWidgetItem * it = m_pTreeWidget->itemAt(pnt);
423 		if(it)
424 		{
425 			QString szText;
426 			((KviTreeWindowListItem *)it)->m_pWindow->getWindowListTipText(szText);
427 			m_pToolTip->tip(QRect(pnt, QSize(16, 16)), szText);
428 		}
429 	}
430 }
431 
addItem(KviWindow * wnd)432 KviWindowListItem * KviTreeWindowList::addItem(KviWindow * wnd)
433 {
434 	// complex insertion task
435 	if(wnd->console())
436 	{
437 		if(wnd->type() != KviWindow::Console)
438 		{
439 			((KviTreeWindowListItem *)(wnd->console()->m_pWindowListItem))->setExpanded(true);
440 			return new KviTreeWindowListItem(((KviTreeWindowListItem *)(wnd->console()->m_pWindowListItem)), wnd);
441 		}
442 	}
443 
444 	// console, or a window that has no irc context
445 	return new KviTreeWindowListItem(m_pTreeWidget, wnd);
446 }
447 
removeItem(KviWindowListItem * it)448 bool KviTreeWindowList::removeItem(KviWindowListItem * it)
449 {
450 	if(it)
451 	{
452 		KviTreeWindowListItem * item = (KviTreeWindowListItem *)it;
453 		if(m_pTreeWidget)
454 		{
455 			int index = m_pTreeWidget->indexOfTopLevelItem(item);
456 			if(index >= 0)
457 			{
458 				delete(KviTreeWindowListItem *)m_pTreeWidget->takeTopLevelItem(index);
459 			}
460 			else
461 			{
462 				index = item->parent()->indexOfChild(item);
463 				if(index >= 0)
464 					delete(KviTreeWindowListItem *)item->parent()->takeChild(index);
465 			}
466 		}
467 	}
468 	return true;
469 }
470 
setActiveItem(KviWindowListItem * it)471 void KviTreeWindowList::setActiveItem(KviWindowListItem * it)
472 {
473 	if(it)
474 	{
475 		if(((KviTreeWindowListItem *)it)->parent())
476 		{
477 			if(!((KviTreeWindowListItem *)it)->parent()->isExpanded())
478 				((KviTreeWindowListItem *)it)->parent()->setExpanded(true);
479 		}
480 
481 		((KviTreeWindowListItem *)it)->setActive(true);
482 		if(g_pMainWindow->trayIcon())
483 			g_pMainWindow->trayIcon()->refresh();
484 	}
485 }
486 
updateActivityMeter()487 void KviTreeWindowList::updateActivityMeter()
488 {
489 	if(KVI_OPTION_BOOL(KviOption_boolUseWindowListActivityMeter))
490 	{
491 		m_pTreeWidget->viewport()->update();
492 	}
493 }
494 
wheelEvent(QWheelEvent * e)495 void KviTreeWindowList::wheelEvent(QWheelEvent * e)
496 {
497 	// Override KviWindowListBase::wheelEvent.
498 	// Mouse wheel handling is done in
499 	// KviTreeWindowListTreeWidget::wheelEvent.
500 }
501 
firstItem()502 KviWindowListItem * KviTreeWindowList::firstItem()
503 {
504 	m_pCurrentItem = (KviTreeWindowListItem *)m_pTreeWidget->topLevelItem(0);
505 	return m_pCurrentItem;
506 }
507 
nextItem()508 KviWindowListItem * KviTreeWindowList::nextItem()
509 {
510 	if(!m_pCurrentItem)
511 		return nullptr;
512 	return m_pCurrentItem = (KviTreeWindowListItem *)m_pTreeWidget->itemBelow(m_pCurrentItem);
513 }
514 
prevItem()515 KviWindowListItem * KviTreeWindowList::prevItem()
516 {
517 	if(!m_pCurrentItem)
518 		return nullptr;
519 	return m_pCurrentItem = (KviTreeWindowListItem *)m_pTreeWidget->itemAbove(m_pCurrentItem);
520 }
521 
lastItem()522 KviWindowListItem * KviTreeWindowList::lastItem()
523 {
524 	// first find last toplevel item
525 	int tops = m_pTreeWidget->topLevelItemCount();
526 	if(tops > 0)
527 	{
528 		int ctops = m_pTreeWidget->topLevelItem(tops - 1)->childCount();
529 		if(ctops)
530 		{
531 			return m_pCurrentItem = (KviTreeWindowListItem *)m_pTreeWidget->topLevelItem(tops - 1)->child(ctops - 1);
532 		}
533 		else
534 		{
535 			return m_pCurrentItem = (KviTreeWindowListItem *)m_pTreeWidget->topLevelItem(tops - 1);
536 		}
537 	}
538 	else
539 	{
540 		return nullptr;
541 	}
542 }
543 
setIterationPointer(KviWindowListItem * it)544 bool KviTreeWindowList::setIterationPointer(KviWindowListItem * it)
545 {
546 	m_pCurrentItem = (KviTreeWindowListItem *)it;
547 	if(!m_pCurrentItem)
548 		return true;
549 	if(m_pTreeWidget == m_pCurrentItem->treeWidget())
550 		return true;
551 	m_pCurrentItem = nullptr;
552 	return false;
553 }
554 
555 // KviTreeWindowListItemDelegate
556 
paint(QPainter * p,const QStyleOptionViewItem & option,const QModelIndex & index) const557 void KviTreeWindowListItemDelegate::paint(QPainter * p, const QStyleOptionViewItem & option, const QModelIndex & index) const
558 {
559 	QString szText = index.data(Qt::DisplayRole).toString();
560 	int iProgress = index.data(KVI_TTBID_PROGRESS).toInt();
561 
562 	//FIXME not exactly model/view coding style.. but we need to access data on the associated window
563 	KviTreeWindowListTreeWidget * treeWidget = (KviTreeWindowListTreeWidget *)parent();
564 	KviTreeWindowListItem * item = (KviTreeWindowListItem *)treeWidget->itemFromIndex(index);
565 	KviWindow * pWindow = item->kviWindow();
566 
567 	QStyleOptionViewItem opt(option);
568 	opt.state = opt.state | QStyle::State_Selected;
569 	opt.showDecorationSelected = true;
570 	//paint cell background
571 	if(treeWidget->currentItem() == item)
572 	{
573 		//selection colored background
574 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
575 		if(treeWidget->style()->inherits("QStyleSheetStyle") || treeWidget->style()->inherits("QWindowsVistaStyle"))
576 		{
577 			// The Windows style does not honor our colors. It uses the system ones instead.
578 			// We can't accept it.
579 			p->fillRect(opt.rect, KVI_OPTION_COLOR(KviOption_colorTreeWindowListActiveBackground));
580 		}
581 		else
582 		{
583 #endif
584 			opt.palette.setColor(QPalette::Highlight, KVI_OPTION_COLOR(KviOption_colorTreeWindowListActiveBackground));
585 			treeWidget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, treeWidget);
586 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
587 		}
588 #endif
589 #ifndef COMPILE_ON_MAC
590 	}
591 	else
592 	{
593 		if(KVI_OPTION_BOOL(KviOption_boolEnableVisualEffects) && option.state & QStyle::State_MouseOver)
594 		{
595 			// paint mouse over effect
596 			QColor col(KVI_OPTION_COLOR(KviOption_colorTreeWindowListActiveBackground));
597 			col.setAlpha(127);
598 
599 	#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
600 			if(treeWidget->style()->inherits("QStyleSheetStyle") || treeWidget->style()->inherits("QWindowsVistaStyle"))
601 			{
602 				// The Windows style does not honor our colors. It uses the system ones instead.
603 				// We can't accept it.
604 				p->fillRect(opt.rect, col);
605 			}
606 			else
607 			{
608 	#endif
609 				opt.palette.setColor(QPalette::Highlight, col);
610 				treeWidget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, treeWidget);
611 	#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
612 			}
613 	#endif
614 		}
615 #endif
616 	}
617 	//draw window icon, irc context indicator (a colored square), set font properties for text
618 	int im = option.rect.left() + 2;
619 	int yPixmap = (option.rect.top() + (option.rect.height() / 2 - 8));
620 
621 	QRect cRect(im + 3, option.rect.top(), option.rect.width(), option.rect.height());
622 
623 	switch(pWindow->type())
624 	{
625 		case KviWindow::Console:
626 		{
627 			if(KVI_OPTION_BOOL(KviOption_boolUseWindowListIrcContextIndicator))
628 			{
629 				QColor base = option.palette.window().color();
630 				QColor cntx = KVI_OPTION_ICCOLOR(pWindow->console()->context()->id() % KVI_NUM_ICCOLOR_OPTIONS);
631 				base.setRgb((base.red() + cntx.red()) >> 1, (base.green() + cntx.green()) >> 1,
632 				    (base.blue() + cntx.blue()) >> 1);
633 				p->fillRect(im + 2, yPixmap, 14, 15, base);
634 				if(KVI_OPTION_BOOL(KviOption_boolUseWindowListIcons))
635 				{
636 					p->drawPixmap(im + 20, yPixmap, *(pWindow->myIconPtr()));
637 					cRect.setLeft(cRect.left() + 37);
638 				}
639 				else
640 				{
641 					cRect.setLeft(cRect.left() + 20);
642 				}
643 			}
644 			else
645 			{
646 				if(KVI_OPTION_BOOL(KviOption_boolUseWindowListIcons))
647 				{
648 					p->drawPixmap(im, yPixmap, *(pWindow->myIconPtr()));
649 					cRect.setLeft(cRect.left() + 17);
650 				}
651 			}
652 			//console window: bold font
653 			QFont f = p->font();
654 			f.setBold(true);
655 			p->setFont(f);
656 		}
657 		break;
658 		case KviWindow::Channel:
659 		case KviWindow::DeadChannel:
660 		case KviWindow::Query:
661 		case KviWindow::DeadQuery:
662 		default:
663 			if(KVI_OPTION_BOOL(KviOption_boolUseWindowListIcons))
664 			{
665 				p->drawPixmap(im, yPixmap, *(pWindow->myIconPtr()));
666 				cRect.setLeft(cRect.left() + 17);
667 			}
668 			//channels, other windows: normal font
669 			QFont f = p->font();
670 			f.setBold(false);
671 			p->setFont(f);
672 			break;
673 	}
674 
675 	// paint the channel activity meter
676 	if(KVI_OPTION_BOOL(KviOption_boolUseWindowListActivityMeter))
677 	{
678 		unsigned int uActivityValue;
679 		unsigned int uActivityTemperature;
680 		if(pWindow->activityMeter(&uActivityValue, &uActivityTemperature))
681 		{
682 			p->drawPixmap(cRect.left(), yPixmap, *g_pActivityMeterPixmap, uActivityValue * 5, uActivityTemperature * 16, 5, 16);
683 			cRect.setLeft(cRect.left() + 7);
684 		}
685 	}
686 
687 	// paint the progress bar
688 	if(iProgress >= 0)
689 	{
690 		int wdth = (iProgress * cRect.width()) / 100;
691 		p->fillRect(cRect.x(), cRect.y(), wdth, cRect.height(), KVI_OPTION_COLOR(KviOption_colorTreeWindowListProgress));
692 	}
693 
694 	//choose window name font color (highlighting)
695 	if(treeWidget->currentItem() == item)
696 	{
697 		p->setPen(KVI_OPTION_COLOR(KviOption_colorTreeWindowListActiveForeground));
698 	}
699 	else
700 	{
701 		int iHighlightLevel = index.data(KVI_TTBID_HIGHLIGHT).toInt();
702 		int iLevel;
703 
704 		switch(iHighlightLevel)
705 		{
706 			case 0:
707 				iLevel = KviOption_colorTreeWindowListForeground;
708 				break;
709 			case 1:
710 				iLevel = KviOption_colorTreeWindowListHighlight1Foreground;
711 				break;
712 			case 2:
713 				iLevel = KviOption_colorTreeWindowListHighlight2Foreground;
714 				break;
715 			case 3:
716 				iLevel = KviOption_colorTreeWindowListHighlight3Foreground;
717 				break;
718 			case 4:
719 				iLevel = KviOption_colorTreeWindowListHighlight4Foreground;
720 				break;
721 			default:
722 				iLevel = KviOption_colorTreeWindowListHighlight5Foreground;
723 				break;
724 		}
725 
726 		p->setPen(KVI_OPTION_COLOR(iLevel));
727 	}
728 
729 	//qDebug("Draw text in %d,%d,%d,%d (%s)",cRect.left(),cRect.top(),cRect.width(),cRect.height(),szText.toUtf8().data());
730 
731 	//draw window name
732 	p->drawText(cRect, Qt::AlignLeft | Qt::AlignVCenter, szText);
733 }
734 
sizeHint(const QStyleOptionViewItem &,const QModelIndex &) const735 QSize KviTreeWindowListItemDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
736 {
737 	KviTreeWindowListTreeWidget * treeWidget = (KviTreeWindowListTreeWidget *)parent();
738 	int iHeight = treeWidget->fontMetrics().lineSpacing();
739 
740 	iHeight += iHeight / 3;
741 	if((KVI_OPTION_BOOL(KviOption_boolUseWindowListIrcContextIndicator) || KVI_OPTION_BOOL(KviOption_boolUseWindowListIcons) || KVI_OPTION_BOOL(KviOption_boolUseWindowListActivityMeter)) && iHeight < 20)
742 		iHeight = 20;
743 
744 	return { treeWidget->viewport()->size().width(), iHeight };
745 }
746