Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-10-21 Thread Nyall Dawson
On Tue, 23 Jan 2018 at 22:34, Enrico Ferreguti  wrote:
>
> I'm trying to programmatically set a QgsLayoutPicture content in QGIS3.0:
>
> 1) I create a new print composition and I name it 'test'
> 2) I create a picture frame in the composition and I call it 'picture'
> 3) I run the following code:
>
> from qgis.core import QgsProject
> myLayout = QgsProject.instance().layoutManager().layoutByName('test')
> myLayoutPicture = myLayout.itemById("picture")
> myLayoutPicture.setPicturePath("path to an image")
>
> and I get the following Exception:
> AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
>
> If I inspect myLayoutPicture object I found it is a qgis._core.QgsLayoutItem 
> not a QgsLayoutPicture
>
> Is this a correct behaviour or is it an issue? How can I get the right Layout 
> object?

Coming back to this older discussion -- last week a workaround was
pushed to 3.3 master to try and avoid this issue. I'd love for
widespread testing of the currently nightlies to confirm that the
issue is now fixed (or not)! If anyone is still hitting this issue,
please report here the build number and what method you are calling to
retrieve a layout item.

Fingers crossed :) would be great to have this solved for 3.4!
Nyall


>
> Regards.
> Enrico Ferreguti
> ___
> QGIS-Developer mailing list
> QGIS-Developer@lists.osgeo.org
> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-24 Thread Nyall Dawson
On 24 January 2018 at 19:20, Etienne Trimaille
 wrote:
> Is-it possible to remove this function from SIP bindings? According to SIP
> version?
>

Unfortunately I don't think this would help - we'd have to remove
every method which returns a QgsLayoutItem to do so - and there's some
things in API which are only possible with these methods. It's also
proven to be an issue even in the most recent Qt and SIP versions, so
we'd have to just remove these methods from the bindings full stop.
There's also underlying Qt base classes which returns these items
which we can't control (eg QGraphicsScene::items() ).

> It's a common issue, already raised on the mailing list and in plugin issue
> trackers.

I think the real solution is to get it fixed upstream.

> I'm copy/pasting another message/snippet from Martin which works perfectly:
>
> Not sure if that is related, was just looking into code of a plugin we
> use with QGIS 2.18 and there for getting composer items we have this
> helper method:
>
> @staticmethod
> def get_composition_item(comp, item_id, item_class):
> for item in comp.items():
> if isinstance(item, item_class):
> if item.id() == item_id:
> return item
>
> And you would call it e.g.:
> ver_label = self.get_composition_item(self.oview_compn, 'version',
> QgsComposerLabel)

I don't see how this helps though - unless some magic in the
isinstance call forces sip to correctly cast the item type? Martin?

> Not sure if that is to work around the same problem as you have - I
> didn't write that code. And to get composer map items, we use
> composition.getComposerMapById(id)

That's gone in 3.0 ;) Map ids where old and crufty, and now everything
is done with the uuids. But unfortunately the methods for retrieving
items by uuid all return a QgsLayoutItem pointer, so will suffer the
same sip casting bug.

It's bad all round. That's why I think we need to try as hard as
possible to get this resolved upstream so we can do away with all the
hacks.

Nyall
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-24 Thread Enrico Ferreguti
I'm testing the code under QGIS3, but I fear that
isinstance(item, item_class), in my case: isinstance(item,
QgsLayoutItemPicture)
returns always false because item is of QgsLayoutItem generic class

Nyall's workaround works for me without exceptions:

from qgis.core import QgsProject, QgsLayoutItemPicture
import sip
myLayout = QgsProject.instance().layoutManager().layoutByName('test')
myLayoutPicture =
sip.cast(myLayout.itemById("picture"),QgsLayoutItemPicture)
myLayoutPicture.setPicturePath("path to an image")


2018-01-24 10:20 GMT+01:00 Etienne Trimaille :

