1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2  * (c)LGPL2+
3  *
4  * LXQt - a lightweight, Qt based, desktop toolset
5  * https://lxqt.org
6  *
7  * Copyright: 2011-2013 Razor team
8  * Authors:
9  *   Petr Vanek <petr@scribus.info>
10  *   Alexander Sokoloff <sokoloff.a@gmail.com>
11  *
12  * This program or library is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21 
22  * You should have received a copy of the GNU Lesser General
23  * Public License along with this library; if not, write to the
24  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301 USA
26  *
27  * END_COMMON_COPYRIGHT_HEADER */
28 
29 #include "popup.h"
30 #include "../panel/ilxqtpanelplugin.h"
31 
32 #include <QDesktopWidget>
33 #include <QVBoxLayout>
34 #include <QTimer>
35 #include <Solid/StorageAccess>
36 #include <Solid/StorageDrive>
37 #include <Solid/DeviceNotifier>
38 
39 // Paulo: I'm not sure what this is for
hasRemovableParent(Solid::Device device)40 static bool hasRemovableParent(Solid::Device device)
41 {
42     // qDebug() << "acess:" << device.udi();
43     for ( ; !device.udi().isEmpty(); device = device.parent())
44     {
45         Solid::StorageDrive* drive = device.as<Solid::StorageDrive>();
46         if (drive && drive->isRemovable())
47         {
48             // qDebug() << "removable parent drive:" << device.udi();
49             return true;
50         }
51     }
52     return false;
53 }
54 
Popup(ILXQtPanelPlugin * plugin,QWidget * parent)55 Popup::Popup(ILXQtPanelPlugin * plugin, QWidget* parent):
56     QDialog(parent,  Qt::Window | Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint | Qt::Popup | Qt::X11BypassWindowManagerHint),
57     mPlugin(plugin),
58     mPlaceholder(nullptr),
59     mDisplayCount(0)
60 {
61     setObjectName(QStringLiteral("LXQtMountPopup"));
62     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
63     setLayout(new QVBoxLayout(this));
64     layout()->setMargin(0);
65 
66     setAttribute(Qt::WA_AlwaysShowToolTips);
67 
68     mPlaceholder = new QLabel(tr("No devices are available"), this);
69     mPlaceholder->setObjectName(QStringLiteral("NoDiskLabel"));
70     layout()->addWidget(mPlaceholder);
71 
72     //Perform the potential long time operation after object construction
73     //Note: can't use QTimer::singleShot with lambda in pre QT 5.4 code
74     QTimer * aux_timer = new QTimer;
75     connect(aux_timer, &QTimer::timeout, this, [this, aux_timer] {
76         delete aux_timer; //cleanup
77         const auto devices = Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess);
78         for (const Solid::Device& device : devices)
79             if (hasRemovableParent(device))
80                 addItem(device);
81     });
82     aux_timer->setSingleShot(true);
83     aux_timer->start(0);
84 
85     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded,
86             this, &Popup::onDeviceAdded);
87     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved,
88             this, &Popup::onDeviceRemoved);
89 }
90 
showHide()91 void Popup::showHide()
92 {
93     if (isHidden())
94     {
95         mPlugin->willShowWindow(this);
96         show();
97     } else
98         close();
99 }
100 
onDeviceAdded(QString const & udi)101 void Popup::onDeviceAdded(QString const & udi)
102 {
103     Solid::Device device(udi);
104     if (device.is<Solid::StorageAccess>() && hasRemovableParent(device))
105         addItem(device);
106 }
107 
onDeviceRemoved(QString const & udi)108 void Popup::onDeviceRemoved(QString const & udi)
109 {
110     MenuDiskItem* item = nullptr;
111     const int size = layout()->count() - 1;
112     for (int i = size; 0 <= i; --i)
113     {
114         QWidget *w = layout()->itemAt(i)->widget();
115         if (w == mPlaceholder)
116             continue;
117 
118         MenuDiskItem *it = static_cast<MenuDiskItem *>(w);
119         if (udi == it->deviceUdi())
120         {
121             item = it;
122             break;
123         }
124     }
125 
126     if (item != nullptr)
127     {
128         layout()->removeWidget(item);
129         item->deleteLater();
130 
131         --mDisplayCount;
132         if (mDisplayCount == 0)
133             mPlaceholder->show();
134 
135         emit deviceRemoved(Solid::Device{udi});
136     }
137 }
138 
showEvent(QShowEvent * event)139 void Popup::showEvent(QShowEvent *event)
140 {
141     mPlaceholder->setVisible(mDisplayCount == 0);
142     realign();
143     setFocus();
144     activateWindow();
145     QWidget::showEvent(event);
146     emit visibilityChanged(true);
147 }
148 
hideEvent(QHideEvent * event)149 void Popup::hideEvent(QHideEvent *event)
150 {
151     QWidget::hideEvent(event);
152     emit visibilityChanged(false);
153 }
154 
addItem(Solid::Device device)155 void Popup::addItem(Solid::Device device)
156 {
157     MenuDiskItem *item = new MenuDiskItem(device, this);
158     connect(item, &MenuDiskItem::invalid, this, &Popup::onDeviceRemoved);
159     item->setVisible(true);
160     layout()->addWidget(item);
161 
162     mDisplayCount++;
163     if (mDisplayCount != 0)
164         mPlaceholder->hide();
165 
166     if (isVisible())
167         realign();
168 
169     emit deviceAdded(device);
170 }
171 
realign()172 void Popup::realign()
173 {
174     adjustSize();
175     setGeometry(mPlugin->calculatePopupWindowPos(sizeHint()));
176 }
177