not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / klipper / popupproxy.cpp
blob8bb605b3c83c42632d83abfb6932a9eb95e81bcb
1 // -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
2 /* This file is part of the KDE project
3 Copyright (C) 2004 Esben Mose Hansen <kde@mosehansen.dk>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU 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.
10 This program 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
20 #include <QRegExp>
21 #include <QStyle>
22 #include <QPixmap>
23 #include <QImage>
24 #include <QStyleOption>
26 #include <kstringhandler.h>
27 #include <klocale.h>
28 #include <kdebug.h>
30 #include "historyitem.h"
31 #include "popupproxy.h"
32 #include "history.h"
33 #include "klipperpopup.h"
36 PopupProxy::PopupProxy( KlipperPopup* parent, int menu_height, int menu_width )
37 : QObject( parent ),
38 m_proxy_for_menu( parent ),
39 m_spillPointer( parent->history()->youngest() ),
40 m_menu_height( menu_height ),
41 m_menu_width( menu_width ),
42 m_nextItemNumber( 0 )
44 connect( parent->history(), SIGNAL( changed() ), SLOT( slotHistoryChanged() ) );
45 connect(m_proxy_for_menu, SIGNAL(triggered(QAction*)), parent->history(), SLOT(slotMoveToTop(QAction*)));
48 void PopupProxy::slotHistoryChanged() {
49 deleteMoreMenus();
53 void PopupProxy::deleteMoreMenus() {
54 const KMenu* myParent = parent();
55 if ( myParent != m_proxy_for_menu ) {
56 KMenu* delme = m_proxy_for_menu;
57 m_proxy_for_menu = static_cast<KMenu*>( m_proxy_for_menu->parent() );
58 while ( m_proxy_for_menu != myParent ) {
59 delme = m_proxy_for_menu;
60 m_proxy_for_menu = static_cast<KMenu*>( m_proxy_for_menu->parent() );
62 // We are called probably from within the menus event-handler (triggered=>slotMoveToTop=>changed=>slotHistoryChanged=>deleteMoreMenus)
63 // what can result in a crash if we just delete the menu here (#155196 and #165154) So, delay the delete.
64 delme->deleteLater();
68 int PopupProxy::buildParent( int index, const QRegExp& filter ) {
69 deleteMoreMenus();
70 // Start from top of history (again)
71 m_spillPointer = parent()->history()->youngest();
72 m_nextItemNumber = 0;
73 if ( filter.isValid() ) {
74 m_filter = filter;
77 return insertFromSpill( index );
81 KlipperPopup* PopupProxy::parent() {
82 return static_cast<KlipperPopup*>( QObject::parent() );
85 void PopupProxy::slotAboutToShow() {
86 insertFromSpill();
89 void PopupProxy::tryInsertItem( HistoryItem const * const item,
90 int& remainingHeight,
91 const int index )
93 QAction *action = new QAction(m_proxy_for_menu);
94 QPixmap image( item->image() );
95 if ( image.isNull() ) {
96 // Squeeze text strings so that do not take up the entire screen (or more)
97 QString text = m_proxy_for_menu->fontMetrics().elidedText( item->text().simplified(), Qt::ElideMiddle, m_menu_width );
98 text.replace( '&', "&&" );
99 action->setText(text);
100 } else {
101 #if 0 // not used because QAction#setIcon does not respect this size; it does scale anyway. TODO: find a way to set a bigger image
102 const QSize max_size( m_menu_width,m_menu_height/4 );
103 if ( image.height() > max_size.height() || image.width() > max_size.width() ) {
104 image = image.scaled( max_size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
106 #endif
107 action->setIcon(QIcon(image));
110 action->setData(m_nextItemNumber);
112 // if the m_proxy_for_menu is a submenu (aka a "More" menu) then it may the case, that there is no other action in that menu yet.
113 QAction *before = index < m_proxy_for_menu->actions().count() ? m_proxy_for_menu->actions().at(index) : 0;
114 // insert the new action to the m_proxy_for_menu
115 m_proxy_for_menu->insertAction(before, action);
117 // Determine height of a menu item.
118 int itemheight = QFontMetrics(m_proxy_for_menu->fontMetrics()).height();
120 //TODO Use old-style QStyle and QStyleOption API
121 #if 0
122 Q_ASSERT( id != -1 ); // Be sure that the item was inserted.
123 QMenuItem* mi = m_proxy_for_menu->findItem( id );
126 int itemheight = m_proxy_for_menu->style().sizeFromContents(QStyle::CT_PopupMenuItem,
127 m_proxy_for_menu,
128 QSize( 0, fontheight ),
129 QStyleOption(mi,10,0) ).height();
130 #endif
131 // Test if there was enough space
132 remainingHeight -= itemheight;
135 int PopupProxy::insertFromSpill( int index ) {
137 // This menu is going to be filled, so we don't need the aboutToShow()
138 // signal anymore
139 disconnect( m_proxy_for_menu, 0, this, 0 );
141 // Insert history items into the current m_proxy_for_menu,
142 // discarding any that doesn't match the current filter.
143 // stop when the total number of items equal m_itemsPerMenu;
144 int count = 0;
145 int remainingHeight = m_menu_height - m_proxy_for_menu->sizeHint().height();
146 // Force at least one item to be inserted.
147 remainingHeight = qMax( remainingHeight, 0 );
149 while (m_spillPointer.hasNext() && remainingHeight >= 0) {
150 const HistoryItem *item = m_spillPointer.next();
151 if ( m_filter.indexIn( item->text() ) == -1) {
152 m_nextItemNumber++; // also count hidden items
153 continue;
155 tryInsertItem( item, remainingHeight, index++ );
156 count++;
157 m_nextItemNumber++;
160 // If there is more items in the history, insert a new "More..." menu and
161 // make *this a proxy for that menu ('s content).
162 if (m_spillPointer.hasNext()) {
163 KMenu* moreMenu = new KMenu(i18n("&More"), m_proxy_for_menu);
164 connect(moreMenu, SIGNAL(aboutToShow()), SLOT(slotAboutToShow()));
165 QAction *before = index < m_proxy_for_menu->actions().count() ? m_proxy_for_menu->actions().at(index) : 0;
166 m_proxy_for_menu->insertMenu(before, moreMenu);
167 m_proxy_for_menu = moreMenu;
170 // Return the number of items inserted.
171 return count;
174 #include "popupproxy.moc"