~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to src/widgets/iconselect.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * iconselect.cpp - class that allows user to select an PsiIcon from an Iconset
 
3
 * Copyright (C) 2003-2005  Michail Pishchagin
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 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
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include "iconselect.h"
 
22
 
 
23
#include <QApplication>
 
24
#include <QDesktopWidget>
 
25
#include <QPainter>
 
26
#include <QStyle>
 
27
#include <QStyleOption>
 
28
#include <QLayout>
 
29
#include <QAbstractButton>
 
30
#include <QLabel>
 
31
#include <QTextCodec>
 
32
#include <QMenuItem>
 
33
#include <QEvent>
 
34
#include <QMouseEvent>
 
35
 
 
36
#include <math.h>
 
37
 
 
38
#include "iconset.h"
 
39
#include "psitooltip.h"
 
40
 
 
41
//----------------------------------------------------------------------------
 
42
// IconSelectButton
 
43
//----------------------------------------------------------------------------
 
44
 
 
45
//! \if _hide_doc_
 
46
/**
 
47
        \class IconSelectButton
 
48
        \brief This button is used by IconSelect and displays one PsiIcon 
 
49
*/
 
50
class IconSelectButton : public QAbstractButton
 
51
{
 
52
        Q_OBJECT
 
53
 
 
54
private:
 
55
        PsiIcon *ic;
 
56
        QString text;
 
57
        QSize s;
 
58
        bool animated;
 
59
 
 
60
public:
 
61
        IconSelectButton(QWidget *parent)
 
62
        : QAbstractButton(parent)
 
63
        {
 
64
                ic = 0;
 
65
                animated = false;
 
66
                connect (this, SIGNAL(clicked()), SLOT(iconSelected()));
 
67
        }
 
68
 
 
69
        ~IconSelectButton()
 
70
        {
 
71
                iconStop();
 
72
 
 
73
                if ( ic ) {
 
74
                        delete ic;
 
75
                        ic = 0;
 
76
                }
 
77
        }
 
78
 
 
79
        void setIcon(const PsiIcon *i)
 
80
        {
 
81
                iconStop();
 
82
 
 
83
                if ( ic ) {
 
84
                        delete ic;
 
85
                        ic = 0;
 
86
                }
 
87
 
 
88
                if ( i )
 
89
                        ic = new PsiIcon(*((PsiIcon *)i));
 
90
                else
 
91
                        ic = 0;
 
92
        }
 
93
 
 
94
        const PsiIcon *icon() const
 
95
        {
 
96
                return ic;
 
97
        }
 
98
 
 
99
        QSize sizeHint() const { return s; }
 
100
        void setSizeHint(QSize sh) { s = sh; }
 
101
 
 
102
signals:
 
103
        void iconSelected(const PsiIcon *);
 
104
        void textSelected(QString);
 
105
 
 
106
public slots:
 
107
        void aboutToShow() { iconStart(); }
 
108
        void aboutToHide() { iconStop();  }
 
109
 
 
110
private:
 
111
        void iconStart()
 
112
        {
 
113
                if ( ic ) {
 
114
                        connect(ic, SIGNAL(pixmapChanged()), SLOT(iconUpdated()));
 
115
                        if ( !animated ) {
 
116
                                ic->activated(false);
 
117
                                animated = true;
 
118
                        }
 
119
 
 
120
                        if ( !ic->text().isEmpty() ) {
 
121
                                // first, try to get the text by priorities
 
122
                                QStringList lang;
 
123
                                lang << QString(QTextCodec::locale()).left(2); // most prioritent, is the local language
 
124
                                lang << "";                                    // and then the language without name goes (international?)
 
125
                                lang << "en";                                  // then real English
 
126
 
 
127
                                QString str;
 
128
                                QStringList::Iterator it = lang.begin();
 
129
                                for ( ; it != lang.end(); ++it) {
 
130
                                        QHash<QString, QString>::const_iterator it2 = ic->text().find( *it );
 
131
                                        if ( it2 != ic->text().end() ) {
 
132
                                                str = it2.value();
 
133
                                                break;
 
134
                                        }
 
135
                                }
 
136
 
 
137
                                // if all fails, just get the first text
 
138
                                if ( str.isEmpty() )
 
139
                                {
 
140
                                        QHashIterator<QString, QString> it ( ic->text() );
 
141
                                        while ( it.hasNext() ) {
 
142
                                                it.next();
 
143
 
 
144
                                                if ( !it.value().isEmpty() ) {
 
145
                                                        str = it.value();
 
146
                                                        break;
 
147
                                                }
 
148
                                        }
 
149
                                }
 
150
 
 
151
                                if ( !str.isEmpty() )
 
152
                                        text = str;
 
153
 
 
154
                                // and list of possible variants in the ToolTip
 
155
                                QString toolTip;
 
156
                                foreach ( QString icText, ic->text() ) {
 
157
                                        if ( !toolTip.isEmpty() )
 
158
                                                toolTip += ", ";
 
159
                                        toolTip += icText;
 
160
                                        break; // comment this to get list of iconsets
 
161
                                }
 
162
                                if ( toolTip.length() > 30 )
 
163
                                        toolTip = toolTip.left(30) + "...";
 
164
                                setToolTip(toolTip);
 
165
                        }
 
166
                }
 
167
        }
 
168
 
 
169
        void iconStop()
 
170
        {
 
171
                if ( ic ) {
 
172
                        disconnect(ic, 0, this, 0 );
 
173
                        if ( animated ) {
 
174
                                ic->stop();
 
175
                                animated = false;
 
176
                        }
 
177
                }
 
178
        }
 
179
 
 
180
        void enterEvent(QEvent *) { setFocus();   update(); } // focus follows mouse mode
 
181
        void leaveEvent(QEvent *) { clearFocus(); update(); }
 
182
 
 
183
private slots:
 
184
        void iconUpdated()
 
185
        {
 
186
                update();
 
187
        }
 
188
 
 
189
        void iconSelected()
 
190
        {
 
191
                clearFocus();
 
192
                if ( ic ) {
 
193
                        emit iconSelected(ic);
 
194
                        emit textSelected(text);
 
195
                }
 
196
        }
 
197
 
 
198
private:
 
199
        void paintEvent(QPaintEvent *)
 
200
        {
 
201
                QPainter p(this);
 
202
                QFlags<QStyle::StateFlag> flags = QStyle::State_Active | QStyle::State_Enabled;
 
203
 
 
204
                if ( hasFocus() )
 
205
                        flags |= QStyle::State_Selected;
 
206
                
 
207
                QStyleOptionMenuItem opt;
 
208
                opt.palette = palette();
 
209
                opt.state = flags;
 
210
                opt.font = font();
 
211
                opt.rect = rect();              
 
212
                style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);
 
213
 
 
214
                if ( ic ) {
 
215
                        QPixmap pix = ic->pixmap();
 
216
                        p.drawPixmap((width() - pix.width())/2, (height() - pix.height())/2, pix);
 
217
                }
 
218
        }
 
