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 – The CD, DVD, and Blu-ray Kreator") + "</body></html>" ); 0263 m_infoText->setHtml( "<html><body align=\"center\">" 0264 + i18n("K3b %1 Copyright © 1998–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"