> Is-it possible to remove this function from SIP bindings? According to SIP
> version?
>
> It's a common issue, already raised on the mailing list and in plugin
> issue trackers.
>
> I'm copy/pasting another message/snippet from Martin which works perfectly:
>
> Not sure if that is related, was just looking into code of a plugin we
> use with QGIS 2.18 and there for getting composer items we have this
> helper method:
>
> @staticmethod
> def get_composition_item(comp, item_id, item_class):
> for item in comp.items():
> if isinstance(item, item_class):
> if item.id() == item_id:
> return item
>
> And you would call it e.g.:
> ver_label = self.get_composition_item(self.oview_compn, 'version',
> QgsComposerLabel)
>
> Not sure if that is to work around the same problem as you have - I
> didn't write that code. And to get composer map items, we use
> composition.getComposerMapById(id)
>
> 2018-01-24 10:09 GMT+03:00 Nyall Dawson :
>
>> On 23 January 2018 at 22:34, Enrico Ferreguti 
>> wrote:
>> > I'm trying to programmatically set a QgsLayoutPicture content in
>> QGIS3.0:
>> >
>> > 1) I create a new print composition and I name it 'test'
>> > 2) I create a picture frame in the composition and I call it 'picture'
>> > 3) I run the following code:
>> >
>> > from qgis.core import QgsProject
>> > myLayout = QgsProject.instance().layoutManager().layoutByName('test')
>> > myLayoutPicture = myLayout.itemById("picture")
>> > myLayoutPicture.setPicturePath("path to an image")
>> >
>> > and I get the following Exception:
>> > AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
>> >
>> > If I inspect myLayoutPicture object I found it is a
>> qgis._core.QgsLayoutItem
>> > not a QgsLayoutPicture
>> >
>> > Is this a correct behaviour or is it an issue? How can I get the right
>> > Layout object?
>>
>> This became an issue after a certain sip version. It affects QGIS 2.x
>> also, and seems to be caused by sip being unable to automatically cast
>> classes which use multiple inheritance (like QgsComposerItem,
>> QgsLayoutItem). The consequence is that Python is only aware of the
>> base class, not the actual item subclass.
>>
>> I can't find anyway to fix this properly. So I hack around by forcing
>> sip to manually cast to the correct item type, e.g. by inserting two
>> lines* which look like this:
>>
>> # screw you sip, I'll just manually cast
>> real_item = sip.cast(item, QgsLayoutItemPicture)
>>
>> It's not pretty, but it works...
>>
>> Nyall
>>
>> * the first line is critical for the fix to work correctly
>> ___
>> QGIS-Developer mailing list
>> QGIS-Developer@lists.osgeo.org
>> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>>
>
>
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-24 Thread Etienne Trimaille
Is-it possible to remove this function from SIP bindings? According to SIP
version?

It's a common issue, already raised on the mailing list and in plugin issue
trackers.

I'm copy/pasting another message/snippet from Martin which works perfectly:

Not sure if that is related, was just looking into code of a plugin we
use with QGIS 2.18 and there for getting composer items we have this
helper method:

@staticmethod
def get_composition_item(comp, item_id, item_class):
for item in comp.items():
if isinstance(item, item_class):
if item.id() == item_id:
return item

And you would call it e.g.:
ver_label = self.get_composition_item(self.oview_compn, 'version',
QgsComposerLabel)

Not sure if that is to work around the same problem as you have - I
didn't write that code. And to get composer map items, we use
composition.getComposerMapById(id)

2018-01-24 10:09 GMT+03:00 Nyall Dawson :

> On 23 January 2018 at 22:34, Enrico Ferreguti  wrote:
> > I'm trying to programmatically set a QgsLayoutPicture content in QGIS3.0:
> >
> > 1) I create a new print composition and I name it 'test'
> > 2) I create a picture frame in the composition and I call it 'picture'
> > 3) I run the following code:
> >
> > from qgis.core import QgsProject
> > myLayout = QgsProject.instance().layoutManager().layoutByName('test')
> > myLayoutPicture = myLayout.itemById("picture")
> > myLayoutPicture.setPicturePath("path to an image")
> >
> > and I get the following Exception:
> > AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
> >
> > If I inspect myLayoutPicture object I found it is a
> qgis._core.QgsLayoutItem
> > not a QgsLayoutPicture
> >
> > Is this a correct behaviour or is it an issue? How can I get the right
> > Layout object?
>
> This became an issue after a certain sip version. It affects QGIS 2.x
> also, and seems to be caused by sip being unable to automatically cast
> classes which use multiple inheritance (like QgsComposerItem,
> QgsLayoutItem). The consequence is that Python is only aware of the
> base class, not the actual item subclass.
>
> I can't find anyway to fix this properly. So I hack around by forcing
> sip to manually cast to the correct item type, e.g. by inserting two
> lines* which look like this:
>
> # screw you sip, I'll just manually cast
> real_item = sip.cast(item, QgsLayoutItemPicture)
>
> It's not pretty, but it works...
>
> Nyall
>
> * the first line is critical for the fix to work correctly
> ___
> QGIS-Developer mailing list
> QGIS-Developer@lists.osgeo.org
> List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
> Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer
>
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-23 Thread Nyall Dawson
On 23 January 2018 at 22:34, Enrico Ferreguti  wrote:
> I'm trying to programmatically set a QgsLayoutPicture content in QGIS3.0:
>
> 1) I create a new print composition and I name it 'test'
> 2) I create a picture frame in the composition and I call it 'picture'
> 3) I run the following code:
>
> from qgis.core import QgsProject
> myLayout = QgsProject.instance().layoutManager().layoutByName('test')
> myLayoutPicture = myLayout.itemById("picture")
> myLayoutPicture.setPicturePath("path to an image")
>
> and I get the following Exception:
> AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
>
> If I inspect myLayoutPicture object I found it is a qgis._core.QgsLayoutItem
> not a QgsLayoutPicture
>
> Is this a correct behaviour or is it an issue? How can I get the right
> Layout object?