219
};
 
220
//! \endif
 
221
 
 
222
//----------------------------------------------------------------------------
 
223
// IconSelect -- the widget that does all dirty work
 
224
//----------------------------------------------------------------------------
 
225
 
 
226
class IconSelect : public QWidget
 
227
{
 
228
        Q_OBJECT
 
229
 
 
230
private:
 
231
        IconSelectPopup *menu;
 
232
        Iconset is;
 
233
        QGridLayout *grid;
 
234
        bool shown;
 
235
 
 
236
public:
 
237
        IconSelect(IconSelectPopup *parentMenu);
 
238
        ~IconSelect();
 
239
 
 
240
        void setIconset(const Iconset &);
 
241
        const Iconset &iconset() const;
 
242
 
 
243
protected:
 
244
        void noIcons();
 
245
 
 
246
protected slots:
 
247
        void closeMenu();
 
248
};
 
249
 
 
250
IconSelect::IconSelect(IconSelectPopup *parentMenu)
 
251
: QWidget(parentMenu)
 
252
{
 
253
        menu = parentMenu;
 
254
        connect(menu, SIGNAL(textSelected(QString)), SLOT(closeMenu()));
 
255
 
 
256
        grid = 0;
 
257
        noIcons();
 
258
}
 
259
 
 
260
IconSelect::~IconSelect()
 
261
{
 
262
}
 
263
 
 
264
void IconSelect::closeMenu()
 
