File indexing completed on 2024-10-13 04:22:15

0001 /*
0002     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
0003     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "k3bwelcomewidget.h"
0009 #include "k3b.h"
0010 #include "k3bapplication.h"
0011 #include "k3bflatbutton.h"
0012 #include "k3bstdguiitems.h"
0013 #include "k3bthememanager.h"
0014 #include "k3bversion.h"
0015 
0016 #include <KConfigGroup>
0017 #include <KAboutData>
0018 #include <KIconLoader>
0019 #include <KLocalizedString>
0020 #include <KActionCollection>
0021 
0022 #include <QMimeData>
0023 #include <QUrl>
0024 #include <QIcon>
0025 #include <QCursor>
0026 #include <QDragEnterEvent>
0027 #include <QDropEvent>
0028 #include <QMouseEvent>
0029 #include <QPainter>
0030 #include <QPaintEvent>
0031 #include <QResizeEvent>
0032 #include <QShowEvent>
0033 #include <QTextDocument>
0034 #include <QMenu>
0035 #include <QStyle>
0036 
0037 namespace {
0038 
0039 const char* s_allActions[] = {
0040     "file_new_data",
0041     "file_continue_multisession",
0042     "_sep_",
0043     "file_new_audio",
0044     "file_new_mixed",
0045     "_sep_",
0046     "file_new_vcd",
0047     "file_new_video_dvd",
0048     "_sep_",
0049     "file_new_movix",
0050     "_sep_",
0051     "tools_copy_medium",
0052     "tools_format_medium",
0053     "tools_write_image",
0054     "_sep_",
0055     "tools_cdda_rip",
0056     "tools_videocd_rip",
0057     "tools_videodvd_rip",
0058     0
0059 };
0060 
0061 const int MARGIN = 20;
0062 const int HEADER_BUTTON_SPACING = 10;
0063 const int BUTTON_SPACING = 4;
0064 
0065 } // namespace
0066 
0067 K3b::WelcomeWidget::WelcomeWidget( MainWindow* mainWindow, QWidget* parent )
0068     : QWidget( parent ),
0069       m_mainWindow( mainWindow )
0070 {
0071     m_header = new QTextDocument( this );
0072     m_infoText = new QTextDocument( this );
0073 
0074     setAcceptDrops( true );
0075     setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
0076 
0077     m_rows = m_cols = 1;
0078 
0079     m_buttonMore = new K3b::FlatButton( i18n("More actions..."), this );
0080 
0081     connect( m_buttonMore, SIGNAL(pressed()), this, SLOT(slotMoreActions()) );
0082     connect( k3bappcore->themeManager(), SIGNAL(themeChanged()), this, SLOT(slotThemeChanged()) );
0083 
0084     slotThemeChanged();
0085 }
0086 
0087 
0088 K3b::WelcomeWidget::~WelcomeWidget()
0089 {
0090 }
0091 
0092 
0093 void K3b::WelcomeWidget::addAction( QAction* action )
0094 {
0095     if( action ) {
0096         m_actions.append(action);
0097         rebuildGui();
0098     }
0099 }
0100 
0101 
0102 void K3b::WelcomeWidget::removeAction( QAction* action )
0103 {
0104     if( action ) {
0105         m_actions.removeAll( action );
0106         rebuildGui();
0107     }
0108 }
0109 
0110 
0111 void K3b::WelcomeWidget::removeButton( K3b::FlatButton* b )
0112 {
0113     removeAction( m_buttonMap[b] );
0114 }
0115 
0116 
0117 void K3b::WelcomeWidget::rebuildGui( const QList<QAction*>& actions )
0118 {
0119     m_actions = actions;
0120     rebuildGui();
0121 }
0122 
0123 
0124 static void calculateButtons( int width, int numActions, int buttonWidth, int& cols, int& rows )
0125 {
0126     // always try to avoid horizontal scrollbars
0127     int wa = width - 2*MARGIN;
0128     cols = qMax( 1, qMin( wa / (buttonWidth+BUTTON_SPACING), numActions ) );
0129     rows = numActions/cols;
0130     int over = numActions%cols;
0131     if( over ) {
0132         rows++;
0133         // try to avoid useless cols
0134         while( over && cols - over - 1 >= rows-1 ) {
0135             --cols;
0136             over = numActions%cols;
0137         }
0138     }
0139 }
0140 
0141 
0142 void K3b::WelcomeWidget::rebuildGui()
0143 {
0144     // step 1: delete all old buttons in the buttons QPtrList<K3b::FlatButton>
0145     m_buttonMap.clear();
0146     qDeleteAll( m_buttons );
0147     m_buttons.clear();
0148 
0149     int numActions = m_actions.count();
0150     if( numActions > 0 ) {
0151 
0152         // create buttons
0153         QList<QAction *> items(m_actions);
0154         for( QList<QAction *>::const_iterator it = items.constBegin();
0155             it != items.constEnd(); ++it ) {
0156             QAction* a = *it;
0157             K3b::FlatButton* b = new K3b::FlatButton( a, this );
0158 
0159             m_buttons.append( b );
0160             m_buttonMap.insert( b, a );
0161         }
0162 
0163         // determine the needed button size (since all buttons should be equal in size
0164         // we use the max of all sizes)
0165         m_buttonSize = m_buttons.first()->sizeHint();
0166         for ( int i = 0;i<m_buttons.count();i++ )
0167         {
0168             m_buttonSize = m_buttonSize.expandedTo( m_buttons.at( i )->sizeHint() );
0169         }
0170 
0171         repositionButtons();
0172     }
0173 }
0174 
0175 
0176 void K3b::WelcomeWidget::repositionButtons()
0177 {
0178     // calculate rows and columns
0179     calculateButtons( width(), m_actions.count(), m_buttonSize.width(), m_cols, m_rows );
0180 
0181     int availHor = width() - 2*MARGIN;
0182     int availVert = height() - MARGIN - HEADER_BUTTON_SPACING - ( int )m_header->size().height() - HEADER_BUTTON_SPACING;
0183     availVert -= ( int )m_infoText->size().height() - HEADER_BUTTON_SPACING;
0184     int leftMargin = MARGIN + (availHor - (m_buttonSize.width()+BUTTON_SPACING)*m_cols)/2;
0185     int topOffset = ( int )m_header->size().height() + MARGIN + ( availVert - (m_buttonSize.height()+BUTTON_SPACING)*m_rows - m_buttonMore->height() )/2;
0186 
0187     int row = 0;
0188     int col = 0;
0189 
0190     for ( int i = 0;i<m_buttons.count();i++ )
0191     {
0192         K3b::FlatButton* b = m_buttons.at( i );
0193 
0194         QRect rect( QPoint( leftMargin + (col*(m_buttonSize.width()+BUTTON_SPACING) + 2 ),
0195                             topOffset + (row*(m_buttonSize.height()+BUTTON_SPACING)) + 2 ), m_buttonSize );
0196         b->setGeometry( QStyle::visualRect( layoutDirection(), contentsRect(), rect ) );
0197         b->show();
0198 
0199         col++;
0200         if( col == m_cols ) {
0201             col = 0;
0202             row++;
0203         }
0204     }
0205     if( col > 0 )
0206         ++row;
0207 
0208     QRect rect( leftMargin + 2, topOffset + (row*(m_buttonSize.height()+BUTTON_SPACING)) + 2,
0209                 m_cols*(m_buttonSize.width()+BUTTON_SPACING) - BUTTON_SPACING, m_buttonMore->height() );
0210     m_buttonMore->setGeometry( QStyle::visualRect( layoutDirection(), contentsRect(), rect ) );
0211 
0212     setMinimumHeight( heightForWidth( width() ) );
0213 }
0214 
0215 
0216 int K3b::WelcomeWidget::heightForWidth(int width) const
0217 {
0218     int ow = (int)m_infoText->idealWidth() + 10;
0219     m_infoText->setTextWidth(ow);
0220     int h = (int)m_infoText->size().height();
0221     int cols, rows;
0222     calculateButtons(width, m_actions.count(), m_buttonSize.width(), cols, rows);
0223     int height = MARGIN +
0224                  m_header->size().toSize().height() +
0225                  HEADER_BUTTON_SPACING +
0226                  ((m_buttonSize.height() + BUTTON_SPACING) * rows) + m_buttonMore->height() +
0227                  HEADER_BUTTON_SPACING + h + MARGIN;
0228     return height;
0229 }
0230 
0231 
0232 bool K3b::WelcomeWidget::event( QEvent *event )
0233 {
0234     if( event->type() == QEvent::StyleChange ) {
0235         update();
0236     }
0237     return QWidget::event( event );
0238 }
0239 
0240 
0241 void K3b::WelcomeWidget::resizeEvent( QResizeEvent* e )
0242 {
0243     m_infoText->setTextWidth( width() - MARGIN );
0244     QWidget::resizeEvent(e);
0245     repositionButtons();
0246     if( e->size() != m_bgPixmap.size() )
0247         updateBgPix();
0248 }
0249 
0250 
0251 void K3b::WelcomeWidget::slotThemeChanged()
0252 {
0253     if( K3b::Theme* theme = k3bappcore->themeManager()->currentTheme() ) {
0254 //         if( theme->backgroundMode() == K3b::Theme::BG_SCALE )
0255 //             m_bgImage = theme->pixmap( K3b::Theme::WELCOME_BG ).convertToImage();
0256         m_header->setDefaultStyleSheet( QString("body { font-size: 16pt; font-weight: bold; color: %1 }")
0257                                         .arg(theme->foregroundColor().name()) );
0258         m_infoText->setDefaultStyleSheet( QString("body { color: %1 }")
0259                                           .arg(theme->foregroundColor().name()) );
0260     }
0261 
0262     m_header->setHtml( "<html><body align=\"center\">" + i18n("Welcome to K3b &ndash; The CD, DVD, and Blu-ray Kreator") + "</body></html>" );
0263     m_infoText->setHtml( "<html><body align=\"center\">" 
0264                          + i18n("K3b %1 Copyright &copy; 1998&ndash;2018 K3b authors",
0265                                 KAboutData::applicationData().version())
0266                          + "</body></html>" );
0267     setMinimumWidth( 2*MARGIN + qMax(( int )m_header->idealWidth(), m_buttonSize.width()) );
0268     updateBgPix();
0269     update();
0270 }
0271 
0272 
0273 void K3b::WelcomeWidget::slotMoreActions()
0274 {
0275     QMenu popup;
0276 
0277     for ( int i = 0; s_allActions[i]; ++i ) {
0278         if ( s_allActions[i][0] == '_' ) {
0279             popup.addSeparator();
0280         }
0281         else {
0282             popup.addAction(m_mainWindow->actionCollection()->action( s_allActions[i] ));
0283         }
0284     }
0285 
0286     popup.exec( QCursor::pos() );
0287 }
0288 
0289 
0290 void K3b::WelcomeWidget::updateBgPix()
0291 {
0292     if( K3b::Theme* theme = k3bappcore->themeManager()->currentTheme() ) {
0293         if( theme->backgroundMode() == K3b::Theme::BG_SCALE )
0294             m_bgPixmap = theme->pixmap( K3b::Theme::WELCOME_BG ).scaled( rect().width(), rect().height() );
0295         else
0296             m_bgPixmap = theme->pixmap( K3b::Theme::WELCOME_BG );
0297     }
0298 }
0299 
0300 
0301 void K3b::WelcomeWidget::paintEvent( QPaintEvent* )
0302 {
0303     if( K3b::Theme* theme = k3bappcore->themeManager()->currentTheme() ) {
0304         QPainter p( this );
0305         p.setPen( theme->foregroundColor() );
0306 
0307         // draw the background including first filling with the bg color for transparent images
0308         p.fillRect( rect(), theme->backgroundColor() );
0309         p.drawTiledPixmap( rect(), m_bgPixmap );
0310 
0311         // rect around the header
0312         QRect rect( 10, 10, qMax( ( int )m_header->idealWidth() + MARGIN, width() - MARGIN ), ( int )m_header->size().height() + MARGIN );
0313         p.fillRect( rect, theme->backgroundColor() );
0314         p.drawRect( rect );
0315 
0316         // big rect around the whole thing
0317         p.drawRect( 10, 10, width()-MARGIN, height()-MARGIN );
0318 
0319         // draw the header text
0320         int pos = MARGIN;
0321         pos += qMax( (width()-2*MARGIN-( int )m_header->idealWidth())/2, 0 );
0322         p.save();
0323         p.translate( pos, MARGIN );
0324         m_header->drawContents( &p );
0325         p.restore();
0326 
0327         // draw the info box
0328         //    int boxWidth = MARGIN + m_infoText->widthUsed();
0329         int boxHeight = 10 + ( int )m_infoText->size().height();
0330         QRect infoBoxRect( 10/*qMax( (width()-MARGIN-m_infoText->widthUsed())/2, 10 )*/,
0331                            height()-10-boxHeight,
0332                            width()-MARGIN/*boxWidth*/,
0333                            boxHeight );
0334         p.fillRect( infoBoxRect, theme->backgroundColor() );
0335         p.drawRect( infoBoxRect );
0336         p.save();
0337         p.translate( infoBoxRect.left()+5, infoBoxRect.top()+5 );
0338         m_infoText->drawContents( &p );
0339         p.restore();
0340     }
0341 }
0342 
0343 
0344 void K3b::WelcomeWidget::dragEnterEvent( QDragEnterEvent* event )
0345 {
0346     event->setAccepted( event->mimeData()->hasUrls() );
0347 }
0348 
0349 
0350 void K3b::WelcomeWidget::dropEvent( QDropEvent* e )
0351 {
0352     QList<QUrl> urls;
0353     Q_FOREACH( const QUrl& url, e->mimeData()->urls() )
0354     {
0355         urls.push_back( url );
0356     }
0357 
0358     QMetaObject::invokeMethod( m_mainWindow, "addUrls", Qt::QueuedConnection, Q_ARG( QList<QUrl>, urls ) );
0359 }
0360 
0361 
0362 void K3b::WelcomeWidget::loadConfig( const KConfigGroup& c )
0363 {
0364     QStringList sl = c.readEntry( "welcome_actions", QStringList() );
0365 
0366     if( sl.isEmpty() ) {
0367         sl.append( "file_new_data" );
0368         sl.append( "file_new_audio" );
0369         sl.append( "tools_copy_medium" );
0370     }
0371 
0372     QList<QAction*> actions;
0373     for( QStringList::const_iterator it = sl.constBegin(); it != sl.constEnd(); ++it )
0374         if( QAction* a = m_mainWindow->actionCollection()->action( *it ) )
0375             actions.append(a);
0376 
0377     rebuildGui( actions );
0378 }
0379 
0380 
0381 void K3b::WelcomeWidget::saveConfig( KConfigGroup c )
0382 {
0383     QStringList sl;
0384     QList<QAction *> items(m_actions);
0385     for( QList<QAction *>::const_iterator it = items.constBegin();
0386             it != items.constEnd(); ++it )
0387         sl.append( (*it)->objectName() );
0388 
0389     c.writeEntry( "welcome_actions", sl );
0390 }
0391 
0392 
0393 void K3b::WelcomeWidget::mousePressEvent ( QMouseEvent* e )
0394 {
0395     if( e->button() == Qt::RightButton ) {
0396         QMap<QAction*, QAction*> map;
0397         QMenu addPop;
0398         addPop.setTitle( i18n("Add Button") );
0399 
0400         QAction* firstAction = 0;
0401         for ( int i = 0; s_allActions[i]; ++i ) {
0402             if ( s_allActions[i][0] != '_' ) {
0403                 QAction* a = m_mainWindow->actionCollection()->action( s_allActions[i] );
0404                 if ( a && !m_actions.contains(a) ) {
0405                     QAction* addAction = addPop.addAction( a->icon(), a->text() );
0406                     map.insert( addAction, a );
0407                     if ( !firstAction )
0408                         firstAction = addAction;
0409                 }
0410             }
0411         }
0412 
0413         // menu identifiers in QT are always < 0 (when automatically generated)
0414         // and unique throughout the entire application!
0415         QAction *r = 0;
0416         QAction *removeAction = 0;
0417 
0418         QWidget* widgetAtPos = childAt(e->pos());
0419         if( widgetAtPos && widgetAtPos->inherits( "K3b::FlatButton" ) ) {
0420             QMenu pop;
0421             removeAction = pop.addAction( QIcon::fromTheme("list-remove"), i18n("Remove Button") );
0422             if ( addPop.actions().count() > 0 )
0423                 pop.addMenu( &addPop );
0424             r = pop.exec( e->globalPos() );
0425         }
0426         else {
0427             addPop.insertSection( firstAction, addPop.title() );
0428             r = addPop.exec( e->globalPos() );
0429         }
0430 
0431         if( r != 0 ) {
0432             if( r == removeAction )
0433                 removeButton( static_cast<K3b::FlatButton*>(widgetAtPos) );
0434             else
0435                 addAction( map[r] );
0436         }
0437     }
0438 }
0439 
0440 #include "moc_k3bwelcomewidget.cpp"