00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "panel.h"
00021
00022 #include <limits>
00023
00024 #include <QApplication>
00025 #include <QGraphicsLinearLayout>
00026 #include <QPainter>
00027 #include <QBitmap>
00028 #include <QDesktopWidget>
00029 #include <QGridLayout>
00030 #include <QLabel>
00031 #include <QComboBox>
00032 #include <QAction>
00033 #include <QGraphicsLayout>
00034 #include <QGraphicsSceneDragDropEvent>
00035
00036
00037 #include <KDebug>
00038 #include <KIcon>
00039 #include <KDialog>
00040 #include <KIntNumInput>
00041 #include <KMessageBox>
00042
00043 #include <Plasma/Corona>
00044 #include <Plasma/FrameSvg>
00045 #include <Plasma/Theme>
00046 #include <Plasma/View>
00047 #include <Plasma/PaintUtils>
00048
00049 #include <kephal/screens.h>
00050
00051 using namespace Plasma;
00052
00053 class Spacer : public QGraphicsWidget
00054 {
00055 public:
00056 Spacer(QGraphicsWidget *parent)
00057 : QGraphicsWidget(parent)
00058 {
00059 setAcceptDrops(true);
00060 }
00061
00062 ~Spacer()
00063 {}
00064
00065 Panel *panel;
00066
00067 protected:
00068 void dropEvent(QGraphicsSceneDragDropEvent *event)
00069 {
00070 event->setPos(mapToParent(event->pos()));
00071 panel->dropEvent(event);
00072 }
00073
00074 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * widget = 0)
00075 {
00076 Q_UNUSED(option)
00077 Q_UNUSED(widget)
00078
00079
00080 painter->setRenderHint(QPainter::Antialiasing);
00081 QPainterPath p = Plasma::PaintUtils::roundedRectangle(contentsRect().adjusted(1, 1, -2, -2), 4);
00082 QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00083 c.setAlphaF(0.3);
00084
00085 painter->fillPath(p, c);
00086 }
00087 };
00088
00089 Panel::Panel(QObject *parent, const QVariantList &args)
00090 : Containment(parent, args),
00091 m_configureAction(0),
00092 m_addPanelAction(0),
00093 m_currentSize(QSize(Kephal::ScreenUtils::screenSize(screen()).width(), 35)),
00094 m_maskDirty(true),
00095 m_spacerIndex(-1),
00096 m_spacer(0)
00097 {
00098 m_background = new Plasma::FrameSvg(this);
00099 m_background->setImagePath("widgets/panel-background");
00100 m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
00101 connect(m_background, SIGNAL(repaintNeeded()), this, SLOT(backgroundChanged()));
00102 setZValue(150);
00103 setContainmentType(Containment::PanelContainment);
00104 resize(m_currentSize);
00105 setMinimumSize(m_currentSize);
00106 setMaximumSize(m_currentSize);
00107
00108 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
00109 connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)),
00110 this, SLOT(layoutApplet(Plasma::Applet*,QPointF)));
00111 connect(this, SIGNAL(appletRemoved(Plasma::Applet*)),
00112 this, SLOT(appletRemoved(Plasma::Applet*)));
00113 }
00114
00115 Panel::~Panel()
00116 {
00117 }
00118
00119 void Panel::init()
00120 {
00121 Containment::init();
00122
00123
00124
00125 KConfigGroup cg = config("Configuration");
00126
00127 m_currentSize = cg.readEntry("minimumSize", m_currentSize);
00128 if (formFactor() == Plasma::Vertical) {
00129 m_currentSize.expandedTo(QSize(0, 35));
00130 } else {
00131 m_currentSize.expandedTo(QSize(35, 0));
00132 }
00133
00134 setMinimumSize(cg.readEntry("minimumSize", m_currentSize));
00135 setMaximumSize(cg.readEntry("maximumSize", m_currentSize));
00136 setDrawWallpaper(false);
00137 }
00138
00139 QList<QAction*> Panel::contextualActions()
00140 {
00141 if (!m_configureAction) {
00142 m_configureAction = new QAction(i18n("Panel Settings"), this);
00143 m_configureAction->setIcon(KIcon("configure"));
00144 connect(m_configureAction, SIGNAL(triggered()), this, SIGNAL(toolBoxToggled()));
00145
00146 m_addPanelAction = new QAction(i18n("Add Panel"), this);
00147 connect(m_addPanelAction, SIGNAL(triggered(bool)), this, SLOT(addPanel()));
00148 m_addPanelAction->setIcon(KIcon("list-add"));
00149 constraintsEvent(Plasma::ImmutableConstraint);
00150 }
00151
00152 QList<QAction*> actions;
00153 actions << action("add widgets") << m_addPanelAction << action("lock widgets") << m_configureAction << action("remove");
00154 return actions;
00155 }
00156
00157 void Panel::backgroundChanged()
00158 {
00159 constraintsEvent(Plasma::LocationConstraint);
00160 }
00161
00162 void Panel::layoutApplet(Plasma::Applet* applet, const QPointF &pos)
00163 {
00164
00165 QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(layout());
00166
00167 if (!lay) {
00168 return;
00169 }
00170
00171 Plasma::FormFactor f = formFactor();
00172 int insertIndex = -1;
00173
00174
00175 QSizeF appletHint = applet->preferredSize();
00176 QSizeF panelHint = layout()->preferredSize();
00177 if (f == Plasma::Horizontal) {
00178 if (panelHint.width() + appletHint.width() > size().width()) {
00179 resize(panelHint.width() + appletHint.width(), size().height());
00180 }
00181 } else {
00182 if (panelHint.height() + appletHint.height() > size().height()) {
00183 resize(size().width(), panelHint.height() + appletHint.height());
00184 }
00185 }
00186 layout()->setMaximumSize(size());
00187
00188
00189 if (pos != QPoint(-1, -1)) {
00190 for (int i = 0; i < lay->count(); ++i) {
00191 QRectF siblingGeometry = lay->itemAt(i)->geometry();
00192 if (f == Plasma::Horizontal) {
00193 qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
00194 if (pos.x() < middle) {
00195 insertIndex = i;
00196 break;
00197 } else if (pos.x() <= siblingGeometry.right()) {
00198 insertIndex = i + 1;
00199 break;
00200 }
00201 } else {
00202 qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
00203 if (pos.y() < middle) {
00204 insertIndex = i;
00205 break;
00206 } else if (pos.y() <= siblingGeometry.bottom()) {
00207 insertIndex = i + 1;
00208 break;
00209 }
00210 }
00211 }
00212 }
00213
00214 if (insertIndex == -1) {
00215 lay->addItem(applet);
00216 } else {
00217 lay->insertItem(insertIndex, applet);
00218 }
00219
00220 connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize()));
00221 }
00222
00223 void Panel::appletRemoved(Plasma::Applet* applet)
00224 {
00225 QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(layout());
00226 lay->removeItem(applet);
00227
00228
00229 if (formFactor() == Plasma::Horizontal) {
00230 resize(size().width() - applet->size().width(), size().height());
00231 } else {
00232 resize(size().width(), size().height() - applet->size().height());
00233 }
00234 layout()->setMaximumSize(size());
00235 }
00236
00237 void Panel::updateSize()
00238 {
00239 Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(sender());
00240
00241 if (applet) {
00242 if (formFactor() == Plasma::Horizontal) {
00243 const int delta = applet->preferredWidth() - applet->size().width();
00244
00245
00246 if (delta != 0) {
00247 setPreferredWidth(preferredWidth() + delta);
00248 }
00249 } else if (formFactor() == Plasma::Vertical) {
00250 const int delta = applet->preferredHeight() - applet->size().height();
00251 if (delta != 0) {
00252 setPreferredHeight(preferredHeight() + delta);
00253 }
00254 }
00255
00256 resize(preferredSize());
00257 }
00258 }
00259
00260 void Panel::addPanel()
00261 {
00262 if (corona()) {
00263 Containment* panel = corona()->addContainment("panel");
00264 panel->showConfigurationInterface();
00265
00266 panel->setScreen(screen());
00267
00268 QList<Plasma::Location> freeEdges = corona()->freeEdges(screen());
00269 kDebug() << freeEdges;
00270 Plasma::Location destination;
00271 if (freeEdges.contains(Plasma::TopEdge)) {
00272 destination = Plasma::TopEdge;
00273 } else if (freeEdges.contains(Plasma::BottomEdge)) {
00274 destination = Plasma::BottomEdge;
00275 } else if (freeEdges.contains(Plasma::LeftEdge)) {
00276 destination = Plasma::LeftEdge;
00277 } else if (freeEdges.contains(Plasma::RightEdge)) {
00278 destination = Plasma::RightEdge;
00279 } else destination = Plasma::TopEdge;
00280
00281 panel->setLocation(destination);
00282
00283
00284
00285 panel->updateConstraints(Plasma::StartupCompletedConstraint);
00286 panel->flushPendingConstraintsEvents();
00287
00288 if (destination == Plasma::LeftEdge ||
00289 destination == Plasma::RightEdge) {
00290 panel->setMinimumSize(10, 35);
00291 panel->setMaximumSize(35,Kephal::ScreenUtils::screenSize(screen()).height());
00292 panel->resize(QSize(35, Kephal::ScreenUtils::screenSize(screen()).height()));
00293 }
00294 }
00295 }
00296
00297 void Panel::updateBorders(const QRect &geom)
00298 {
00299 Plasma::Location loc = location();
00300 FrameSvg::EnabledBorders enabledBorders = FrameSvg::AllBorders;
00301
00302 int s = screen();
00303
00304
00305 qreal topHeight = m_background->marginSize(Plasma::TopMargin);
00306 qreal bottomHeight = m_background->marginSize(Plasma::BottomMargin);
00307 qreal leftWidth = m_background->marginSize(Plasma::LeftMargin);
00308 qreal rightWidth = m_background->marginSize(Plasma::RightMargin);
00309
00310
00311 if (s < 0) {
00312
00313 } else if (loc == BottomEdge || loc == TopEdge) {
00314 QRect r = Kephal::ScreenUtils::screenGeometry(s);
00315
00316 if (loc == BottomEdge) {
00317 enabledBorders ^= FrameSvg::BottomBorder;
00318 bottomHeight = 0;
00319 } else {
00320 enabledBorders ^= FrameSvg::TopBorder;
00321 topHeight = 0;
00322 }
00323
00324 if (geom.x() <= r.x()) {
00325 enabledBorders ^= FrameSvg::LeftBorder;
00326 leftWidth = 0;
00327 }
00328 if (geom.right() >= r.right()) {
00329 enabledBorders ^= FrameSvg::RightBorder;
00330 rightWidth = 0;
00331 }
00332
00333
00334 } else if (loc == LeftEdge || loc == RightEdge) {
00335 QRect r = Kephal::ScreenUtils::screenGeometry(s);
00336
00337 if (loc == RightEdge) {
00338 enabledBorders ^= FrameSvg::RightBorder;
00339 rightWidth = 0;
00340 } else {
00341 enabledBorders ^= FrameSvg::LeftBorder;
00342 leftWidth = 0;
00343 }
00344 if (geom.y() <= r.y()) {
00345 enabledBorders ^= FrameSvg::TopBorder;
00346 topHeight = 0;
00347 }
00348 if (geom.bottom() >= r.bottom()) {
00349 enabledBorders ^= FrameSvg::BottomBorder;
00350 bottomHeight = 0;
00351 }
00352
00353
00354 } else {
00355 kDebug() << "no location!?";
00356 }
00357
00358
00359 m_background->setEnabledBorders(enabledBorders);
00360 m_background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00361
00362
00363 const QGraphicsItem *box = toolBoxItem();
00364 if (box && immutability() == Mutable) {
00365 QSizeF s = box->boundingRect().size();
00366 if (formFactor() == Vertical) {
00367
00368 bottomHeight += s.height();;
00369
00370 } else {
00371 if (QApplication::layoutDirection() == Qt::RightToLeft) {
00372 leftWidth += s.width();
00373 } else {
00374 rightWidth += s.width();
00375 }
00376 }
00377 }
00378
00379
00380 if (layout()) {
00381 switch (location()) {
00382 case LeftEdge:
00383 rightWidth = qMin(rightWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium));
00384 break;
00385 case RightEdge:
00386 leftWidth = qMin(leftWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium));
00387 break;
00388 case TopEdge:
00389 bottomHeight = qMin(bottomHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium));
00390 break;
00391 case BottomEdge:
00392 topHeight = qMin(topHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium));
00393 break;
00394 default:
00395 break;
00396 }
00397 layout()->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00398 layout()->invalidate();
00399 }
00400
00401 update();
00402 }
00403
00404 void Panel::constraintsEvent(Plasma::Constraints constraints)
00405 {
00406 kDebug() << "constraints updated with" << constraints << "!!!!!!";
00407
00408 m_maskDirty = true;
00409
00410 if (constraints & Plasma::FormFactorConstraint) {
00411 Plasma::FormFactor form = formFactor();
00412 Qt::Orientation layoutDirection = form == Plasma::Vertical ? Qt::Vertical : Qt::Horizontal;
00413
00414 if (layout()) {
00415 QGraphicsLayout *lay = layout();
00416 QGraphicsLinearLayout * linearLay = dynamic_cast<QGraphicsLinearLayout *>(lay);
00417 if (linearLay) {
00418 linearLay->setOrientation(layoutDirection);
00419 }
00420 linearLay->setMaximumSize(size());
00421 } else {
00422 QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
00423 lay->setOrientation(layoutDirection);
00424 lay->setContentsMargins(0, 0, 0, 0);
00425 lay->setSpacing(4);
00426 lay->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
00427 setLayout(lay);
00428 updateBorders(geometry().toRect());
00429
00430 foreach (Applet *applet, applets()) {
00431 lay->addItem(applet);
00432 }
00433
00434 lay->setMaximumSize(size());
00435 }
00436 }
00437
00438
00439 if (constraints & Plasma::LocationConstraint || constraints & Plasma::SizeConstraint) {
00440 m_currentSize = geometry().size().toSize();
00441 QRectF screenRect = screen() >= 0 ? Kephal::ScreenUtils::screenGeometry(screen()) :
00442 geometry();
00443
00444 if ((formFactor() == Horizontal && m_currentSize.width() >= screenRect.width()) ||
00445 (formFactor() == Vertical && m_currentSize.height() >= screenRect.height())) {
00446 m_background->setElementPrefix(location());
00447 } else {
00448 switch (location()) {
00449 case LeftEdge:
00450
00451 m_background->setElementPrefix("west-mini");
00452 break;
00453 case RightEdge:
00454 m_background->setElementPrefix("east-mini");
00455 break;
00456 case TopEdge:
00457 m_background->setElementPrefix("north-mini");
00458 break;
00459 case BottomEdge:
00460 default:
00461 m_background->setElementPrefix("south-mini");
00462 break;
00463 }
00464 }
00465
00466 m_background->resizeFrame(m_currentSize);
00467 }
00468
00469
00470
00471
00472 if (layout() && (constraints & Plasma::SizeConstraint)) {
00473 layout()->setMaximumSize(size());
00474 }
00475
00476 if (constraints & Plasma::LocationConstraint) {
00477 setFormFactorFromLocation(location());
00478 }
00479
00480 if (constraints & Plasma::ImmutableConstraint) {
00481 bool unlocked = immutability() == Plasma::Mutable;
00482
00483 if (m_addPanelAction) {
00484 m_addPanelAction->setEnabled(unlocked);
00485 m_addPanelAction->setVisible(unlocked);
00486 }
00487
00488 if (m_configureAction) {
00489 m_configureAction->setEnabled(unlocked);
00490 m_configureAction->setVisible(unlocked);
00491 }
00492
00493 QGraphicsView *panelView = view();
00494 if (panelView) {
00495 updateBorders(panelView->geometry());
00496 }
00497 }
00498 }
00499
00500 void Panel::saveState(KConfigGroup &config) const
00501 {
00502 config.writeEntry("minimumSize", minimumSize());
00503 config.writeEntry("maximumSize", maximumSize());
00504 }
00505
00506 void Panel::themeUpdated()
00507 {
00508
00509
00510
00511 qreal oldLeftWidth;
00512 qreal newLeftWidth;
00513 qreal oldTopHeight;
00514 qreal newTopHeight;
00515 qreal oldRightWidth;
00516 qreal newRightWidth;
00517 qreal oldBottomHeight;
00518 qreal newBottomHeight;
00519
00520 layout()->getContentsMargins(&oldLeftWidth, &oldTopHeight, &oldRightWidth, &oldBottomHeight);
00521 m_background->getMargins(newLeftWidth, newTopHeight, newRightWidth, newBottomHeight);
00522
00523 QSize newSize(size().width()-(oldLeftWidth - newLeftWidth)-(oldRightWidth - newRightWidth),
00524 size().height()-(oldTopHeight - newTopHeight)-(oldBottomHeight - newBottomHeight));
00525
00526 resize(newSize);
00527
00528 if (formFactor() == Plasma::Vertical) {
00529 setMaximumWidth(newSize.width());
00530 setMinimumWidth(newSize.width());
00531 } else {
00532 setMaximumHeight(newSize.height());
00533 setMinimumHeight(newSize.height());
00534 }
00535
00536 updateBorders(geometry().toRect());
00537 }
00538
00539 void Panel::paintInterface(QPainter *painter,
00540 const QStyleOptionGraphicsItem *option,
00541 const QRect& contentsRect)
00542 {
00543 Q_UNUSED(contentsRect)
00544
00545
00546 painter->save();
00547 painter->resetTransform();
00548
00549 const Containment::StyleOption *containmentOpt = qstyleoption_cast<const Containment::StyleOption *>(option);
00550
00551 QRect viewGeom;
00552 if (containmentOpt) {
00553 viewGeom = containmentOpt->view->geometry();
00554 }
00555
00556 if (m_maskDirty || m_lastViewGeom != viewGeom) {
00557 m_maskDirty = false;
00558 m_lastViewGeom = viewGeom;
00559
00560 updateBorders(viewGeom);
00561 if (containmentOpt && containmentOpt->view) {
00562 containmentOpt->view->setMask(m_background->mask());
00563 }
00564 }
00565
00566
00567 painter->setCompositionMode(QPainter::CompositionMode_Source);
00568 painter->setRenderHint(QPainter::Antialiasing);
00569
00570 m_background->paintFrame(painter, option->exposedRect);
00571
00572
00573 painter->restore();
00574 }
00575
00576 void Panel::setFormFactorFromLocation(Plasma::Location loc) {
00577 switch (loc) {
00578 case BottomEdge:
00579 case TopEdge:
00580
00581 setFormFactor(Plasma::Horizontal);
00582 break;
00583 case RightEdge:
00584 case LeftEdge:
00585
00586 setFormFactor(Plasma::Vertical);
00587 break;
00588 case Floating:
00589
00590 kDebug() << "Floating is unimplemented.";
00591 break;
00592 default:
00593 kDebug() << "invalid location!!";
00594 }
00595 }
00596
00597 void Panel::showDropZone(const QPoint pos)
00598 {
00599 if (!scene()) {
00600 return;
00601 }
00602
00603
00604
00605 if (((formFactor() == Plasma::Vertical && pos.y() > 1 && pos.y() > size().height() - 2) ||
00606 (pos.x() > 1 && pos.x() < size().width() - 2)) &&
00607 scene()->itemAt(mapToScene(pos)) != this) {
00608 return;
00609 }
00610
00611 QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(layout());
00612
00613 if (!lay) {
00614 return;
00615 }
00616
00617 if (pos == QPoint()) {
00618 if (m_spacer) {
00619 lay->removeItem(m_spacer);
00620 m_spacer->hide();
00621 }
00622 return;
00623 }
00624
00625
00626 if (m_spacer && m_spacer->geometry().contains(pos)) {
00627 return;
00628 }
00629
00630 Plasma::FormFactor f = formFactor();
00631 int insertIndex = -1;
00632
00633
00634 for (int i = 0; i < lay->count(); ++i) {
00635 QRectF siblingGeometry = lay->itemAt(i)->geometry();
00636
00637 if (f == Plasma::Horizontal) {
00638 qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
00639 if (pos.x() < middle) {
00640 insertIndex = i;
00641 break;
00642 } else if (pos.x() <= siblingGeometry.right()) {
00643 insertIndex = i + 1;
00644 break;
00645 }
00646 } else {
00647 qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
00648 if (pos.y() < middle) {
00649 insertIndex = i;
00650 break;
00651 } else if (pos.y() <= siblingGeometry.bottom()) {
00652 insertIndex = i + 1;
00653 break;
00654 }
00655 }
00656 }
00657
00658 m_spacerIndex = insertIndex;
00659 if (insertIndex != -1) {
00660 if (!m_spacer) {
00661 m_spacer = new Spacer(this);
00662 m_spacer->panel = this;
00663 }
00664 lay->removeItem(m_spacer);
00665 m_spacer->show();
00666 lay->insertItem(insertIndex, m_spacer);
00667 }
00668 }
00669
00670
00671 K_EXPORT_PLASMA_APPLET(panel, Panel)
00672
00673 #include "panel.moc"
00674