This became an issue after a certain sip version. It affects QGIS 2.x
also, and seems to be caused by sip being unable to automatically cast
classes which use multiple inheritance (like QgsComposerItem,
QgsLayoutItem). The consequence is that Python is only aware of the
base class, not the actual item subclass.

I can't find anyway to fix this properly. So I hack around by forcing
sip to manually cast to the correct item type, e.g. by inserting two
lines* which look like this:

# screw you sip, I'll just manually cast
real_item = sip.cast(item, QgsLayoutItemPicture)

It's not pretty, but it works...

Nyall

* the first line is critical for the fix to work correctly
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-23 Thread Alexander Bruy
2018-01-23 14:34 GMT+02:00 Enrico Ferreguti :
> from qgis.core import QgsProject
> myLayout = QgsProject.instance().layoutManager().layoutByName('test')
> myLayoutPicture = myLayout.itemById("picture")
> myLayoutPicture.setPicturePath("path to an image")
>
> and I get the following Exception:
> AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'

Which QGIS revision do you use? I can not reproduce your issue on master,
all works as expected.

-- 
Alexander Bruy
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Re: [QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-23 Thread Alessandro Pasotti
On Tue, Jan 23, 2018 at 1:34 PM, Enrico Ferreguti 
wrote:

> I'm trying to programmatically set a QgsLayoutPicture content in QGIS3.0:
>
> 1) I create a new print composition and I name it 'test'
> 2) I create a picture frame in the composition and I call it 'picture'
> 3) I run the following code:
>
> from qgis.core import QgsProject
> myLayout = QgsProject.instance().layoutManager().layoutByName('test')
> myLayoutPicture = myLayout.itemById("picture")
>
myLayoutPicture.setPicturePath("path to an image")
>
> and I get the following Exception:
> AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'
>
> If I inspect myLayoutPicture object I found it is a
> qgis._core.QgsLayoutItem not a QgsLayoutPicture
>
> Is this a correct behaviour or is it an issue? How can I get the right
> Layout object?
>

Yes, it is the correct behavior, the method returns  a pointer to the base
class which is QgsLayoutItem.

In the C++ API there is a template method to retrieve all objects of a
certain type but it's not exposed to Python (that's not even possible with
current SIP I think):

template void layoutItems( QList  ) const SIP_SKIP

Sorry but I don't have an answer to your last question.

-- 
Alessandro Pasotti
w3:   www.itopen.it
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

[QGIS-Developer] QgsLayout.itemById returns wrong object

2018-01-23 Thread Enrico Ferreguti
I'm trying to programmatically set a QgsLayoutPicture content in QGIS3.0:

1) I create a new print composition and I name it 'test'
2) I create a picture frame in the composition and I call it 'picture'
3) I run the following code:

from qgis.core import QgsProject
myLayout = QgsProject.instance().layoutManager().layoutByName('test')
myLayoutPicture = myLayout.itemById("picture")
myLayoutPicture.setPicturePath("path to an image")

and I get the following Exception:
AttributeError: 'QgsLayoutItem' object has no attribute 'setPicturePath'

If I inspect myLayoutPicture object I found it is a
qgis._core.QgsLayoutItem not a QgsLayoutPicture

Is this a correct behaviour or is it an issue? How can I get the right
Layout object?

Regards.
Enrico Ferreguti
___
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer