completely separe appletprivate
will be easier then to split with the qgraphicsview version
This commit is contained in:
parent
3a8ffb89c0
commit
2a909445bd
@ -104,7 +104,7 @@ set(plasma_LIB_SRCS
|
||||
datacontainer.cpp
|
||||
dataengine.cpp
|
||||
dataenginemanager.cpp
|
||||
delegate.cpp
|
||||
|
||||
package.cpp
|
||||
packagestructure.cpp
|
||||
paintutils.cpp
|
||||
@ -138,7 +138,8 @@ set(plasma_LIB_SRCS
|
||||
private/wallpaperrenderthread.cpp
|
||||
private/windowpreview.cpp
|
||||
private/windowshadows.cpp
|
||||
private/kineticscroll.cpp
|
||||
private/appletprivate.cpp
|
||||
|
||||
querymatch.cpp
|
||||
remote/accessmanager.cpp
|
||||
remote/accessappletjob.cpp
|
||||
@ -168,7 +169,6 @@ set(plasma_LIB_SRCS
|
||||
tooltipcontent.cpp
|
||||
tooltipmanager.cpp
|
||||
version.cpp
|
||||
view.cpp
|
||||
wallpaper.cpp
|
||||
|
||||
|
||||
@ -189,9 +189,11 @@ set(plasma_LIB_SRCS
|
||||
#FIXME: all these must move into the qgv library
|
||||
private/themedwidgetinterface.cpp
|
||||
widgets/iconwidget.cpp
|
||||
view.cpp
|
||||
)
|
||||
|
||||
set (plasmaqgv_LIB_SRCS
|
||||
delegate.cpp
|
||||
#FIXME: this is duplicated with libplasma because iconwidget requires it!
|
||||
private/themedwidgetinterface.cpp
|
||||
|
||||
@ -218,6 +220,7 @@ set (plasmaqgv_LIB_SRCS
|
||||
private/focusindicator.cpp
|
||||
private/nativetabbar.cpp
|
||||
private/style.cpp
|
||||
private/kineticscroll.cpp
|
||||
|
||||
widgets/label.cpp
|
||||
widgets/scrollbar.cpp
|
||||
|
781
applet.cpp
781
applet.cpp
@ -324,12 +324,6 @@ void Applet::restore(KConfigGroup &group)
|
||||
*/
|
||||
}
|
||||
|
||||
void AppletPrivate::setFocus()
|
||||
{
|
||||
//kDebug() << "setting focus";
|
||||
q->setFocus(Qt::ShortcutFocusReason);
|
||||
}
|
||||
|
||||
void Applet::setFailedToLaunch(bool failed, const QString &reason)
|
||||
{
|
||||
d->failed = failed;
|
||||
@ -395,71 +389,7 @@ bool Applet::destroyed() const
|
||||
return d->transient;
|
||||
}
|
||||
|
||||
void AppletPrivate::selectItemToDestroy()
|
||||
{
|
||||
//FIXME: this will not work nicely with multiple screens and being zoomed out!
|
||||
if (isContainment) {
|
||||
QGraphicsView *view = q->view();
|
||||
if (view && view->transform().isScaling() &&
|
||||
q->scene()->focusItem() != q) {
|
||||
QGraphicsItem *focus = q->scene()->focusItem();
|
||||
|
||||
if (focus) {
|
||||
Containment *toDestroy = dynamic_cast<Containment*>(focus->topLevelItem());
|
||||
|
||||
if (toDestroy) {
|
||||
toDestroy->destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q->destroy();
|
||||
}
|
||||
|
||||
void AppletPrivate::updateRect(const QRectF &rect)
|
||||
{
|
||||
q->update(rect);
|
||||
}
|
||||
|
||||
void AppletPrivate::cleanUpAndDelete()
|
||||
{
|
||||
//kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????";
|
||||
QGraphicsWidget *parent = dynamic_cast<QGraphicsWidget *>(q->parentItem());
|
||||
//it probably won't matter, but right now if there are applethandles, *they* are the parent.
|
||||
//not the containment.
|
||||
|
||||
//is the applet in a containment and does the containment have a layout?
|
||||
//if yes, we remove the applet in the layout
|
||||
if (parent && parent->layout()) {
|
||||
QGraphicsLayout *l = parent->layout();
|
||||
for (int i = 0; i < l->count(); ++i) {
|
||||
if (q == l->itemAt(i)) {
|
||||
l->removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configLoader) {
|
||||
configLoader->setDefaults();
|
||||
}
|
||||
|
||||
resetConfigurationObject();
|
||||
|
||||
if (q->scene()) {
|
||||
if (isContainment) {
|
||||
// prematurely emit our destruction if we are a Containment,
|
||||
// giving Corona a chance to remove this Containment from its collection
|
||||
emit q->QObject::destroyed(q);
|
||||
}
|
||||
|
||||
q->scene()->removeItem(q);
|
||||
}
|
||||
|
||||
q->deleteLater();
|
||||
}
|
||||
|
||||
ConfigLoader *Applet::configScheme() const
|
||||
{
|
||||
@ -1154,56 +1084,6 @@ void Applet::setGlobalShortcut(const KShortcut &shortcut)
|
||||
d->globalShortcutChanged();
|
||||
}
|
||||
|
||||
void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(show)
|
||||
Q_UNUSED(reason)
|
||||
}
|
||||
|
||||
void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(icon)
|
||||
Q_UNUSED(message)
|
||||
Q_UNUSED(buttons)
|
||||
}
|
||||
|
||||
void AppletPrivate::positionMessageOverlay()
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
}
|
||||
|
||||
void AppletPrivate::setBusy(bool busy)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(busy)
|
||||
}
|
||||
|
||||
bool AppletPrivate::isBusy() const
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppletPrivate::updateFailedToLaunch(const QString &reason)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(reason)
|
||||
}
|
||||
|
||||
void AppletPrivate::globalShortcutChanged()
|
||||
{
|
||||
if (!activationAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
|
||||
shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
|
||||
scheduleModificationNotification();
|
||||
//kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
|
||||
}
|
||||
|
||||
KShortcut Applet::globalShortcut() const
|
||||
{
|
||||
if (d->activationAction) {
|
||||
@ -1339,37 +1219,6 @@ void Applet::setHasConfigurationInterface(bool hasInterface)
|
||||
d->hasConfigurationInterface = hasInterface;
|
||||
}
|
||||
|
||||
KActionCollection* AppletPrivate::defaultActions(QObject *parent)
|
||||
{
|
||||
KActionCollection *actions = new KActionCollection(parent);
|
||||
actions->setConfigGroup("Shortcuts-Applet");
|
||||
|
||||
KAction *configAction = actions->addAction("configure");
|
||||
configAction->setAutoRepeat(false);
|
||||
configAction->setText(i18n("Widget Settings"));
|
||||
configAction->setIcon(KIcon("configure"));
|
||||
configAction->setShortcut(KShortcut("alt+d, s"));
|
||||
configAction->setData(AbstractToolBox::ConfigureTool);
|
||||
|
||||
KAction *closeApplet = actions->addAction("remove");
|
||||
closeApplet->setAutoRepeat(false);
|
||||
closeApplet->setText(i18n("Remove this Widget"));
|
||||
closeApplet->setIcon(KIcon("edit-delete"));
|
||||
closeApplet->setShortcut(KShortcut("alt+d, r"));
|
||||
closeApplet->setData(AbstractToolBox::DestructiveTool);
|
||||
|
||||
KAction *runAssociatedApplication = actions->addAction("run associated application");
|
||||
runAssociatedApplication->setAutoRepeat(false);
|
||||
runAssociatedApplication->setText(i18n("Run the Associated Application"));
|
||||
runAssociatedApplication->setIcon(KIcon("system-run"));
|
||||
runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
|
||||
runAssociatedApplication->setVisible(false);
|
||||
runAssociatedApplication->setEnabled(false);
|
||||
runAssociatedApplication->setData(AbstractToolBox::ControlTool);
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
|
||||
{
|
||||
if (watched == this) {
|
||||
@ -1575,212 +1424,6 @@ void Applet::showConfigurationInterface(QWidget *widget)
|
||||
QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this));
|
||||
}
|
||||
|
||||
QString AppletPrivate::configDialogId() const
|
||||
{
|
||||
return QString("%1settings%2").arg(appletId).arg(q->name());
|
||||
}
|
||||
|
||||
QString AppletPrivate::configWindowTitle() const
|
||||
{
|
||||
return i18nc("@title:window", "%1 Settings", q->name());
|
||||
}
|
||||
|
||||
QSet<QString> AppletPrivate::knownCategories()
|
||||
{
|
||||
// this is to trick the tranlsation tools into making the correct
|
||||
// strings for translation
|
||||
QSet<QString> categories = s_customCategories;
|
||||
categories << QString(I18N_NOOP("Accessibility")).toLower()
|
||||
<< QString(I18N_NOOP("Application Launchers")).toLower()
|
||||
<< QString(I18N_NOOP("Astronomy")).toLower()
|
||||
<< QString(I18N_NOOP("Date and Time")).toLower()
|
||||
<< QString(I18N_NOOP("Development Tools")).toLower()
|
||||
<< QString(I18N_NOOP("Education")).toLower()
|
||||
<< QString(I18N_NOOP("Environment and Weather")).toLower()
|
||||
<< QString(I18N_NOOP("Examples")).toLower()
|
||||
<< QString(I18N_NOOP("File System")).toLower()
|
||||
<< QString(I18N_NOOP("Fun and Games")).toLower()
|
||||
<< QString(I18N_NOOP("Graphics")).toLower()
|
||||
<< QString(I18N_NOOP("Language")).toLower()
|
||||
<< QString(I18N_NOOP("Mapping")).toLower()
|
||||
<< QString(I18N_NOOP("Miscellaneous")).toLower()
|
||||
<< QString(I18N_NOOP("Multimedia")).toLower()
|
||||
<< QString(I18N_NOOP("Online Services")).toLower()
|
||||
<< QString(I18N_NOOP("Productivity")).toLower()
|
||||
<< QString(I18N_NOOP("System Information")).toLower()
|
||||
<< QString(I18N_NOOP("Utilities")).toLower()
|
||||
<< QString(I18N_NOOP("Windows and Tasks")).toLower();
|
||||
return categories;
|
||||
}
|
||||
|
||||
KConfigDialog *AppletPrivate::generateGenericConfigDialog()
|
||||
{
|
||||
KConfigSkeleton *nullManager = new KConfigSkeleton(0);
|
||||
KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
|
||||
nullManager->setParent(dialog);
|
||||
dialog->setFaceType(KPageDialog::Auto);
|
||||
dialog->setWindowTitle(configWindowTitle());
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
q->createConfigurationInterface(dialog);
|
||||
dialog->showButton(KDialog::Default, false);
|
||||
dialog->showButton(KDialog::Help, false);
|
||||
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
|
||||
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
|
||||
{
|
||||
addGlobalShortcutsPage(dialog);
|
||||
addPublishPage(dialog);
|
||||
}
|
||||
|
||||
void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
|
||||
{
|
||||
#ifndef PLASMA_NO_GLOBAL_SHORTCUTS
|
||||
if (isContainment) {
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *page = new QWidget;
|
||||
QVBoxLayout *layout = new QVBoxLayout(page);
|
||||
|
||||
if (!shortcutEditor) {
|
||||
shortcutEditor = new KKeySequenceWidget(page);
|
||||
QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
|
||||
}
|
||||
|
||||
shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
|
||||
layout->addWidget(shortcutEditor.data());
|
||||
layout->addStretch();
|
||||
dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
|
||||
|
||||
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
|
||||
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppletPrivate::addPublishPage(KConfigDialog *dialog)
|
||||
{
|
||||
#ifdef ENABLE_REMOTE_WIDGETS
|
||||
QWidget *page = new QWidget;
|
||||
publishUI.setupUi(page);
|
||||
publishUI.publishCheckbox->setChecked(q->isPublished());
|
||||
QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
|
||||
publishUI.allUsersCheckbox->setEnabled(q->isPublished());
|
||||
QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
|
||||
|
||||
QString resourceName =
|
||||
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
|
||||
"%1 on %2", q->name(), QHostInfo::localHostName());
|
||||
if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
|
||||
publishUI.allUsersCheckbox->setChecked(true);
|
||||
} else {
|
||||
publishUI.allUsersCheckbox->setChecked(false);
|
||||
}
|
||||
|
||||
q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
|
||||
q, SLOT(publishCheckboxStateChanged(int)));
|
||||
dialog->addPage(page, i18n("Share"), "applications-internet");
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppletPrivate::publishCheckboxStateChanged(int state)
|
||||
{
|
||||
if (state == Qt::Checked) {
|
||||
publishUI.allUsersCheckbox->setEnabled(true);
|
||||
} else {
|
||||
publishUI.allUsersCheckbox->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::configDialogFinished()
|
||||
{
|
||||
if (shortcutEditor) {
|
||||
QKeySequence sequence = shortcutEditor.data()->keySequence();
|
||||
if (sequence != q->globalShortcut().primary()) {
|
||||
q->setGlobalShortcut(KShortcut(sequence));
|
||||
emit q->configNeedsSaving();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_REMOTE_WIDGETS
|
||||
if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
|
||||
q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
|
||||
|
||||
if (publishUI.publishCheckbox->isChecked()) {
|
||||
QString resourceName =
|
||||
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
|
||||
"%1 on %2", q->name(), QHostInfo::localHostName());
|
||||
q->publish(Plasma::ZeroconfAnnouncement, resourceName);
|
||||
if (publishUI.allUsersCheckbox->isChecked()) {
|
||||
if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
|
||||
AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
|
||||
rule->setPolicy(AuthorizationRule::Allow);
|
||||
rule->setTargets(AuthorizationRule::AllUsers);
|
||||
AuthorizationManager::self()->d->rules.append(rule);
|
||||
}
|
||||
} else {
|
||||
AuthorizationRule *matchingRule =
|
||||
AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
|
||||
if (matchingRule) {
|
||||
AuthorizationManager::self()->d->rules.removeAll(matchingRule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
q->unpublish();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!configLoader) {
|
||||
// the config loader will trigger this for us, so we don't need to.
|
||||
propagateConfigChanged();
|
||||
if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
|
||||
dialog->enableButton(KDialog::Apply, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::updateShortcuts()
|
||||
{
|
||||
if (isContainment) {
|
||||
//a horrible hack to avoid clobbering corona settings
|
||||
//we pull them out, then read, then put them back
|
||||
QList<QString> names;
|
||||
QList<QAction*> qactions;
|
||||
names << "add sibling containment" << "configure shortcuts" << "lock widgets";
|
||||
foreach (const QString &name, names) {
|
||||
QAction *a = actions->action(name);
|
||||
actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
|
||||
qactions << a;
|
||||
}
|
||||
|
||||
actions->readSettings();
|
||||
|
||||
for (int i = 0; i < names.size(); ++i) {
|
||||
QAction *a = qactions.at(i);
|
||||
if (a) {
|
||||
actions->addAction(names.at(i), a);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
actions->readSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::propagateConfigChanged()
|
||||
{
|
||||
if (isContainment) {
|
||||
Containment *c = qobject_cast<Containment *>(q);
|
||||
if (c) {
|
||||
c->d->configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
q->configChanged();
|
||||
}
|
||||
|
||||
void Applet::configChanged()
|
||||
{
|
||||
if (d->script) {
|
||||
@ -1852,49 +1495,6 @@ bool Applet::hasValidAssociatedApplication() const
|
||||
return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
|
||||
}
|
||||
|
||||
void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
|
||||
{
|
||||
KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
|
||||
foreach (const QString &key, constraintGroup.keyList()) {
|
||||
//kDebug() << "security constraint" << key;
|
||||
if (constraintGroup.readEntry(key, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//ugh. a qlist of ksharedptr<kservice>
|
||||
QMutableListIterator<KService::Ptr> it(offers);
|
||||
while (it.hasNext()) {
|
||||
KService::Ptr p = it.next();
|
||||
QString prop = QString("X-Plasma-Requires-").append(key);
|
||||
QVariant req = p->property(prop, QVariant::String);
|
||||
//valid values: Required/Optional/Unused
|
||||
QString reqValue;
|
||||
if (req.isValid()) {
|
||||
reqValue = req.toString();
|
||||
} else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
|
||||
//TODO: be able to check whether or not a script engine provides "controled"
|
||||
//bindings; for now we just give a pass to the qscript ones
|
||||
reqValue = "Unused";
|
||||
}
|
||||
|
||||
if (!(reqValue == "Optional" || reqValue == "Unused")) {
|
||||
//if (reqValue == "Required") {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString AppletPrivate::parentAppConstraint(const QString &parentApp)
|
||||
{
|
||||
if (parentApp.isEmpty()) {
|
||||
return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
|
||||
.arg(KGlobal::mainComponent().aboutData()->appName());
|
||||
}
|
||||
|
||||
return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
|
||||
}
|
||||
|
||||
KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp)
|
||||
{
|
||||
return PluginLoader::self()->listAppletInfo(category, parentApp);
|
||||
@ -2183,26 +1783,6 @@ void Applet::lower()
|
||||
setZValue(--AppletPrivate::s_minZValue);
|
||||
}
|
||||
|
||||
void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
|
||||
{
|
||||
if (isContainment == nowIsContainment && !forceUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
isContainment = nowIsContainment;
|
||||
//FIXME I do not like this function.
|
||||
//currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
|
||||
//if someone calls it at some other time it'll cause headaches. :P
|
||||
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
|
||||
Containment *c = q->containment();
|
||||
if (c) {
|
||||
c->d->checkContainmentFurniture();
|
||||
}
|
||||
}
|
||||
|
||||
bool Applet::isContainment() const
|
||||
{
|
||||
return d->isContainment;
|
||||
@ -2210,363 +1790,7 @@ bool Applet::isContainment() const
|
||||
|
||||
// PRIVATE CLASS IMPLEMENTATION
|
||||
|
||||
AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
|
||||
: appletId(uniqueID),
|
||||
q(applet),
|
||||
remotingService(0),
|
||||
preferredBackgroundHints(StandardBackground),
|
||||
backgroundHints(NoBackground),
|
||||
aspectRatioMode(Plasma::KeepAspectRatio),
|
||||
immutability(Mutable),
|
||||
appletDescription(info ? *info : KPluginInfo(service)),
|
||||
background(0),
|
||||
mainConfig(0),
|
||||
pendingConstraints(NoConstraint),
|
||||
script(0),
|
||||
package(0),
|
||||
configLoader(0),
|
||||
actions(AppletPrivate::defaultActions(applet)),
|
||||
activationAction(0),
|
||||
itemStatus(UnknownStatus),
|
||||
preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
|
||||
modificationsTimer(0),
|
||||
hasConfigurationInterface(false),
|
||||
failed(false),
|
||||
isContainment(false),
|
||||
transient(false),
|
||||
needsConfig(false),
|
||||
started(false)
|
||||
{
|
||||
if (appletId == 0) {
|
||||
appletId = ++s_maxAppletId;
|
||||
} else if (appletId > s_maxAppletId) {
|
||||
s_maxAppletId = appletId;
|
||||
}
|
||||
}
|
||||
|
||||
AppletPrivate::~AppletPrivate()
|
||||
{
|
||||
if (activationAction && activationAction->isGlobalShortcutEnabled()) {
|
||||
//kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
|
||||
activationAction->forgetGlobalShortcut();
|
||||
}
|
||||
|
||||
delete script;
|
||||
script = 0;
|
||||
delete package;
|
||||
package = 0;
|
||||
delete configLoader;
|
||||
configLoader = 0;
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
delete modificationsTimer;
|
||||
}
|
||||
|
||||
void AppletPrivate::init(const QString &packagePath)
|
||||
{
|
||||
// WARNING: do not access config() OR globalConfig() in this method!
|
||||
// that requires a scene, which is not available at this point
|
||||
q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
|
||||
q->setAcceptsHoverEvents(true);
|
||||
q->setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
q->setFocusPolicy(Qt::ClickFocus);
|
||||
// FIXME: adding here because nothing seems to be doing it in QGraphicsView,
|
||||
// but it doesn't actually work anyways =/
|
||||
q->setLayoutDirection(qApp->layoutDirection());
|
||||
|
||||
//set a default size before any saved settings are read
|
||||
QSize size(200, 200);
|
||||
q->setBackgroundHints(DefaultBackground);
|
||||
q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
|
||||
|
||||
QAction *closeApplet = actions->action("remove");
|
||||
if (closeApplet) {
|
||||
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
|
||||
}
|
||||
|
||||
QAction *configAction = actions->action("configure");
|
||||
if (configAction) {
|
||||
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
|
||||
}
|
||||
|
||||
QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
|
||||
if (!appletDescription.isValid()) {
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "Check your constructor! "
|
||||
<< "You probably want to be passing in a Service::Ptr "
|
||||
<< "or a QVariantList with a valid storageid as arg[0].";
|
||||
#endif
|
||||
q->resize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant s = appletDescription.property("X-Plasma-DefaultSize");
|
||||
if (s.isValid()) {
|
||||
size = s.toSize();
|
||||
}
|
||||
//kDebug() << "size" << size;
|
||||
q->resize(size);
|
||||
|
||||
QString api = appletDescription.property("X-Plasma-API").toString();
|
||||
|
||||
// we have a scripted plasmoid
|
||||
if (api.isEmpty()) {
|
||||
q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api));
|
||||
|
||||
// find where the Package is
|
||||
QString path = packagePath;
|
||||
if (path.isEmpty()) {
|
||||
const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/';
|
||||
path = KStandardDirs::locate("data", subPath + "metadata.desktop");
|
||||
if (path.isEmpty()) {
|
||||
path = KStandardDirs::locate("data", subPath);
|
||||
} else {
|
||||
path.remove(QString("metadata.desktop"));
|
||||
}
|
||||
} else if (!path.endsWith('/')) {
|
||||
path.append('/');
|
||||
}
|
||||
|
||||
if (path.isEmpty()) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true,
|
||||
i18nc("Package file, name of the widget",
|
||||
"Could not locate the %1 package required for the %2 widget.",
|
||||
appletDescription.pluginName(), appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
package->setPath(path);
|
||||
if (!package->isValid()) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
|
||||
"Could not open the %1 package required for the %2 widget.",
|
||||
appletDescription.pluginName(), appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
// create the package and see if we have something real
|
||||
//kDebug() << "trying for" << path;
|
||||
|
||||
// now we try and set up the script engine.
|
||||
// it will be parented to this applet and so will get
|
||||
// deleted when the applet does
|
||||
|
||||
script = Plasma::loadScriptEngine(api, q);
|
||||
if (!script) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true,
|
||||
i18nc("API or programming language the widget was written in, name of the widget",
|
||||
"Could not create a %1 ScriptEngine for the %2 widget.",
|
||||
api, appletDescription.name()));
|
||||
}
|
||||
}
|
||||
|
||||
// put all setup routines for script here. at this point we can assume that
|
||||
// package exists and that we have a script engine
|
||||
void AppletPrivate::setupScriptSupport()
|
||||
{
|
||||
if (!package) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "setting up script support, package is in" << package->path()
|
||||
<< ", main script is" << package->filePath("mainscript");
|
||||
#endif
|
||||
|
||||
const QString translationsPath = package->filePath("translations");
|
||||
if (!translationsPath.isEmpty()) {
|
||||
KGlobal::dirs()->addResourceDir("locale", translationsPath);
|
||||
KGlobal::locale()->insertCatalog(appletDescription.pluginName());
|
||||
}
|
||||
|
||||
const QString xmlPath = package->filePath("mainconfigxml");
|
||||
if (!xmlPath.isEmpty()) {
|
||||
QFile file(xmlPath);
|
||||
KConfigGroup config = q->config();
|
||||
configLoader = new ConfigLoader(&config, &file);
|
||||
QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
|
||||
}
|
||||
|
||||
if (!package->filePath("mainconfigui").isEmpty()) {
|
||||
q->setHasConfigurationInterface(true);
|
||||
}
|
||||
}
|
||||
|
||||
QString AppletPrivate::globalName() const
|
||||
{
|
||||
if (!appletDescription.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return appletDescription.service()->library();
|
||||
}
|
||||
|
||||
QString AppletPrivate::instanceName()
|
||||
{
|
||||
if (!appletDescription.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return appletDescription.service()->library() + QString::number(appletId);
|
||||
}
|
||||
|
||||
void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
|
||||
{
|
||||
// Don't start up a timer if we're just starting up
|
||||
// flushPendingConstraints will be called by Corona
|
||||
if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
|
||||
constraintsTimer.start(0, q);
|
||||
}
|
||||
|
||||
if (c & Plasma::StartupCompletedConstraint) {
|
||||
started = true;
|
||||
}
|
||||
|
||||
pendingConstraints |= c;
|
||||
}
|
||||
|
||||
void AppletPrivate::scheduleModificationNotification()
|
||||
{
|
||||
// modificationsTimer is not allocated until we get our notice of being started
|
||||
if (modificationsTimer) {
|
||||
// schedule a save
|
||||
if (modificationsTimer->isActive()) {
|
||||
modificationsTimer->stop();
|
||||
}
|
||||
|
||||
modificationsTimer->start(1000, q);
|
||||
}
|
||||
}
|
||||
|
||||
KConfigGroup *AppletPrivate::mainConfigGroup()
|
||||
{
|
||||
if (mainConfig) {
|
||||
return mainConfig;
|
||||
}
|
||||
|
||||
bool newGroup = false;
|
||||
if (isContainment) {
|
||||
Corona *corona = qobject_cast<Corona*>(q->scene());
|
||||
KConfigGroup containmentConfig;
|
||||
//kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
|
||||
|
||||
if (corona) {
|
||||
containmentConfig = KConfigGroup(corona->config(), "Containments");
|
||||
} else {
|
||||
containmentConfig = KConfigGroup(KGlobal::config(), "Containments");
|
||||
}
|
||||
|
||||
if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
|
||||
newGroup = true;
|
||||
}
|
||||
|
||||
mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
|
||||
} else {
|
||||
KConfigGroup appletConfig;
|
||||
|
||||
Containment *c = q->containment();
|
||||
Applet *parentApplet = qobject_cast<Applet *>(q->parent());
|
||||
if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
|
||||
// this applet is nested inside another applet! use it's config
|
||||
// as the parent group in the config
|
||||
appletConfig = parentApplet->config();
|
||||
appletConfig = KConfigGroup(&appletConfig, "Applets");
|
||||
} else if (c) {
|
||||
// applet directly in a Containment, as usual
|
||||
appletConfig = c->config();
|
||||
appletConfig = KConfigGroup(&appletConfig, "Applets");
|
||||
} else {
|
||||
kWarning() << "requesting config for" << q->name() << "without a containment!";
|
||||
appletConfig = KConfigGroup(KGlobal::config(), "Applets");
|
||||
}
|
||||
|
||||
if (package && !appletConfig.hasGroup(QString::number(appletId))) {
|
||||
newGroup = true;
|
||||
}
|
||||
|
||||
mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
|
||||
}
|
||||
|
||||
if (newGroup) {
|
||||
//see if we have a default configuration in our package
|
||||
const QString defaultConfigFile = package->filePath("defaultconfig");
|
||||
if (!defaultConfigFile.isEmpty()) {
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "copying default config: " << package->filePath("defaultconfig");
|
||||
#endif
|
||||
KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
|
||||
defaultConfig.copyTo(mainConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return mainConfig;
|
||||
}
|
||||
|
||||
QString AppletPrivate::visibleFailureText(const QString &reason)
|
||||
{
|
||||
QString text;
|
||||
|
||||
if (reason.isEmpty()) {
|
||||
text = i18n("This object could not be created.");
|
||||
} else {
|
||||
text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void AppletPrivate::themeChanged()
|
||||
{
|
||||
if (background) {
|
||||
//do again the translucent background fallback
|
||||
q->setBackgroundHints(backgroundHints);
|
||||
|
||||
qreal left;
|
||||
qreal right;
|
||||
qreal top;
|
||||
qreal bottom;
|
||||
background->getMargins(left, top, right, bottom);
|
||||
q->setContentsMargins(left, right, top, bottom);
|
||||
}
|
||||
q->update();
|
||||
}
|
||||
|
||||
void AppletPrivate::resetConfigurationObject()
|
||||
{
|
||||
// make sure mainConfigGroup exists in all cases
|
||||
mainConfigGroup();
|
||||
|
||||
mainConfig->deleteGroup();
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
|
||||
Corona * corona = qobject_cast<Corona*>(q->scene());
|
||||
if (corona) {
|
||||
corona->requireConfigSync();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::handleDisappeared(AppletHandle *h)
|
||||
{
|
||||
if (h == handle.data()) {
|
||||
h->detachApplet();
|
||||
QGraphicsScene *scene = q->scene();
|
||||
if (scene && h->scene() == scene) {
|
||||
scene->removeItem(h);
|
||||
}
|
||||
h->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void ContainmentPrivate::checkRemoveAction()
|
||||
{
|
||||
@ -2574,11 +1798,6 @@ void ContainmentPrivate::checkRemoveAction()
|
||||
}
|
||||
|
||||
|
||||
uint AppletPrivate::s_maxAppletId = 0;
|
||||
int AppletPrivate::s_maxZValue = 0;
|
||||
int AppletPrivate::s_minZValue = 0;
|
||||
QSet<QString> AppletPrivate::s_customCategories;
|
||||
|
||||
} // Plasma namespace
|
||||
|
||||
#include "moc_applet.cpp"
|
||||
|
830
private/appletprivate.cpp
Normal file
830
private/appletprivate.cpp
Normal file
@ -0,0 +1,830 @@
|
||||
/*
|
||||
* Copyright 2005 by Aaron Seigo <aseigo@kde.org>
|
||||
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
|
||||
* Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
|
||||
* Copyright (c) 2009 Chani Armitage <chani@kde.org>
|
||||
* Copyright 2012 by Marco Martin <mart@kde.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "private/applet_p.h"
|
||||
|
||||
#include <QGraphicsLayout>
|
||||
#include <QGraphicsView>
|
||||
|
||||
#include "abstracttoolbox.h"
|
||||
#include "containment.h"
|
||||
#include "corona.h"
|
||||
#include "pluginloader.h"
|
||||
#include "scripting/scriptengine.h"
|
||||
|
||||
#include "private/containment_p.h"
|
||||
|
||||
#include <kaction.h>
|
||||
#include <kkeysequencewidget.h>
|
||||
#include <kicon.h>
|
||||
#include <kstandarddirs.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
|
||||
: appletId(uniqueID),
|
||||
q(applet),
|
||||
remotingService(0),
|
||||
preferredBackgroundHints(StandardBackground),
|
||||
backgroundHints(NoBackground),
|
||||
aspectRatioMode(Plasma::KeepAspectRatio),
|
||||
immutability(Mutable),
|
||||
appletDescription(info ? *info : KPluginInfo(service)),
|
||||
background(0),
|
||||
mainConfig(0),
|
||||
pendingConstraints(NoConstraint),
|
||||
script(0),
|
||||
package(0),
|
||||
configLoader(0),
|
||||
actions(AppletPrivate::defaultActions(applet)),
|
||||
activationAction(0),
|
||||
itemStatus(UnknownStatus),
|
||||
preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
|
||||
modificationsTimer(0),
|
||||
hasConfigurationInterface(false),
|
||||
failed(false),
|
||||
isContainment(false),
|
||||
transient(false),
|
||||
needsConfig(false),
|
||||
started(false)
|
||||
{
|
||||
if (appletId == 0) {
|
||||
appletId = ++s_maxAppletId;
|
||||
} else if (appletId > s_maxAppletId) {
|
||||
s_maxAppletId = appletId;
|
||||
}
|
||||
}
|
||||
|
||||
AppletPrivate::~AppletPrivate()
|
||||
{
|
||||
if (activationAction && activationAction->isGlobalShortcutEnabled()) {
|
||||
//kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
|
||||
activationAction->forgetGlobalShortcut();
|
||||
}
|
||||
|
||||
delete script;
|
||||
script = 0;
|
||||
delete package;
|
||||
package = 0;
|
||||
delete configLoader;
|
||||
configLoader = 0;
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
delete modificationsTimer;
|
||||
}
|
||||
|
||||
void AppletPrivate::init(const QString &packagePath)
|
||||
{
|
||||
// WARNING: do not access config() OR globalConfig() in this method!
|
||||
// that requires a scene, which is not available at this point
|
||||
q->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
|
||||
q->setAcceptsHoverEvents(true);
|
||||
q->setFlag(QGraphicsItem::ItemIsFocusable, true);
|
||||
q->setFocusPolicy(Qt::ClickFocus);
|
||||
// FIXME: adding here because nothing seems to be doing it in QGraphicsView,
|
||||
// but it doesn't actually work anyways =/
|
||||
q->setLayoutDirection(qApp->layoutDirection());
|
||||
|
||||
//set a default size before any saved settings are read
|
||||
QSize size(200, 200);
|
||||
q->setBackgroundHints(DefaultBackground);
|
||||
q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
|
||||
|
||||
QAction *closeApplet = actions->action("remove");
|
||||
if (closeApplet) {
|
||||
closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
|
||||
}
|
||||
|
||||
QAction *configAction = actions->action("configure");
|
||||
if (configAction) {
|
||||
configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
|
||||
}
|
||||
|
||||
QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
|
||||
if (!appletDescription.isValid()) {
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "Check your constructor! "
|
||||
<< "You probably want to be passing in a Service::Ptr "
|
||||
<< "or a QVariantList with a valid storageid as arg[0].";
|
||||
#endif
|
||||
q->resize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant s = appletDescription.property("X-Plasma-DefaultSize");
|
||||
if (s.isValid()) {
|
||||
size = s.toSize();
|
||||
}
|
||||
//kDebug() << "size" << size;
|
||||
q->resize(size);
|
||||
|
||||
QString api = appletDescription.property("X-Plasma-API").toString();
|
||||
|
||||
// we have a scripted plasmoid
|
||||
if (api.isEmpty()) {
|
||||
q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api));
|
||||
|
||||
// find where the Package is
|
||||
QString path = packagePath;
|
||||
if (path.isEmpty()) {
|
||||
const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/';
|
||||
path = KStandardDirs::locate("data", subPath + "metadata.desktop");
|
||||
if (path.isEmpty()) {
|
||||
path = KStandardDirs::locate("data", subPath);
|
||||
} else {
|
||||
path.remove(QString("metadata.desktop"));
|
||||
}
|
||||
} else if (!path.endsWith('/')) {
|
||||
path.append('/');
|
||||
}
|
||||
|
||||
if (path.isEmpty()) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true,
|
||||
i18nc("Package file, name of the widget",
|
||||
"Could not locate the %1 package required for the %2 widget.",
|
||||
appletDescription.pluginName(), appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
package->setPath(path);
|
||||
if (!package->isValid()) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
|
||||
"Could not open the %1 package required for the %2 widget.",
|
||||
appletDescription.pluginName(), appletDescription.name()));
|
||||
return;
|
||||
}
|
||||
|
||||
// create the package and see if we have something real
|
||||
//kDebug() << "trying for" << path;
|
||||
|
||||
// now we try and set up the script engine.
|
||||
// it will be parented to this applet and so will get
|
||||
// deleted when the applet does
|
||||
|
||||
script = Plasma::loadScriptEngine(api, q);
|
||||
if (!script) {
|
||||
delete package;
|
||||
package = 0;
|
||||
q->setFailedToLaunch(true,
|
||||
i18nc("API or programming language the widget was written in, name of the widget",
|
||||
"Could not create a %1 ScriptEngine for the %2 widget.",
|
||||
api, appletDescription.name()));
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::setFocus()
|
||||
{
|
||||
//kDebug() << "setting focus";
|
||||
q->setFocus(Qt::ShortcutFocusReason);
|
||||
}
|
||||
|
||||
void AppletPrivate::selectItemToDestroy()
|
||||
{
|
||||
//FIXME: this will not work nicely with multiple screens and being zoomed out!
|
||||
if (isContainment) {
|
||||
QGraphicsView *view = q->view();
|
||||
if (view && view->transform().isScaling() &&
|
||||
q->scene()->focusItem() != q) {
|
||||
QGraphicsItem *focus = q->scene()->focusItem();
|
||||
|
||||
if (focus) {
|
||||
Containment *toDestroy = dynamic_cast<Containment*>(focus->topLevelItem());
|
||||
|
||||
if (toDestroy) {
|
||||
toDestroy->destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q->destroy();
|
||||
}
|
||||
|
||||
void AppletPrivate::updateRect(const QRectF &rect)
|
||||
{
|
||||
q->update(rect);
|
||||
}
|
||||
|
||||
void AppletPrivate::cleanUpAndDelete()
|
||||
{
|
||||
//kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????";
|
||||
QGraphicsWidget *parent = dynamic_cast<QGraphicsWidget *>(q->parentItem());
|
||||
//it probably won't matter, but right now if there are applethandles, *they* are the parent.
|
||||
//not the containment.
|
||||
|
||||
//is the applet in a containment and does the containment have a layout?
|
||||
//if yes, we remove the applet in the layout
|
||||
if (parent && parent->layout()) {
|
||||
QGraphicsLayout *l = parent->layout();
|
||||
for (int i = 0; i < l->count(); ++i) {
|
||||
if (q == l->itemAt(i)) {
|
||||
l->removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configLoader) {
|
||||
configLoader->setDefaults();
|
||||
}
|
||||
|
||||
resetConfigurationObject();
|
||||
|
||||
if (q->scene()) {
|
||||
if (isContainment) {
|
||||
// prematurely emit our destruction if we are a Containment,
|
||||
// giving Corona a chance to remove this Containment from its collection
|
||||
emit q->QObject::destroyed(q);
|
||||
}
|
||||
|
||||
q->scene()->removeItem(q);
|
||||
}
|
||||
|
||||
q->deleteLater();
|
||||
}
|
||||
|
||||
void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(show)
|
||||
Q_UNUSED(reason)
|
||||
}
|
||||
|
||||
void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(icon)
|
||||
Q_UNUSED(message)
|
||||
Q_UNUSED(buttons)
|
||||
}
|
||||
|
||||
void AppletPrivate::positionMessageOverlay()
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
}
|
||||
|
||||
void AppletPrivate::setBusy(bool busy)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(busy)
|
||||
}
|
||||
|
||||
bool AppletPrivate::isBusy() const
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppletPrivate::updateFailedToLaunch(const QString &reason)
|
||||
{
|
||||
// reimplemented in the UI specific library
|
||||
Q_UNUSED(reason)
|
||||
}
|
||||
|
||||
void AppletPrivate::globalShortcutChanged()
|
||||
{
|
||||
if (!activationAction) {
|
||||
return;
|
||||
}
|
||||
|
||||
KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
|
||||
shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
|
||||
scheduleModificationNotification();
|
||||
//kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
|
||||
}
|
||||
|
||||
KActionCollection* AppletPrivate::defaultActions(QObject *parent)
|
||||
{
|
||||
KActionCollection *actions = new KActionCollection(parent);
|
||||
actions->setConfigGroup("Shortcuts-Applet");
|
||||
|
||||
KAction *configAction = actions->addAction("configure");
|
||||
configAction->setAutoRepeat(false);
|
||||
configAction->setText(i18n("Widget Settings"));
|
||||
configAction->setIcon(KIcon("configure"));
|
||||
configAction->setShortcut(KShortcut("alt+d, s"));
|
||||
configAction->setData(AbstractToolBox::ConfigureTool);
|
||||
|
||||
KAction *closeApplet = actions->addAction("remove");
|
||||
closeApplet->setAutoRepeat(false);
|
||||
closeApplet->setText(i18n("Remove this Widget"));
|
||||
closeApplet->setIcon(KIcon("edit-delete"));
|
||||
closeApplet->setShortcut(KShortcut("alt+d, r"));
|
||||
closeApplet->setData(AbstractToolBox::DestructiveTool);
|
||||
|
||||
KAction *runAssociatedApplication = actions->addAction("run associated application");
|
||||
runAssociatedApplication->setAutoRepeat(false);
|
||||
runAssociatedApplication->setText(i18n("Run the Associated Application"));
|
||||
runAssociatedApplication->setIcon(KIcon("system-run"));
|
||||
runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
|
||||
runAssociatedApplication->setVisible(false);
|
||||
runAssociatedApplication->setEnabled(false);
|
||||
runAssociatedApplication->setData(AbstractToolBox::ControlTool);
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
QString AppletPrivate::configDialogId() const
|
||||
{
|
||||
return QString("%1settings%2").arg(appletId).arg(q->name());
|
||||
}
|
||||
|
||||
QString AppletPrivate::configWindowTitle() const
|
||||
{
|
||||
return i18nc("@title:window", "%1 Settings", q->name());
|
||||
}
|
||||
|
||||
QSet<QString> AppletPrivate::knownCategories()
|
||||
{
|
||||
// this is to trick the tranlsation tools into making the correct
|
||||
// strings for translation
|
||||
QSet<QString> categories = s_customCategories;
|
||||
categories << QString(I18N_NOOP("Accessibility")).toLower()
|
||||
<< QString(I18N_NOOP("Application Launchers")).toLower()
|
||||
<< QString(I18N_NOOP("Astronomy")).toLower()
|
||||
<< QString(I18N_NOOP("Date and Time")).toLower()
|
||||
<< QString(I18N_NOOP("Development Tools")).toLower()
|
||||
<< QString(I18N_NOOP("Education")).toLower()
|
||||
<< QString(I18N_NOOP("Environment and Weather")).toLower()
|
||||
<< QString(I18N_NOOP("Examples")).toLower()
|
||||
<< QString(I18N_NOOP("File System")).toLower()
|
||||
<< QString(I18N_NOOP("Fun and Games")).toLower()
|
||||
<< QString(I18N_NOOP("Graphics")).toLower()
|
||||
<< QString(I18N_NOOP("Language")).toLower()
|
||||
<< QString(I18N_NOOP("Mapping")).toLower()
|
||||
<< QString(I18N_NOOP("Miscellaneous")).toLower()
|
||||
<< QString(I18N_NOOP("Multimedia")).toLower()
|
||||
<< QString(I18N_NOOP("Online Services")).toLower()
|
||||
<< QString(I18N_NOOP("Productivity")).toLower()
|
||||
<< QString(I18N_NOOP("System Information")).toLower()
|
||||
<< QString(I18N_NOOP("Utilities")).toLower()
|
||||
<< QString(I18N_NOOP("Windows and Tasks")).toLower();
|
||||
return categories;
|
||||
}
|
||||
|
||||
KConfigDialog *AppletPrivate::generateGenericConfigDialog()
|
||||
{
|
||||
KConfigSkeleton *nullManager = new KConfigSkeleton(0);
|
||||
KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
|
||||
nullManager->setParent(dialog);
|
||||
dialog->setFaceType(KPageDialog::Auto);
|
||||
dialog->setWindowTitle(configWindowTitle());
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
q->createConfigurationInterface(dialog);
|
||||
dialog->showButton(KDialog::Default, false);
|
||||
dialog->showButton(KDialog::Help, false);
|
||||
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
|
||||
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
|
||||
{
|
||||
addGlobalShortcutsPage(dialog);
|
||||
addPublishPage(dialog);
|
||||
}
|
||||
|
||||
void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
|
||||
{
|
||||
#ifndef PLASMA_NO_GLOBAL_SHORTCUTS
|
||||
if (isContainment) {
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *page = new QWidget;
|
||||
QVBoxLayout *layout = new QVBoxLayout(page);
|
||||
|
||||
if (!shortcutEditor) {
|
||||
shortcutEditor = new KKeySequenceWidget(page);
|
||||
QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
|
||||
}
|
||||
|
||||
shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
|
||||
layout->addWidget(shortcutEditor.data());
|
||||
layout->addStretch();
|
||||
dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
|
||||
|
||||
QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
|
||||
QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppletPrivate::addPublishPage(KConfigDialog *dialog)
|
||||
{
|
||||
#ifdef ENABLE_REMOTE_WIDGETS
|
||||
QWidget *page = new QWidget;
|
||||
publishUI.setupUi(page);
|
||||
publishUI.publishCheckbox->setChecked(q->isPublished());
|
||||
QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
|
||||
publishUI.allUsersCheckbox->setEnabled(q->isPublished());
|
||||
QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
|
||||
|
||||
QString resourceName =
|
||||
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
|
||||
"%1 on %2", q->name(), QHostInfo::localHostName());
|
||||
if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
|
||||
publishUI.allUsersCheckbox->setChecked(true);
|
||||
} else {
|
||||
publishUI.allUsersCheckbox->setChecked(false);
|
||||
}
|
||||
|
||||
q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
|
||||
q, SLOT(publishCheckboxStateChanged(int)));
|
||||
dialog->addPage(page, i18n("Share"), "applications-internet");
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppletPrivate::publishCheckboxStateChanged(int state)
|
||||
{
|
||||
if (state == Qt::Checked) {
|
||||
publishUI.allUsersCheckbox->setEnabled(true);
|
||||
} else {
|
||||
publishUI.allUsersCheckbox->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::configDialogFinished()
|
||||
{
|
||||
if (shortcutEditor) {
|
||||
QKeySequence sequence = shortcutEditor.data()->keySequence();
|
||||
if (sequence != q->globalShortcut().primary()) {
|
||||
q->setGlobalShortcut(KShortcut(sequence));
|
||||
emit q->configNeedsSaving();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_REMOTE_WIDGETS
|
||||
if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
|
||||
q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
|
||||
|
||||
if (publishUI.publishCheckbox->isChecked()) {
|
||||
QString resourceName =
|
||||
i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
|
||||
"%1 on %2", q->name(), QHostInfo::localHostName());
|
||||
q->publish(Plasma::ZeroconfAnnouncement, resourceName);
|
||||
if (publishUI.allUsersCheckbox->isChecked()) {
|
||||
if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
|
||||
AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
|
||||
rule->setPolicy(AuthorizationRule::Allow);
|
||||
rule->setTargets(AuthorizationRule::AllUsers);
|
||||
AuthorizationManager::self()->d->rules.append(rule);
|
||||
}
|
||||
} else {
|
||||
AuthorizationRule *matchingRule =
|
||||
AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
|
||||
if (matchingRule) {
|
||||
AuthorizationManager::self()->d->rules.removeAll(matchingRule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
q->unpublish();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!configLoader) {
|
||||
// the config loader will trigger this for us, so we don't need to.
|
||||
propagateConfigChanged();
|
||||
if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
|
||||
dialog->enableButton(KDialog::Apply, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::updateShortcuts()
|
||||
{
|
||||
if (isContainment) {
|
||||
//a horrible hack to avoid clobbering corona settings
|
||||
//we pull them out, then read, then put them back
|
||||
QList<QString> names;
|
||||
QList<QAction*> qactions;
|
||||
names << "add sibling containment" << "configure shortcuts" << "lock widgets";
|
||||
foreach (const QString &name, names) {
|
||||
QAction *a = actions->action(name);
|
||||
actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
|
||||
qactions << a;
|
||||
}
|
||||
|
||||
actions->readSettings();
|
||||
|
||||
for (int i = 0; i < names.size(); ++i) {
|
||||
QAction *a = qactions.at(i);
|
||||
if (a) {
|
||||
actions->addAction(names.at(i), a);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
actions->readSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::propagateConfigChanged()
|
||||
{
|
||||
if (isContainment) {
|
||||
Containment *c = qobject_cast<Containment *>(q);
|
||||
if (c) {
|
||||
c->d->configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
q->configChanged();
|
||||
}
|
||||
|
||||
void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
|
||||
{
|
||||
KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
|
||||
foreach (const QString &key, constraintGroup.keyList()) {
|
||||
//kDebug() << "security constraint" << key;
|
||||
if (constraintGroup.readEntry(key, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//ugh. a qlist of ksharedptr<kservice>
|
||||
QMutableListIterator<KService::Ptr> it(offers);
|
||||
while (it.hasNext()) {
|
||||
KService::Ptr p = it.next();
|
||||
QString prop = QString("X-Plasma-Requires-").append(key);
|
||||
QVariant req = p->property(prop, QVariant::String);
|
||||
//valid values: Required/Optional/Unused
|
||||
QString reqValue;
|
||||
if (req.isValid()) {
|
||||
reqValue = req.toString();
|
||||
} else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
|
||||
//TODO: be able to check whether or not a script engine provides "controled"
|
||||
//bindings; for now we just give a pass to the qscript ones
|
||||
reqValue = "Unused";
|
||||
}
|
||||
|
||||
if (!(reqValue == "Optional" || reqValue == "Unused")) {
|
||||
//if (reqValue == "Required") {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString AppletPrivate::parentAppConstraint(const QString &parentApp)
|
||||
{
|
||||
if (parentApp.isEmpty()) {
|
||||
return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
|
||||
.arg(KGlobal::mainComponent().aboutData()->appName());
|
||||
}
|
||||
|
||||
return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
|
||||
}
|
||||
|
||||
void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
|
||||
{
|
||||
if (isContainment == nowIsContainment && !forceUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
isContainment = nowIsContainment;
|
||||
//FIXME I do not like this function.
|
||||
//currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
|
||||
//if someone calls it at some other time it'll cause headaches. :P
|
||||
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
|
||||
Containment *c = q->containment();
|
||||
if (c) {
|
||||
c->d->checkContainmentFurniture();
|
||||
}
|
||||
}
|
||||
|
||||
// put all setup routines for script here. at this point we can assume that
|
||||
// package exists and that we have a script engine
|
||||
void AppletPrivate::setupScriptSupport()
|
||||
{
|
||||
if (!package) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "setting up script support, package is in" << package->path()
|
||||
<< ", main script is" << package->filePath("mainscript");
|
||||
#endif
|
||||
|
||||
const QString translationsPath = package->filePath("translations");
|
||||
if (!translationsPath.isEmpty()) {
|
||||
KGlobal::dirs()->addResourceDir("locale", translationsPath);
|
||||
KGlobal::locale()->insertCatalog(appletDescription.pluginName());
|
||||
}
|
||||
|
||||
const QString xmlPath = package->filePath("mainconfigxml");
|
||||
if (!xmlPath.isEmpty()) {
|
||||
QFile file(xmlPath);
|
||||
KConfigGroup config = q->config();
|
||||
configLoader = new ConfigLoader(&config, &file);
|
||||
QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
|
||||
}
|
||||
|
||||
if (!package->filePath("mainconfigui").isEmpty()) {
|
||||
q->setHasConfigurationInterface(true);
|
||||
}
|
||||
}
|
||||
|
||||
QString AppletPrivate::globalName() const
|
||||
{
|
||||
if (!appletDescription.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return appletDescription.service()->library();
|
||||
}
|
||||
|
||||
QString AppletPrivate::instanceName()
|
||||
{
|
||||
if (!appletDescription.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return appletDescription.service()->library() + QString::number(appletId);
|
||||
}
|
||||
|
||||
void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
|
||||
{
|
||||
// Don't start up a timer if we're just starting up
|
||||
// flushPendingConstraints will be called by Corona
|
||||
if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
|
||||
constraintsTimer.start(0, q);
|
||||
}
|
||||
|
||||
if (c & Plasma::StartupCompletedConstraint) {
|
||||
started = true;
|
||||
}
|
||||
|
||||
pendingConstraints |= c;
|
||||
}
|
||||
|
||||
void AppletPrivate::scheduleModificationNotification()
|
||||
{
|
||||
// modificationsTimer is not allocated until we get our notice of being started
|
||||
if (modificationsTimer) {
|
||||
// schedule a save
|
||||
if (modificationsTimer->isActive()) {
|
||||
modificationsTimer->stop();
|
||||
}
|
||||
|
||||
modificationsTimer->start(1000, q);
|
||||
}
|
||||
}
|
||||
|
||||
KConfigGroup *AppletPrivate::mainConfigGroup()
|
||||
{
|
||||
if (mainConfig) {
|
||||
return mainConfig;
|
||||
}
|
||||
|
||||
bool newGroup = false;
|
||||
if (isContainment) {
|
||||
Corona *corona = qobject_cast<Corona*>(q->scene());
|
||||
KConfigGroup containmentConfig;
|
||||
//kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
|
||||
|
||||
if (corona) {
|
||||
containmentConfig = KConfigGroup(corona->config(), "Containments");
|
||||
} else {
|
||||
containmentConfig = KConfigGroup(KGlobal::config(), "Containments");
|
||||
}
|
||||
|
||||
if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
|
||||
newGroup = true;
|
||||
}
|
||||
|
||||
mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
|
||||
} else {
|
||||
KConfigGroup appletConfig;
|
||||
|
||||
Containment *c = q->containment();
|
||||
Applet *parentApplet = qobject_cast<Applet *>(q->parent());
|
||||
if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
|
||||
// this applet is nested inside another applet! use it's config
|
||||
// as the parent group in the config
|
||||
appletConfig = parentApplet->config();
|
||||
appletConfig = KConfigGroup(&appletConfig, "Applets");
|
||||
} else if (c) {
|
||||
// applet directly in a Containment, as usual
|
||||
appletConfig = c->config();
|
||||
appletConfig = KConfigGroup(&appletConfig, "Applets");
|
||||
} else {
|
||||
kWarning() << "requesting config for" << q->name() << "without a containment!";
|
||||
appletConfig = KConfigGroup(KGlobal::config(), "Applets");
|
||||
}
|
||||
|
||||
if (package && !appletConfig.hasGroup(QString::number(appletId))) {
|
||||
newGroup = true;
|
||||
}
|
||||
|
||||
mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
|
||||
}
|
||||
|
||||
if (newGroup) {
|
||||
//see if we have a default configuration in our package
|
||||
const QString defaultConfigFile = package->filePath("defaultconfig");
|
||||
if (!defaultConfigFile.isEmpty()) {
|
||||
#ifndef NDEBUG
|
||||
kDebug() << "copying default config: " << package->filePath("defaultconfig");
|
||||
#endif
|
||||
KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
|
||||
defaultConfig.copyTo(mainConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return mainConfig;
|
||||
}
|
||||
|
||||
QString AppletPrivate::visibleFailureText(const QString &reason)
|
||||
{
|
||||
QString text;
|
||||
|
||||
if (reason.isEmpty()) {
|
||||
text = i18n("This object could not be created.");
|
||||
} else {
|
||||
text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void AppletPrivate::themeChanged()
|
||||
{
|
||||
if (background) {
|
||||
//do again the translucent background fallback
|
||||
q->setBackgroundHints(backgroundHints);
|
||||
|
||||
qreal left;
|
||||
qreal right;
|
||||
qreal top;
|
||||
qreal bottom;
|
||||
background->getMargins(left, top, right, bottom);
|
||||
q->setContentsMargins(left, right, top, bottom);
|
||||
}
|
||||
q->update();
|
||||
}
|
||||
|
||||
void AppletPrivate::resetConfigurationObject()
|
||||
{
|
||||
// make sure mainConfigGroup exists in all cases
|
||||
mainConfigGroup();
|
||||
|
||||
mainConfig->deleteGroup();
|
||||
delete mainConfig;
|
||||
mainConfig = 0;
|
||||
|
||||
Corona * corona = qobject_cast<Corona*>(q->scene());
|
||||
if (corona) {
|
||||
corona->requireConfigSync();
|
||||
}
|
||||
}
|
||||
|
||||
void AppletPrivate::handleDisappeared(AppletHandle *h)
|
||||
{
|
||||
if (h == handle.data()) {
|
||||
h->detachApplet();
|
||||
QGraphicsScene *scene = q->scene();
|
||||
if (scene && h->scene() == scene) {
|
||||
scene->removeItem(h);
|
||||
}
|
||||
h->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
uint AppletPrivate::s_maxAppletId = 0;
|
||||
int AppletPrivate::s_maxZValue = 0;
|
||||
int AppletPrivate::s_minZValue = 0;
|
||||
QSet<QString> AppletPrivate::s_customCategories;
|
||||
|
||||
} //namespace Plasma
|
Loading…
Reference in New Issue
Block a user