I'm running Plone 4.3 and have been trying to create a custom portlet. The portlet is simple and should allow the user to upload an image and provide some descriptive text which can be displayed beneath the image.
Here's the code I have so far:
from zope.interface import implements
from zope.formlib import form
from zope import schema
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from plone.app.portlets.portlets import base
from plone.memoize.instance import memoize
from plone.namedfile.field import NamedImage
from plone.directives import form
from z3c.form import field
from plone.app.portlets.browser import z3cformhelper
class IMyImagePortlet(form.Schema):
myimagetitle = schema.TextLine(
title=u"Image title",
description=u"Enter the image title",
default=u"",
required=True)
myimagedescription = schema.TextLine(
title=u"Image text",
description=u"Enter the text which appears below the image",
default=u"",
required=True)
myimage = NamedImage(
title=u"My image",
description=u"Upload an image",
required=True)
class Assignment(base.Assignment):
implements(IMyImagePortlet)
header = u"My Image"
myimagetitle = u""
myimagedescription = u""
myimage = u""
def __init__(self, myimagetitle=None, myimagedescription=None, myimage=None):
self.myimagetitle = myimagetitle
self.myimagedescription = myimagedescription
self.myimage = myimage
#property
def title(self):
"""This property is used to give the title of the portlet in the
"manage portlets" screen.
"""
return u"My image"
class Renderer(base.Renderer):
_template = ViewPageTemplateFile('templates/myimage_portlet.pt')
def __init__(self, *args):
base.Renderer.__init__(self, *args)
#memoize
def myimagetitle(self):
return self.data.myimgaetitle
#memoize
def myimagedescription(self):
return self.data.myimagedescription
#memoize
def myimage(self):
return self.data.myimage
def render(self):
return self._template()
class AddForm(z3cformhelper.AddForm):
fields = field.Fields(IMyImagePortlet)
label = u"Edit image"
description = u"A portlet which can display image with text"
def create(self, data):
return Assignment(**data)
class EditForm(z3cformhelper.EditForm):
fields = field.Fields(IMyImagePortlet)
label = u"Edit image"
description = u"A portlet which can display image with text"
This seems to work as expected and allows me to add a new portlet with a title, image, and image description. However, I've been reading the docs and I couldn't find many examples of creating a portlet with an image upload field, so there may be a better way of doing this.
My issue is that I can't seem to render the image in the template. I've been referring to the docs at https://developer.plone.org/reference_manuals/external/plone.app.dexterity/advanced/files-and-images.html and have the following in my template, but the image is not being displayed:
<div tal:define="picture nocall:context/myimage"
tal:condition="nocall:picture">
<img tal:attributes="src string:${context/absolute_url}/##download/myimage/${picture/filename};
height picture/_height | nothing;
width picture/_width | nothing;"
/>
</div>
We did exactly what you want.
https://github.com/4teamwork/ftw.subsite/tree/master/ftw/subsite/portlets
It's a teaser portlet, unfortunately not in a single package. but you can adapt the code to your needs.
We defined a browser view in image.py:
from Acquisition import aq_inner
from zope.publisher.browser import BrowserView
class ImageView(BrowserView):
"""View the image field of the image portlet. We steal header details
from zope.app.file.browser.file and adapt it to use the dublin
core implementation that the Image object here has."""
def __call__(self):
context = aq_inner(self.context)
image = context.image
self.request.response.setHeader('Content-Type', image.contentType)
self.request.response.write(image.data)
Register with zcml (Important the image view is for your portlet Assignment):
<browser:page
for=".yourportlet.Assignment"
name="image"
class=".image.ImageView"
permission="zope.Public"
/>
In your portlet Renderer you have to define a method, which gets the image (traverse).
from plone.app.portlets.portlets import base
class MyPortletRenderer(base.Renderer)
def image_tag(self):
state = getMultiAdapter((self.context, self.request),
name="plone_portal_state")
portal = state.portal()
assignment_url = \
portal.unrestrictedTraverse(
self.data.assignment_context_path).absolute_url()
return "<img src='%s/%s/##image' alt=''/>" % (
assignment_url,
self.data.__name__)
Now you are able to use the image in your portlet:
<tal:image content="structure view/image_tag />
I don't know if there is a simpler solution.
Naming could be better :-)
But it works and it's tested https://github.com/4teamwork/ftw.subsite/blob/master/ftw/subsite/tests/test_subsiteportlet.py
Related
I posted this as a followup question on Include folium in bokeh tabs, and now as a new question as well.
I´m trying to render the raw HTML-code from my folium map, but it´s not working.. Any ideas? :)
div = Div(
text=map.get_root().render(),
width=x,
height=y
)
I would much rather be able to render my folium map directly into a bokeh Div object instead of running an Flask app on the side.. I have looked into the possibilities of using an iframe, but there seems to be something off with my code here as well:
div.text = """<iframe srcdoc= """ + map.get_root().render() + """ height=""" + y + """ width=""" + x +"""></iframe>"""
I managed to use a Flask app on the side for the folium map and then use the url as src to my iframe, but then I was having trouble updating the content of that map from my bokeh tool.
Feel free to comment on anything of the above, cheers! :)
Update - Testscript:
from bokeh.models.widgets import Div
from bokeh.layouts import row
from bokeh.plotting import curdoc
import folium
def run():
folium_map = folium.Map(location=(60., 20.))
div = Div(
text=folium_map._repr_html_(),
width=500,
height=500,
)
return row(div)
bokeh_layout = run()
doc = curdoc()
doc.add_root(bokeh_layout)
With map.get_root().render(), you have all the HTML page. If you just want an iframe, you can use the method _repr_html_() of the folium map :
div = Div(
text=map._repr_html_(),
width=x,
height=y
)
I need a larger piece of text to use as a heading to label sections of a form in a Vaadin 8 app using the Valo theme.
In previous versions of Vaadin, I recall doing this with a Label that I had somehow assigned a predefined style of "H1" (as in HTML "h1" tag) where that style was part of the Reindeer theme.
I tried and failed to do this in Vaadin 8 by calling Label::addStyleName and passing the constant ValoTheme.LABEL_H1.
Yes, indeed, calling addStyleName on the Label and passing the constant ValoTheme.LABEL_H1 does work, as per the comment by Morfic.
final Label labelPlain = new Label ( "This is a plain Label in Vaadin 8.1.0 Alpha 6." );
final Label labelH1 = new Label ( "This is a 'h1' Label in Vaadin 8.1.0 Alpha 6." );
labelH1.addStyleName ( ValoTheme.LABEL_H1 );
Here is a complete example app, modified from the usual Vaadin archetype vaadin-archetype-application in Vaadin 8.1.0 Alpha 6.
package com.example.try_h1;
import javax.servlet.annotation.WebServlet;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
/**
* This UI is the application entry point. A UI may either represent a browser window
* (or tab) or some part of a html page where a Vaadin application is embedded.
* <p>
* The UI is initialized using {#link #init(VaadinRequest)}. This method is intended to be
* overridden to add component to the user interface and initialize non-component functionality.
*/
#Theme ( "mytheme" )
public class MyUI extends UI {
#Override
protected void init ( VaadinRequest vaadinRequest ) {
final VerticalLayout layout = new VerticalLayout ( );
final Label labelPlain = new Label ( "This is a plain Label in Vaadin 8.1.0 Alpha 6." );
final Label labelH1 = new Label ( "This is a 'h1' Label in Vaadin 8.1.0 Alpha 6." );
labelH1.addStyleName ( ValoTheme.LABEL_H1 );
layout.addComponents ( labelPlain, labelH1 );
setContent ( layout );
}
#WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
#VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
public static class MyUIServlet extends VaadinServlet {
}
}
Screenshot of running that example app.
addStyleName versus setStyleName
Be careful to call addStyleName rather than setStyleName. That second one clears all existing styles, replacing with your one style argument. This is not what you want, as you’ll lose all the existing styles assigned by the Vaadin framework.
Is there a way to control the placement and alignment of ipywidgets (inside jupyter notebook)?
from ipywidgets import widgets
from IPython.display import Javascript, display
event_type_ui = widgets.Text(value='open', description='Test Event')
platform_ui = widgets.Text(value='Android', description='Control Event')
display(event_type_ui)
display(platform_ui)
I would like to specify an offset (in pixels?) to allow the label to fit and to have two controls aligned vertically.
After some fiddling, I was able to get this:
Before:
After:
Here is a copy-paste snippet, if interested:
from ipywidgets import widgets
from IPython.display import Javascript, display
align_kw = dict(
_css = (('.widget-label', 'min-width', '20ex'),),
margin = '0px 0px 5px 12px'
)
platform_ui = widgets.Dropdown(description = 'platform',options=['iPhone','iPad','Android'], **align_kw)
event_type_ui = widgets.Text(value='open', description='Test Event', **align_kw)
os_version_ui = widgets.Text(value='iOS9', description='Operating System', **align_kw)
refresh_ui = widgets.Checkbox(description='Force Refresh', **align_kw)
display(platform_ui,event_type_ui,os_version_ui,refresh_ui)
The layout and styling documentation for ipywidgets says:
Every Jupyter interactive widget has a layout attribute exposing a number of css properties that impact how widgets are laid out.
I was able to coax it into aligning the labels:
from ipywidgets import Text, HBox, VBox, Box
from IPython.display import display
widget1 = Text(value='Cats', description='Test Event', layout='margin-right:5px')
widget2 = Text(value='Oranges', description='Another Test Event')
widget1.width = '200px'
widget2.width = '150px'
display(VBox([widget1, widget2]))
to produced this:
But in general, I doesn't seem like we can directly target layout properties of the description label, just the entire widget itself.
The ipywidgets also have an add_class that can be used for getting into the weeds when you really need it:
import ipywidgets as widgets
from IPython.display import display, HTML
widget_list={}
for label in ("longish description","brief"):
widget_list[label]=widgets.Text(description=label)
widget_list[label].add_class("balanced-text")
display(HTML("<style>div.balanced-text .widget-label {max-width:200px; width:200px}</style>"))
display(widgets.VBox(list(widget_list.values())))
I'm writing a simple tool menu for Maya, and I'd like to stick it to the border of model panel (perspective).
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class TestWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent = self.getMayaWindow())
self.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint)
self.setFixedSize(100, 100)
panelPtr = omui.MQtUtil.findControl('modelPanel4')
panel = wrapInstance(long(panelPtr), QtGui.QWidget)
position = panel.mapToGlobal(panel.pos())
self.move(position.x(), position.y() + panel.geometry().height() / 2 - self.geometry().height() / 2)
mainLayout = QtGui.QVBoxLayout(self)
button = QtGui.QPushButton('CLOSE')
button.setFixedSize(80, 80)
button.clicked.connect(self.deleteLater)
mainLayout.addWidget(button)
def getMayaWindow(self):
omui.MQtUtil.mainWindow()
ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(ptr), QtGui.QWidget)
w = TestWidget()
w.show()
The main widget is positioned exactly where I want when it is created (horizontally on the left side of model panel, vertically - in the middle of model panel).
I need to reposition it accordingly when the model panel is resized, but model panel does not emit resized() signal. I'd appreciate any advise.
I've been trying many things to get this working yesterday. I did some additionnal researches today and came to this topic: cgsociety: Creating a floating button inside the viewport
In case of broken link, this is one of the answer:
You can use geometry but there are some issues with triggering
commands based on selection and the undo queue. If you want to go that
route, I would suggest looking into zooHud and zooTriggers (Part of
the zooToolbox)
If you are wanting actual GUI control parented to the viewport, mel
only offers hudslider, hudbutton, and headsUpMessage.
You can also use PyQt and parent in your own custom widgets/layouts or
whatever you want using something like this:
import maya.OpenMayaUI as apiUI import sip
from PyQt4 import QtGui
view = apiUI.M3dView()
apiUI.M3dView.getM3dViewFromModelPanel('modelPanel4', view)
viewWidget = sip.wrapinstance(long(view.widget()), QtCore.QObject)
global myBtn
myBtn = QtGui.QPushButton(viewWidget)
myBtn.setText('testing!')
myBtn.move(100, 100) #Relative to top-left corner of viewport myBtn.show()
You can do anything a full qt widget can do with that, so it's
extremely flexible. but it would require having PyQt installed, which
can be a barrier depending on your tools distribution.
I did a mix of this answer and your code:
from PySide import QtCore, QtGui
from maya import OpenMayaUI as omui
from shiboken import wrapInstance
class CustomQWidget(QtGui.QWidget):
def __init__(self, *args, **kwargs):
QtGui.QWidget.__init__(self, *args, **kwargs)
mainLayout = QtGui.QVBoxLayout(self)
closeButton = QtGui.QPushButton('CLOSE')
closeButton.setFixedSize(80, 40)
closeButton.clicked.connect(self.deleteLater)
helloButton = QtGui.QPushButton('HELLO')
helloButton.setFixedSize(80, 40)
helloButton.clicked.connect(self.printHello)
#Trying to fix glitchy background / Doesn't work, why?
#Is it because layouts don't have background?
p = self.palette()
p.setColor(self.backgroundRole(), QtCore.Qt.red)
self.setPalette(p)
self.setAttribute(QtCore.Qt.WA_StyledBackground, True)
##############################
mainLayout.addWidget(closeButton)
mainLayout.addWidget(helloButton)
def printHello(self):
print "Hello"
view = omui.M3dView()
omui.M3dView.getM3dViewFromModelPanel('modelPanel4', view) #Given the name of a model panel,
#get the M3dView used by that panel. If this fails, then a panel with the given name could not be located.
viewWidget = wrapInstance(long(view.widget()), QtGui.QWidget)
position = viewWidget.mapToGlobal(viewWidget.pos())
w = CustomQWidget(viewWidget)
w.move(0, viewWidget.geometry().height() / 2 - 100 / 2) #Relative to middle-left corner of viewport
w.show()
One of the issue I have it that the background of the widget is glitched:
If anyone knows why and how to fix it, I'll edit my answer with pleasure.
Else, when running this script from Maya's script editor, the widget follows the panel when it is resized.
I did fix such a problem, but not using Python/PyQt.
The problem itself is, that your Qt Widget is there. I have not found a way to make it not paint its background.
My solution was different: I derived from a Qt Layout, pushed all my widgets into that layout and used MQtUtil to get the QWidget of that modelPanel's modelEditor to attach the "real Qt layout" to it.
Heavy caveat that may make Python not suited: Maya doesn't expect "non-Maya" Layouts to be bound to "real-Maya" Widgets like modelEditors. So you need to listen to QEvents and find out when to destroy your layout, so Maya doesn't crash trying.
set autofillbackground True to fix your background painting issue
Maybe a simple question but I'm having alot of trouble making a button change the view of a Flex blackberry playbook app. I am coding it entirely in actionscript, no MXML.
myButton.addEventListener(MouseEvent.CLICK, doSomethingOnClick);
private function doSomethingOnClick(e:MouseEvent):void {
navigator.pushView(view.Login, "testdata");
}
When I try this I get:
1120: Access of undefined property navigator.
Which is weird as it works in a MXML file. How do I change views in actionscript?
Thanks
Phil
EDIT:
Cheer J_A_X, but now i have:
navigator = new ViewNavigator();
navigator.pushView(net.airpoint.assessments.view.Login, " ");
TypeError: Error #1009: Cannot access a property or method of a null object reference.
Apologies, as I realise this is really simple stuff but it just isnt clicking!
Update 2
*Assessments.as*
package
{
import flash.display.Sprite;
import flash.events.Event;
import net.airpoint.assessments.view.*;
import qnx.ui.core.Container;
import qnx.ui.core.ContainerAlign;
import qnx.ui.core.ContainerFlow;
import qnx.ui.core.Containment;
import qnx.ui.text.Label;
import spark.components.ViewNavigator;
[SWF(height="600", width="1024", frameRate="30", backgroundColor="#FFFFFF")]
/* Main Layout */
public class Assessments extends Sprite
{
//containers
private var main:Container;
private var menu:Container
private var firstLabel:Label;
private var navigator:ViewNavigator;
public function Assessments()
{
initializeUI();
}
private function initializeUI():void
{
main = new Container();
main.padding = Vector.<Number>([20,20,20,20]);
main.flow = ContainerFlow.HORIZONTAL;
main.debugColor = 0xFFCC00;
firstLabel = new Label();
firstLabel.text = "First label";
firstLabel.size=35;
main.addChild(firstLabel);
addChild(main);
navigator = new ViewNavigator();
navigator.pushView(Login, " ");
}
}
}
Login.as
package net.airpoint.assessments.view
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import qnx.ui.buttons.Button;
import qnx.ui.core.Container;
import qnx.ui.text.Label;
import qnx.ui.text.TextInput;
import spark.components.View;
public class Login extends View
{
private var usernameLabel:Label;
public function Login()
{
initializeUI();
}
public function initializeUI():void
{
usernameLabel.text = "test";
this.addChild(usernameLabel);
}
}
}
Something isn't right. If it's a Flex Mobile Project, you need an Application at the top level (you know, like how Flash Builder created the project with an mxml file). Either you create an actionscript file that extends Application as mentioned here or you just use an mxml file for the root component.
However, your argument to 'not use mxml' is redundant if you're using Flex components. If you're using Flex components, you're using mxml no matter what, so there's no performance increase. If anything, RIM is recommending to use AS only because their SDK is AS only (which is idiotic anyways). You could always add their UI component through AS in mxml files.
So really, the point is moot and you should just use mxml anyways since it's better than straight AS for UI layout and skinning. Either that or go Pure AS with no Flex components.
I think using Sprite is ok in an ActionScript project.
But if you're using ActionScript instead of Flex just because of the QNX components, then you could switch your project to Flex and follow these instructions to use the QNX components there: Using qnx.ui.picker.Picker in mobile Flex Hero project for Blackberry Playbook