source: visorpdf/sources/miscellaneous.cpp @ e8a029e

pruebas
Last change on this file since e8a029e was e0e368b, checked in by Pedro Buitrago <pbuitrago@…>, 8 years ago

agregando los directorios pendientes

  • Property mode set to 100644
File size: 18.0 KB
Line 
1/*
2
3Copyright 2014 S. Razi Alavizadeh
4Copyright 2012-2015 Adam Reichold
5Copyright 2014 Dorian Scholz
6
7This file is part of qpdfview.
8
9qpdfview is free software: you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation, either version 2 of the License, or
12(at your option) any later version.
13
14qpdfview is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with qpdfview.  If not, see <http://www.gnu.org/licenses/>.
21
22*/
23
24#include "miscellaneous.h"
25
26#include <QApplication>
27#include <QDebug>
28#include <QDialog>
29#include <QDialogButtonBox>
30#include <QLabel>
31#include <QMenu>
32#include <QMouseEvent>
33#include <QScrollBar>
34#include <QTimer>
35#include <QToolTip>
36#include <QVBoxLayout>
37
38#include "searchmodel.h"
39
40namespace
41{
42
43using namespace qpdfview;
44
45inline bool isPrintable(const QString& string)
46{
47    foreach(QChar character, string)
48    {
49        if(!character.isPrint())
50        {
51            return false;
52        }
53    }
54
55    return true;
56}
57
58inline QModelIndex firstIndex(const QModelIndexList& indexes)
59{
60    return !indexes.isEmpty() ? indexes.first() : QModelIndex();
61}
62
63} // anonymous
64
65namespace qpdfview
66{
67
68GraphicsCompositionModeEffect::GraphicsCompositionModeEffect(QPainter::CompositionMode compositionMode, QObject* parent) : QGraphicsEffect(parent),
69    m_compositionMode(compositionMode)
70{
71}
72
73void GraphicsCompositionModeEffect::draw(QPainter* painter)
74{
75    painter->save();
76
77    painter->setCompositionMode(m_compositionMode);
78
79    drawSource(painter);
80
81    painter->restore();
82}
83
84ProxyStyle::ProxyStyle() : QProxyStyle(),
85    m_scrollableMenus(false)
86{
87}
88
89bool ProxyStyle::scrollableMenus() const
90{
91    return m_scrollableMenus;
92}
93
94void ProxyStyle::setScrollableMenus(bool scrollableMenus)
95{
96    m_scrollableMenus = scrollableMenus;
97}
98
99int ProxyStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const
100{
101    if(m_scrollableMenus && hint == QStyle::SH_Menu_Scrollable)
102    {
103        return 1;
104    }
105
106    return QProxyStyle::styleHint(hint, option, widget, returnData);
107}
108
109SearchableMenu::SearchableMenu(const QString& title, QWidget* parent) : QMenu(title, parent),
110    m_searchable(false),
111    m_text()
112{
113}
114
115bool SearchableMenu::isSearchable() const
116{
117    return m_searchable;
118}
119
120void SearchableMenu::setSearchable(bool searchable)
121{
122    m_searchable = searchable;
123}
124
125void SearchableMenu::hideEvent(QHideEvent* event)
126{
127    QMenu::hideEvent(event);
128
129    if(m_searchable && !event->spontaneous())
130    {
131        m_text = QString();
132
133        foreach(QAction* action, actions())
134        {
135            action->setVisible(true);
136        }
137    }
138}
139
140void SearchableMenu::keyPressEvent(QKeyEvent* event)
141{
142    if(!m_searchable)
143    {
144        QMenu::keyPressEvent(event);
145        return;
146    }
147
148    const QString text = event->text();
149
150    if(!text.isEmpty() && isPrintable(text))
151    {
152        m_text.append(text);
153    }
154    else if(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete)
155    {
156        m_text.chop(1);
157    }
158    else
159    {
160        QMenu::keyPressEvent(event);
161        return;
162    }
163
164    setActiveAction(0);
165
166    foreach(QAction* action, actions())
167    {
168        if(!action->data().isNull()) // Modify only flagged actions
169        {
170            const bool visible = action->text().contains(m_text, Qt::CaseInsensitive);
171
172            action->setVisible(visible);
173
174            if(visible && activeAction() == 0)
175            {
176                setActiveAction(action);
177            }
178        }
179    }
180
181    QToolTip::showText(mapToGlobal(rect().topLeft()), tr("Search for '%1'...").arg(m_text), this);
182}
183
184TabBar::TabBar(QWidget* parent) : QTabBar(parent)
185{
186}
187
188QSize TabBar::tabSizeHint(int index) const
189{
190    QSize size = QTabBar::tabSizeHint(index);
191
192    const TabWidget* tabWidget = qobject_cast< TabWidget* >(parentWidget());
193
194    if(tabWidget != 0 && tabWidget->spreadTabs())
195    {
196        switch(tabWidget->tabPosition())
197        {
198        default:
199        case QTabWidget::North:
200        case QTabWidget::South:
201            size.setWidth(qMax(width() / count(), size.width()));
202            break;
203        case QTabWidget::East:
204        case QTabWidget::West:
205            size.setHeight(qMax(height() / count(), size.height()));
206            break;
207        }
208    }
209
210    return size;
211}
212
213void TabBar::mousePressEvent(QMouseEvent* event)
214{
215    QTabBar::mousePressEvent(event);
216
217    if(event->button() == Qt::MidButton)
218    {
219        const int index = tabAt(event->pos());
220
221        if(index != -1)
222        {
223            emit tabCloseRequested(index);
224        }
225    }
226}
227
228TabWidget::TabWidget(QWidget* parent) : QTabWidget(parent),
229    m_tabBarPolicy(TabBarAsNeeded),
230    m_spreadTabs(false)
231{
232    setTabBar(new TabBar(this));
233
234    tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
235
236    connect(tabBar(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(on_tabBar_customContextMenuRequested(QPoint)));
237}
238
239TabWidget::TabBarPolicy TabWidget::tabBarPolicy() const
240{
241    return m_tabBarPolicy;
242}
243
244void TabWidget::setTabBarPolicy(TabWidget::TabBarPolicy tabBarPolicy)
245{
246    m_tabBarPolicy = tabBarPolicy;
247
248    switch(m_tabBarPolicy)
249    {
250    case TabBarAsNeeded:
251        tabBar()->setVisible(count() > 1);
252        break;
253    case TabBarAlwaysOn:
254        tabBar()->setVisible(true);
255        break;
256    case TabBarAlwaysOff:
257        tabBar()->setVisible(false);
258        break;
259    }
260}
261
262bool TabWidget::spreadTabs() const
263{
264    return m_spreadTabs;
265}
266
267void TabWidget::setSpreadTabs(bool spreadTabs)
268{
269    if(m_spreadTabs != spreadTabs)
270    {
271        m_spreadTabs = spreadTabs;
272
273        QResizeEvent resizeEvent(tabBar()->size(), tabBar()->size());
274        QApplication::sendEvent(tabBar(), &resizeEvent);
275    }
276}
277
278void TabWidget::on_tabBar_customContextMenuRequested(const QPoint& pos)
279{
280    emit tabContextMenuRequested(tabBar()->mapToGlobal(pos), tabBar()->tabAt(pos));
281}
282
283void TabWidget::tabInserted(int index)
284{
285    QTabWidget::tabInserted(index);
286
287    if(m_tabBarPolicy == TabBarAsNeeded)
288    {
289        tabBar()->setVisible(count() > 1);
290    }
291}
292
293void TabWidget::tabRemoved(int index)
294{
295    QTabWidget::tabRemoved(index);
296
297    if(m_tabBarPolicy == TabBarAsNeeded)
298    {
299        tabBar()->setVisible(count() > 1);
300    }
301}
302
303TreeView::TreeView(int expansionRole, QWidget* parent) : QTreeView(parent),
304    m_expansionRole(expansionRole)
305{
306    connect(this, SIGNAL(expanded(QModelIndex)), SLOT(on_expanded(QModelIndex)));
307    connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(on_collapsed(QModelIndex)));
308}
309
310void TreeView::expandAbove(const QModelIndex& child)
311{
312    for(QModelIndex index = child.parent(); index.isValid(); index = index.parent())
313    {
314        expand(index);
315    }
316}
317
318void TreeView::expandAll(const QModelIndex& index)
319{
320    if(index.isValid())
321    {
322        if(!isExpanded(index))
323        {
324            expand(index);
325        }
326
327        for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
328        {
329            expandAll(index.child(row, 0));
330        }
331    }
332    else
333    {
334        QTreeView::expandAll();
335    }
336}
337
338void TreeView::collapseAll(const QModelIndex& index)
339{
340    if(index.isValid())
341    {
342        if(isExpanded(index))
343        {
344            collapse(index);
345        }
346
347        for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
348        {
349            collapseAll(index.child(row, 0));
350        }
351    }
352    else
353    {
354        QTreeView::collapseAll();
355    }
356}
357
358int TreeView::expandedDepth(const QModelIndex& index)
359{
360    if(index.isValid())
361    {
362        if(!isExpanded(index) || !model()->hasChildren(index))
363        {
364            return 0;
365        }
366
367        int depth = 0;
368
369        for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
370        {
371            depth = qMax(depth, expandedDepth(index.child(row, 0)));
372        }
373
374        return 1 + depth;
375    }
376    else
377    {
378        int depth = 0;
379
380        for(int row = 0, rowCount = model()->rowCount(); row < rowCount; ++row)
381        {
382            depth = qMax(depth, expandedDepth(model()->index(row, 0)));
383        }
384
385        return depth;
386    }
387}
388
389void TreeView::expandToDepth(const QModelIndex& index, int depth)
390{
391    if(index.isValid())
392    {
393        if(depth > 0)
394        {
395            if(!isExpanded(index))
396            {
397                expand(index);
398            }
399        }
400
401        if(depth > 1)
402        {
403            for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
404            {
405                expandToDepth(index.child(row, 0), depth - 1);
406            }
407        }
408    }
409    else
410    {
411        for(int row = 0, rowCount = model()->rowCount(); row < rowCount; ++row)
412        {
413            expandToDepth(model()->index(row, 0), depth);
414        }
415    }
416}
417
418void TreeView::collapseFromDepth(const QModelIndex& index, int depth)
419{
420    if(index.isValid())
421    {
422        if(depth <= 0)
423        {
424            if(isExpanded(index))
425            {
426                collapse(index);
427            }
428        }
429
430        for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
431        {
432            collapseFromDepth(index.child(row, 0), depth - 1);
433        }
434    }
435    else
436    {
437        for(int row = 0, rowCount = model()->rowCount(); row < rowCount; ++row)
438        {
439            collapseFromDepth(model()->index(row, 0), depth);
440        }
441    }
442}
443
444void TreeView::restoreExpansion(const QModelIndex& index)
445{
446    if(index.isValid())
447    {
448        const bool expanded = index.data(m_expansionRole).toBool();
449
450        if(isExpanded(index) != expanded)
451        {
452            setExpanded(index, expanded);
453        }
454    }
455
456    for(int row = 0, rowCount = model()->rowCount(index); row < rowCount; ++row)
457    {
458        restoreExpansion(model()->index(row, 0, index));
459    }
460}
461
462void TreeView::keyPressEvent(QKeyEvent* event)
463{
464    const bool verticalKeys = event->key() == Qt::Key_Up || event->key() == Qt::Key_Down;
465    const bool horizontalKeys = event->key() == Qt::Key_Left || event->key() == Qt::Key_Right;
466
467    const QModelIndex selection = firstIndex(selectedIndexes());
468
469    // If Shift is pressed, the view is scrolled up or down.
470    if(event->modifiers().testFlag(Qt::ShiftModifier) && verticalKeys)
471    {
472        QScrollBar* scrollBar = verticalScrollBar();
473
474        if(event->key() == Qt::Key_Up && scrollBar->value() > scrollBar->minimum())
475        {
476            scrollBar->triggerAction(QAbstractSlider::SliderSingleStepSub);
477
478            event->accept();
479            return;
480        }
481        else if(event->key() == Qt::Key_Down && scrollBar->value() < scrollBar->maximum())
482        {
483            scrollBar->triggerAction(QAbstractSlider::SliderSingleStepAdd);
484
485            event->accept();
486            return;
487        }
488    }
489
490    // If Control is pressed, all children of the selected item are expanded or collapsed.
491    if(event->modifiers().testFlag(Qt::ControlModifier) && horizontalKeys)
492    {
493        if(event->key() == Qt::Key_Left)
494        {
495            collapseAll(selection);
496        }
497        else if(event->key() == Qt::Key_Right)
498        {
499            expandAll(selection);
500        }
501
502        event->accept();
503        return;
504    }
505
506    // If Shift is pressed, one level of children of the selected item are expanded or collapsed.
507    if(event->modifiers().testFlag(Qt::ShiftModifier) && horizontalKeys)
508    {
509        const int depth = expandedDepth(selection);
510
511        if(event->key() == Qt::Key_Left)
512        {
513            collapseFromDepth(selection, depth - 1);
514        }
515        else if(event->key() == Qt::Key_Right)
516        {
517            expandToDepth(selection, depth + 1);
518        }
519
520        event->accept();
521        return;
522    }
523
524    QTreeView::keyPressEvent(event);
525}
526
527void TreeView::wheelEvent(QWheelEvent* event)
528{
529    const QModelIndex selection = firstIndex(selectedIndexes());
530
531    // If Control is pressed, expand or collapse the selected entry.
532    if(event->modifiers().testFlag(Qt::ControlModifier) && selection.isValid())
533    {
534        if(event->delta() > 0)
535        {
536            collapse(selection);
537        }
538        else
539        {
540            expand(selection);
541        }
542
543        // Fall through when Shift is also pressed.
544        if(!event->modifiers().testFlag(Qt::ShiftModifier))
545        {
546            event->accept();
547            return;
548        }
549    }
550
551    // If Shift is pressed, move the selected entry up and down.
552    if(event->modifiers().testFlag(Qt::ShiftModifier) && selection.isValid())
553    {
554        QModelIndex sibling;
555
556        if(event->delta() > 0)
557        {
558            sibling = indexAbove(selection);
559        }
560        else
561        {
562            sibling = indexBelow(selection);
563        }
564
565        if(sibling.isValid())
566        {
567            setCurrentIndex(sibling);
568        }
569
570        event->accept();
571        return;
572    }
573
574    QTreeView::wheelEvent(event);
575}
576
577void TreeView::contextMenuEvent(QContextMenuEvent* event)
578{
579    QTreeView::contextMenuEvent(event);
580
581    if(!event->isAccepted())
582    {
583        QMenu menu;
584
585        const QAction* expandAllAction = menu.addAction(tr("&Expand all"));
586        const QAction* collapseAllAction = menu.addAction(tr("&Collapse all"));
587
588        const QAction* action = menu.exec(event->globalPos());
589
590        if(action == expandAllAction)
591        {
592            expandAll(indexAt(event->pos()));
593        }
594        else if(action == collapseAllAction)
595        {
596            collapseAll(indexAt(event->pos()));
597        }
598    }
599}
600
601void TreeView::on_expanded(const QModelIndex& index)
602{
603    model()->setData(index, true, m_expansionRole);
604}
605
606void TreeView::on_collapsed(const QModelIndex& index)
607{
608    model()->setData(index, false, m_expansionRole);
609}
610
611LineEdit::LineEdit(QWidget* parent) : QLineEdit(parent)
612{
613}
614
615void LineEdit::mousePressEvent(QMouseEvent* event)
616{
617    QLineEdit::mousePressEvent(event);
618
619    selectAll();
620}
621
622ComboBox::ComboBox(QWidget* parent) : QComboBox(parent)
623{
624    setLineEdit(new LineEdit(this));
625}
626
627SpinBox::SpinBox(QWidget* parent) : QSpinBox(parent)
628{
629    setLineEdit(new LineEdit(this));
630}
631
632void SpinBox::keyPressEvent(QKeyEvent* event)
633{
634    QSpinBox::keyPressEvent(event);
635
636    if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
637    {
638        emit returnPressed();
639    }
640}
641
642MappingSpinBox::MappingSpinBox(TextValueMapper* mapper, QWidget* parent) : SpinBox(parent),
643    m_mapper(mapper)
644{
645}
646
647QString MappingSpinBox::textFromValue(int val) const
648{
649    bool ok = false;
650    QString text = m_mapper->textFromValue(val, ok);
651
652    if(!ok)
653    {
654        text = SpinBox::textFromValue(val);
655    }
656
657    return text;
658}
659
660int MappingSpinBox::valueFromText(const QString& text) const
661{
662    bool ok = false;
663    int val = m_mapper->valueFromText(text, ok);
664
665    if(!ok)
666    {
667        val = SpinBox::valueFromText(text);
668    }
669
670    return val;
671}
672
673QValidator::State MappingSpinBox::validate(QString& input, int& pos) const
674{
675    Q_UNUSED(input);
676    Q_UNUSED(pos);
677
678    return QValidator::Acceptable;
679}
680
681int getMappedNumber(MappingSpinBox::TextValueMapper* mapper,
682                    QWidget* parent, const QString& title, const QString& caption,
683                    int value, int min, int max, bool* ok, Qt::WindowFlags flags)
684{
685    QDialog* dialog = new QDialog(parent, flags | Qt::MSWindowsFixedSizeDialogHint);
686    dialog->setWindowTitle(title);
687
688    QLabel* label = new QLabel(dialog);
689    label->setText(caption);
690
691    MappingSpinBox* mappingSpinBox = new MappingSpinBox(mapper, dialog);
692    mappingSpinBox->setRange(min, max);
693    mappingSpinBox->setValue(value);
694
695    QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, dialog);
696    QObject::connect(dialogButtonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
697    QObject::connect(dialogButtonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
698
699    dialog->setLayout(new QVBoxLayout(dialog));
700    dialog->layout()->addWidget(label);
701    dialog->layout()->addWidget(mappingSpinBox);
702    dialog->layout()->addWidget(dialogButtonBox);
703
704    dialog->setFocusProxy(mappingSpinBox);
705
706    const int dialogResult = dialog->exec();
707    const int number = mappingSpinBox->value();
708
709    delete dialog;
710
711    if(ok)
712    {
713        *ok = dialogResult == QDialog::Accepted;
714    }
715
716    return number;
717}
718
719ProgressLineEdit::ProgressLineEdit(QWidget* parent) : QLineEdit(parent),
720    m_progress(0)
721{   
722}
723
724int ProgressLineEdit::progress() const
725{
726    return m_progress;
727}
728
729void ProgressLineEdit::setProgress(int progress)
730{
731    if(m_progress != progress && progress >= 0 && progress <= 100)
732    {
733        m_progress = progress;
734
735        update();
736    }
737}
738
739void ProgressLineEdit::paintEvent(QPaintEvent* event)
740{
741    QLineEdit::paintEvent(event);
742
743    QPainter painter(this);
744
745    QRect highlightedRect = rect();
746    highlightedRect.setWidth(m_progress * highlightedRect.width() / 100);
747
748    painter.setCompositionMode(QPainter::CompositionMode_Multiply);
749    painter.fillRect(highlightedRect, palette().highlight());
750}
751
752void ProgressLineEdit::keyPressEvent(QKeyEvent* event)
753{
754    QLineEdit::keyPressEvent(event);
755
756    if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
757    {
758        emit returnPressed(event->modifiers());
759    }
760}
761
762SearchLineEdit::SearchLineEdit(QWidget* parent) : ProgressLineEdit(parent)
763{
764    m_timer = new QTimer(this);
765
766    m_timer->setInterval(2000);
767    m_timer->setSingleShot(true);
768
769    connect(this, SIGNAL(textEdited(QString)), m_timer, SLOT(start()));
770    connect(this, SIGNAL(returnPressed(Qt::KeyboardModifiers)), SLOT(on_returnPressed(Qt::KeyboardModifiers)));
771    connect(m_timer, SIGNAL(timeout()), SLOT(on_timeout()));
772}
773
774void SearchLineEdit::startSearch()
775{
776    QTimer::singleShot(0, this, SLOT(on_timeout()));
777}
778
779void SearchLineEdit::startTimer()
780{
781    m_timer->start();
782}
783
784void SearchLineEdit::stopTimer()
785{
786    m_timer->stop();
787}
788
789void SearchLineEdit::on_timeout()
790{
791    emit searchInitiated(text());
792}
793
794void SearchLineEdit::on_returnPressed(const Qt::KeyboardModifiers& modifiers)
795{
796    stopTimer();
797
798    emit searchInitiated(text(), modifiers == Qt::ShiftModifier);
799}
800
801} // qpdfview
Note: See TracBrowser for help on using the repository browser.