265
{
 
266
        // this way all parent menus (if any) would be closed too
 
267
        QMouseEvent me(QEvent::MouseButtonPress, menu->pos() - QPoint(5, 5), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
 
268
        menu->mousePressEvent(&me);
 
269
        
 
270
        // just in case
 
271
        menu->close();
 
272
}
 
273
 
 
274
void IconSelect::noIcons()
 
275
{
 
276
        grid = new QGridLayout(this);
 
277
 
 
278
        QLabel *lbl = new QLabel(this);
 
279
        grid->addWidget(lbl);
 
280
        lbl->setText( tr("No icons available") );
 
281
}
 
282
 
 
283
void IconSelect::setIconset(const Iconset &iconset)
 
284
{
 
285
        is = iconset;
 
286
 
 
287
        // delete all children
 
288
        if (grid) {
 
289
                delete grid;
 
290
 
 
291
                QList<QWidget *> list = findChildren<QWidget *>();
 
292
                QObject *object;
 
293
                foreach (object, list)
 
294
                        delete object;
 
295
        }
 
296
 
 
297
        if ( !is.count() ) {
 
298
                noIcons();
 
299
                return;
 
300
        }
 
301
 
 
302
        // first we need to find optimal size for elements and don't forget about
 
303
        // taking too much screen space
 
304
        float w = 0, h = 0;
 
305
 
 
306
        double count; // the 'double' type is somewhat important for MSVC.NET here
 
307
        QListIterator<PsiIcon *> it = is.iterator();
 
308
        for (count = 0; it.hasNext(); count++) {
 
309
                PsiIcon *icon = it.next();
 
310
                w += icon->pixmap().width();
 
311
                h += icon->pixmap().height();
 
312
        }
 
313
        w /= count;
 
314
        h /= count;
 
315
 
 
316
        const int margin = 2;
 
317
        int tileSize = (int)QMAX(w, h) + 2*margin;
 
318
 
 
319
        QRect r = QApplication::desktop()->availableGeometry( menu );
 
320
        int maxSize = QMIN(r.width(), r.height())*3/4;
 
321
 
 
322
        int size = (int)ceil( sqrt( count ) );
 
323
 
 
324
        if ( size*tileSize > maxSize ) { // too many icons. find reasonable size.
 
325
                int c = 0;
 
326
                for (w = 0; w <= maxSize; w += tileSize)
 
327
                        c++;
 
328
                size = c - 1;
 
329
        }
 
330
 
 
331
        // now, fill grid with elements
 
332
        grid = new QGridLayout(this, size, size);
 
333
 
 
334
        count = 0;
 
335
 
 
336
        it = is.iterator();
 
337
        while ( it.hasNext() ) {
 
338
                if ( ++count > size*size )
 
339
                        break;
 
340
 
 
341
                IconSelectButton *b = new IconSelectButton(this);
 
342
                grid->addWidget(b);
 
343
                b->setIcon( it.next() );
 
344
                b->setSizeHint( QSize(tileSize, tileSize) );
 
345
                connect (b, SIGNAL(iconSelected(const PsiIcon *)), menu, SIGNAL(iconSelected(const PsiIcon *)));
 
346
                connect (b, SIGNAL(textSelected(QString)), menu, SIGNAL(textSelected(QString)));
 
347
 
 
348
                connect (menu, SIGNAL(aboutToShow()), b, SLOT(aboutToShow()));
 
349
                connect (menu, SIGNAL(aboutToHide()), b, SLOT(aboutToHide()));
 
350
        }
 
351
}
 
352
 
 
353
const Iconset &IconSelect::iconset() const
 
354
{
 
355
        return is;
 
356
}
 
357
 
 
358
//----------------------------------------------------------------------------
 
359
// IconSelectPopup
 
360
//----------------------------------------------------------------------------
 
361
 
 
362
class IconSelectPopup::Private : public QObject
 
363
{
 
364
public:
 
365
        Private(IconSelectPopup *parent)
 
366
        : QObject(parent)
 
367
        {
 
368
                icsel = new IconSelect(parent);
 
369
        }
 
370
        
 
371
        IconSelect *icsel;
 
372
};
 
373
 
 
374
IconSelectPopup::IconSelectPopup(QWidget *parent)
 
375
: QMenu(parent)
 
376
{
 
377
        QGridLayout *grid = new QGridLayout(this);
 
378
        grid->setMargin(style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this));
 
379
        grid->setAutoAdd(true);
 
380
        
 
381
        d = new Private(this);
 
382
}
 
383
 
 
384
IconSelectPopup::~IconSelectPopup()
 
385
{
 
386
}
 
387
 
 
388
void IconSelectPopup::setIconset(const Iconset &i)
 
389
{
 
390
        d->icsel->setIconset(i);
 
391
}
 
392
 
 
393
const Iconset &IconSelectPopup::iconset() const
 
394
{
 
395
        return d->icsel->iconset();
 
396
}
 
397
 
 
398
/**
 
399
        It's used by child widget to close the menu by simulating a
 
400
        click slightly outside of menu. This seems to be the best way
 
401
        to achieve this.
 
402
*/
 
403
void IconSelectPopup::mousePressEvent(QMouseEvent *e)
 
404
{
 
405
        QMenu::mousePressEvent(e);
 
406
}
 
407
 
 
408
/**
 
409
        Override QMenu's nasty sizeHint() and use standard QWidget one
 
410
        which honors layouts and child widgets.
 
411
*/
 
412
QSize IconSelectPopup::sizeHint() const
 
413
{
 
414
        return QWidget::sizeHint();
 
415
}
 
416
 
 
417
#include "iconselect.moc"