Unload Plugin in Qt - qt

Issue comes up when i try to unload plugin that is loaded and load a new one. So both plugins are loaded correctly, but when switching them (first is loaded, second is unloaded and viceversa) my app crashes. What can be the problem ?
First what i'm doing i try to unload a plugin stored into a QList of QPluginLoader, then i check (depdend on id(integer number) passed from a special menu for loading plugins ) what plugin to load. First load is well (first plugin is loaded, nothing at this point to unload) , second load (unload first plugin, second is loaded), at third load i get crash
void MainWindow::loadPluginUsingId (int plugin_id) {
foreach (QPluginLoader* pluginLoader, plugins) {
pluginLoader->unload();
delete pluginLoader;
}
switch (plugin_id) {
case 0 : {
foreach (QString fileName, pluginDir.entryList(QDir::Files)) {
if (fileName == fullNameOfPlugins.value(plugin_id)) {
QPluginLoader* pluginLoader = new QPluginLoader(pluginDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader->instance();
IndicatorInterface *indicator = qobject_cast<IndicatorInterface*>(plugin);
indicator->initIndicator();
plugins.append(pluginLoader);
}
}
}
break;
case 1 : {
foreach (QString fileName, pluginDir.entryList(QDir::Files)) {
if (fileName == fullNameOfPlugins.value(plugin_id)) {
QPluginLoader* pluginLoader = new QPluginLoader(pluginDir.absoluteFilePath(fileName));
QObject* plugin = pluginLoader->instance();
PlotterInterface *plotter = qobject_cast<PlotterInterface*>(plugin);
plotter->initPlotter();
plugins.append(pluginLoader);
}
}
}
break;
default :
break;
}
}

foreach (QPluginLoader* pluginLoader, plugins) {
pluginLoader->unload();
delete pluginLoader; // this could be your problem
}
You need to remove the dangling pointer from the plugins list. Failure to do that would result in what you're describing.
Try this:
while (!plugins.isEmpty()) {
QPluginLoader* pluginLoader = plugins.takeFirst();
pluginLoader->unload();
delete pluginLoader;
}

Related

gradle plugin copy without default excludes

I want to get some dependency artifact and copy the content into a specific location.
This works well in general, but not for files called e.g. .gitignore.
I found that those are default excludes.
How can i disable those default exclude, by using the Java-Gradle-API in my plugin code?
project.copy( spec -> {
spec.from (project.zipTree(artifact.getFile()));
spec.into( tf.toFile());
//spec.setExcludes(Collections.emptyList()); // does not work
});
Also i tried to the setExcludes in the from/into copyspec.
Frank
I found a solution, but i don't like it, because it modifies the globally visible defaultExcludes:
private static void withoutDefaultExcludes( Runnable r ) {
String[] defaultExcludes = org.apache.tools.ant.DirectoryScanner.getDefaultExcludes();
try {
for( String defaultExclude : defaultExcludes) {
org.apache.tools.ant.DirectoryScanner.removeDefaultExclude(defaultExclude);
}
r.run();
}
finally {
for( String defaultExclude : defaultExcludes) {
org.apache.tools.ant.DirectoryScanner.addDefaultExclude(defaultExclude);
}
}
}
withoutDefaultExcludes( () -> {
project.copy( spec -> {
spec.from (project.zipTree(artifact.getFile()));
spec.into( tf.toFile());
});
});

Sitecore: Show input option after using menu context item

I've added a menu context item to the TreelistEx. This menu item sends a messages that I later catch in a HandleMessage method.
In this method i create a new item ( template type and parent item are given in the source of the treelist field ).
All i need now is a way to ask the user for a name. But i haven't been able to find a simple way to do this.
class MyTreeListEx : TreelistEx, IMessageHandler
{
void IMessageHandler.HandleMessage(Message message)
{
if (message == null)
{ return; }
if (message["id"] == null)
{ return; }
if (!message["id"].Equals(ID))
{ return; }
switch (message.Name)
{
case "treelist:edit":
// call default treelist code
case "mytreelistex:add":
// my own code to create a new item
}
}
}
Does anyone have any suggestions on how to achieve this ?
Edit: added image & code + i'm using Sitecore 8 Update 1
I don't know which version of Sitecore you use but what you can try is SheerResponse.Input method.
You can use it like this:
using Sitecore.Configuration;
using Sitecore.Globalization;
using Sitecore.Shell.Applications.ContentEditor.FieldTypes;
using Sitecore.Web.UI.Sheer;
void IMessageHandler.HandleMessage(Message message)
{
...
case "mytreelistex:add":
Sitecore.Context.ClientPage.Start(this, "AddItem");
break;
}
protected static void AddItem(ClientPipelineArgs args)
{
if (args.IsPostBack)
{
if (!args.HasResult)
return;
string newItemName = args.Result;
// create new item here
// if you need refresh the page:
//SheerResponse.Eval("scForm.browser.getParentWindow(scForm.browser.getFrameElement(window).ownerDocument).location.reload(true)");
}
else
{
SheerResponse.Input("Enter the name of the new item:", "New Item Default Name", Settings.ItemNameValidation,
Translate.Text("'$Input' is not a valid name."), Settings.MaxItemNameLength);
args.WaitForPostBack();
}
}
This code will even validate your new item name for incorrect characters and length.

How can I run custom tool or save a file programmatically using EnvDTE?

I want to save/run custom tools on a handful of .tt files from my extension. I don't want to loop over all the files in the solution/project, rather I want to be able to use a relative (or full) path of the file to execute a save/run custom tool.
Is there a way to get a ProjectItem object given a path of the file ($(SolutionDir)/MyProject/MyFile.tt) so I can execute methods on it?
You can use the FindProjectItem method of the EnvDTE.Solution type to find a file within the current solution by its name. The ExecuteCommand method is dependent on the current UI context; so the item must be selected, otherwise, the call fails.
private bool TryExecuteTextTemplate(string filename)
{
var dte = (DTE2)this.GetService(typeof(SDTE));
Solution solution = dte.Solution;
if ((solution != null) && solution.IsOpen)
{
VSProjectItem projectItem;
ProjectItem item = solution.FindProjectItem(filename);
if (item != null && ((projectItem = item.Object as VSProjectItem) != null))
{
// TODO: track the item in the Solution Explorer
try
{
projectItem.RunCustomTool();
return true;
}
catch (COMException)
{
}
}
}
return false;
}

Flex navigateToURL from iframe POST

Let me explain my current issue right now:
I have a webapp located at domain A. Let's call it A-App. I open an iframe from A-App that points to a Flex app on domain B. We'll call it B-FlexApp. B-FlexApp wants to post some data to another app located on the same domain, we'll call it B-App. The problem is that in IE the communication breaks somewhere between B-FlexApp and B-App while B-FlexApp is opened in the iframe. This only happens in IE.
However when opening B-FlexApp in a new window, posting the data to B-App works just fine. How to overcome this? Dropping the iframe is not possible.
ThereĀ“s a issue with AS3 navigateToURL and IE. You can try calling javascript to navigate: I have a little utility class to handle this:
//class URLUtil
package com
{
import flash.external.*;
import flash.net.*;
public class URLUtil extends Object
{
protected static const WINDOW_OPEN_FUNCTION:String="window.open";
public function URLUtil()
{
super();
return;
}
public static function openWindow(arg1:String = "", arg2:String="_blank", arg3:String=""):void
{
var browserName:String = getBrowserName();
switch (browserName)
{
case "Firefox":
{
flash.external.ExternalInterface.call(WINDOW_OPEN_FUNCTION, arg1, arg2, arg3);
break;
}
case "IE":
{
flash.external.ExternalInterface.call("function setWMWindow() {window.open(\'" + arg1 + "\');}");
break;
}
case "Safari":
case "Opera":
{
flash.net.navigateToURL(new URLRequest(arg1), arg2);
break;
}
default:
{
flash.net.navigateToURL(new URLRequest(arg1), arg2);
break;
}
}
return;
}
private static function getBrowserName():String
{
var str:String="";
var browserName:String = ExternalInterface.call("function getBrowser(){return navigator.userAgent;}");
if (!(browserName == null) && browserName.indexOf("Firefox") >= 0)
{
str = "Firefox";
}
else
{
if (!(browserName == null) && browserName.indexOf("Safari") >= 0)
{
str = "Safari";
}
else
{
if (!(browserName == null) && browserName.indexOf("MSIE") >= 0)
{
str = "IE";
}
else
{
if (!(browserName == null) && browserName.indexOf("Opera") >= 0)
{
str = "Opera";
}
else
{
str = "Undefined";
}
}
}
}
trace("Browser: \t" + str);
return str;
}
}
}
and you call it like:
btn.addEventListener(MouseEvent.CLICK, onBTNClick);
function onBTNClick(evt:MouseEvent):void
{
URLUtil.openWindow(YOUR_URL_STRING);
}
Hope it helps!
It is better to let the browser actually does the "navigate to URL" function instead of Flex.
For example, in the page that contains the Flex app, the page would contain a Javascript function call handleNavigationRequest(pageName, target). In the Flex application, you may utilize ExternalInterface, and call the handleNavigationRequest.
By using this paradigm, the Flex application would not have to figure the details as to how the external implementations such as frame setup, etc, and you end up having a cleaner and less-coupled design.
I've found out that i can use swfObject to embed the flash object thus the iframe implementation is completely useless. Embedding the flash component in the overlay, instead of opening it in an iframe, makes IE behave properly.
I had the same problem and I solved it simply passing the second argument (browser window) to the function:
navigateToUrl(url,"_blank"); , in my case I use "_blank".
It works with IE8 and IE9.
Davide

QObject::connect: Cannot connect (null)

I try to load to plugins. If they are loaded with success , then i must connect returned widgets.
With one plugin i create an action and add it to a menu , with another plugin i create a label and add it to window. Even if i get this error during runtime (when app loads plugins) , these two widgets are created and are visible. But there is no connection between them.
This is how i try to connect widgets
QObject *plugin = pluginLoader.instance();
if (plugin) {
myAction = qobject_cast<ActionInterface *>(plugin);
if (myAction) {
pluginMenu->addAction(myAction->newAction());
verify ++;
}
myLabel = qobject_cast<LabelInterface *>(plugin);
if (myLabel) {
layout->addWidget(myLabel->newLabel());
verify++;
}
if (verify == 2)
connect(myAction, SIGNAL(pushMyAction()),
myLabel, SLOT(setTextforLabel()));
}
...
}
Error message is :
QObject::connect: Cannot connect (null)::pushMyAction() to LabelPlugin::setTextforLabel()
You have two different plugins. Apparently one can be cast to an ActionInterface but not a LabelInterface, and the other can be cast to a LabelInterface but not an ActionInterface.
Your idea here seems to be that once you have both plugins loaded (and a verify count of 2) then it's safe to make a connect call between these plugins. However you appear to be trying to cast the second loaded plugin to serve as both the signal and the slot. This is because each time you run the code you overwrite both myAction and myLabel. So at minimum:
QObject* plugin = pluginLoader.instance();
if (plugin) {
ActionInterface* myActionTemp = qobject_cast<ActionInterface*>(plugin);
if (myActionTemp) {
myAction = myActionTemp;
pluginMenu->addAction(myAction->newAction());
verify++;
}
LabelInterface* myLabelTemp = qobject_cast<LabelInterface*>(plugin);
if (myLabelTemp) {
myLabel = myLabelTemp;
layout->addWidget(myLabel->newLabel());
verify++;
}
/* if (myAction and myLabel) would be less convoluted... */
if (verify == 2) {
connect(myAction, SIGNAL(pushMyAction()),
myLabel, SLOT(setTextforLabel()));
}
...
}
Still, this looks like a fairly brittle design that could use some rethinking...!
QObject *plugin = pluginLoader.instance();
if (plugin) {
if (plugin->inherits("ActionInterface")) {
myAction = qobject_cast<ActionInterface *>(plugin);
pluginMenu->addAction(myAction->newAction());
}
if (plugin->inherits("LabelInterface")) {
myLabel = qobject_cast<LabelInterface *>(plugin);
layout->addWidget(myLabel->newLabel());
}
if (myLabel && myAction)
connect(myAction, SIGNAL(pushMyAction()),
myLabel, SLOT(setTextforLabel()));
}
...
}
Remove this "ugly" verify counter. Remember to initialize myLabel and myAction with NULL

Resources