Fix datepicker arrows style on hover
[cds-indico.git] / indico / MaKaC / webinterface / displayMgr.py
blob49473ffc3fc5d4bcfdccd6c16a9e4aed28d25c99
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 import re
19 from BTrees import OOBTree
20 from persistent import Persistent
21 from MaKaC.common.url import EndpointURL
23 import MaKaC.webinterface.internalPagesMgr as internalPagesMgr
24 from indico.core import signals
25 from indico.core.db import DBMgr
26 from indico.util.contextManager import ContextManager
27 from indico.util.i18n import _, N_
28 from MaKaC.common.Counter import Counter
29 from MaKaC.common.Locators import Locator
30 from MaKaC.webinterface import urlHandlers
31 from MaKaC.trashCan import TrashCanManager
32 from MaKaC.errors import MaKaCError
33 from MaKaC.conference import LocalFile
34 from indico.util.signals import values_from_signal
37 class ConfDisplayMgrRegistery:
38 """
39 Class to get the DisplayMgr for a conference
40 """
42 def __init__(self):
43 self._displayMgrRegistery = None
45 def _getDisplayMgrRegistery( self ):
46 #DBMgr.getInstance().commit()
47 if not self._displayMgrRegistery:
48 db_root = DBMgr.getInstance().getDBConnection().root()
49 if db_root.has_key( "displayRegistery" ):
50 self._displayMgrRegistery = db_root["displayRegistery"]
51 else:
52 self._displayMgrRegistery = OOBTree.OOBTree()
53 db_root["displayRegistery"] = self._displayMgrRegistery
54 return self._displayMgrRegistery
57 def registerDisplayMgr( self, conference, dispMgr ):
58 """Associates a given conference with a confDispplayMgr
59 """
60 self._getDisplayMgrRegistery()[ conference.getId() ] = dispMgr
62 def getDisplayMgr( self, conference, update=False ):
63 """Gives back the webfactory associated with a given conference or None
64 if no association exists
65 """
66 if self._getDisplayMgrRegistery().has_key( conference.getId() ):
67 DM = self._getDisplayMgrRegistery()[ conference.getId() ]
68 # as the object can just coming out the database, we must update the system link of the menu
69 if update:
70 DM.getMenu().updateSystemLink()
71 return DM
72 DM = ConfDisplayMgr(conference, Menu(conference))
73 self.registerDisplayMgr(conference, DM)
74 # as the object just coming out the database, we must update the system link of the menu
75 DM.getMenu().updateSystemLink()
76 return DM
79 class DisplayMgr(Persistent):
80 """
81 base class for the DisplayMgr object
82 """
84 def __init__(self):
85 pass
87 class ConfDisplayMgr(DisplayMgr):
88 """
89 DisplayMgr for a conference
90 """
92 def __init__(self, conf, menu=None, format=None, tickerTape=None):
93 self._conf = conf
94 if menu:
95 self._menu = menu
96 else:
97 self._menu = Menu(self._conf, self)
98 if format:
99 self._format = format
100 else:
101 self._format = Format()
102 if tickerTape:
103 self._tickerTape = tickerTape
104 else:
105 self._tickerTape = TickerTape()
106 self._defaultstyle = ""
107 #################################
108 # Fermi timezone awareness #
109 #################################
110 self.defaulttimezone = ""
111 #################################
112 # Fermi timezone awareness(end) #
113 #################################
115 # Search is enabled, by default
116 self._searchEnabled = True
118 #Manager for all the images stored in the conference
119 self._imagesMngr = ImagesManager(conf)
121 #Manager for CSS file rendering the main display page for the conference
122 self._styleMngr = StyleManager(conf)
124 # Displaying navigation bar
125 self._displayNavigationBar = True
127 self._showSocialApps = True
129 def clone(self, conf):
130 newCdm = ConfDisplayMgrRegistery().getDisplayMgr(conf, update=False)
131 # default style
132 newCdm.setDefaultStyle(self.getDefaultStyle())
133 # clone the menu
134 self.getMenu().clone(newCdm)
135 # clone the format
136 self.getFormat().clone(newCdm)
137 # clone the tickertape
138 self.getTickerTape().clone(newCdm)
139 # clone the imagesmanager
140 self.getImagesManager().clone(newCdm)
141 # clone the imagesmanager
142 self.getStyleManager().clone(newCdm)
143 return newCdm
145 def getDefaultStyle( self ):
146 """Returns the default view of the conference"""
147 try:
148 return self._defaultstyle
149 except:
150 self._defaultstyle = ""
151 return self._defaultstyle
153 def setDefaultStyle( self, style ):
154 self._defaultstyle = style
156 #################################
157 # Fermi timezone awareness #
158 #################################
159 def getDefaultTimezone(self):
160 try:
161 return self._defaulttimezone
162 except:
163 self._defaulttimezone = ""
164 return self._defaulttimezone
166 def setDefaultTimezone(self, tz):
167 self._defaulttimezone = tz
169 #################################
170 # Fermi timezone awareness(end) #
171 #################################
173 def getShowSocialApps(self):
174 if not hasattr(self, '_showSocialApps'):
175 self._showSocialApps = True
176 return self._showSocialApps
178 def setShowSocialApps(self, value):
179 self._showSocialApps = value
181 def getDisplayNavigationBar(self):
182 if not hasattr(self, "_displayNavigationBar"):
183 self._displayNavigationBar = True
184 return self._displayNavigationBar
186 def setDisplayNavigationBar(self, value):
187 self._displayNavigationBar = value
189 def getMenu(self):
190 if self._menu.getParent() is None:
191 self._menu.setParent(self)
192 extra_items = frozenset(x.name for x in values_from_signal(signals.event.sidemenu.send()))
193 if getattr(self, 'extra_items', frozenset()) != extra_items:
194 self._menu.updateSystemLink()
195 self.extra_items = extra_items
196 return self._menu
198 def getConference(self):
199 return self._conf
201 def getFormat(self):
202 try:
203 if self._format:
204 pass
205 except AttributeError, e:
206 self._format = Format()
207 return self._format
209 def getSearchEnabled(self):
210 if ContextManager.get('offlineMode', False):
211 return False
212 try:
213 return self._searchEnabled
214 except AttributeError:
215 self._searchEnabled = True
216 return self._searchEnabled
218 def setSearchEnabled(self, value):
219 self._searchEnabled = value
221 def getTickerTape(self):
222 try:
223 if self._tickerTape:
224 pass
225 except AttributeError, e:
226 self._tickerTape = TickerTape()
227 return self._tickerTape
229 def getImagesManager(self):
230 try:
231 if self._imagesMngr:
232 pass
233 except AttributeError, e:
234 self._imagesMngr = ImagesManager(self._conf)
235 return self._imagesMngr
237 def getStyleManager(self):
238 try:
239 if self._styleMngr:
240 pass
241 except AttributeError, e:
242 self._styleMngr = StyleManager(self._conf)
243 return self._styleMngr
246 class EventMenuEntry(object):
247 """Defines an endpoint-based conference menu entry.
249 :param endpoint: Name of the endpoint for building the link's target URL
250 :param caption: Caption of the link
251 :param parent: Name of the parent link
252 :param name: Name of the link. Defaults to the endpoint.
253 :param plugin: True if the endpoint is in a plugin
254 :param visible: Callback to set the visibility of the link.
255 Invoked with the event as its only argument,
256 must return True or False.
258 def __init__(self, endpoint, caption, parent=None, name=None, plugin=False, visible=None):
259 if plugin:
260 endpoint = 'plugin_{}'.format(endpoint)
261 self.endpoint = endpoint
262 self.caption = caption
263 self.parent = parent or '' # the code actually expects '' and not None for top-level items m(
264 self.name = name or endpoint
265 self.visible = visible
267 def __hash__(self):
268 return hash((self.endpoint, self.name))
270 def __eq__(self, other):
271 return (self.endpoint, self.name) == (other.endpoint, other.name)
273 def __repr__(self):
274 return '<EventMenuEntry({}, {}, {})>'.format(self.name, self.endpoint, self.caption)
277 class Menu(Persistent):
279 class to configure a menu
282 def __init__(self, conf, parent=None):
283 self._listLink = []
284 self._parent = parent
285 self._conf = conf
286 self._indent = "&nbsp;&nbsp;&nbsp;&nbsp;"
287 self._linkGenerator = Counter()
288 self._timetable_detailed_view = False
289 self._timetable_layout = 'normal'
291 def clone(self, cdm):
292 newMenu = cdm.getMenu()
293 newMenu.set_timetable_detailed_view(self.is_timetable_detailed_view())
294 newMenu.set_timetable_layout(self.get_timetable_layout())
295 newMenu._linkGenerator = self._linkGenerator.clone()
296 newList = []
297 for link in self.getLinkList():
298 newList.append(link.clone(newMenu))
299 if len(newList) != 0:
300 newMenu._listLink = newList
302 # change system links to new event id
303 newMenu.updateSystemLink()
305 return newMenu
307 def enable(self):
308 pass
310 def disable(self):
311 pass
313 def getName(self):
314 return ""
316 def getConference(self):
317 return self._conf
319 def updateSystemLink(self):
320 systemLinkData = SystemLinkData(self._conf)
321 linksData = systemLinkData.getLinkData()
322 linksDataOrderedKeys = systemLinkData.getLinkDataOrderedKeys()
324 #remove system links (and sublinks) which are not define in linksData
325 for link in self.getAllLinks()[:]:
326 if isinstance(link, SystemLink):
327 if link.getParent() is not None:
328 if not link.getName() in linksData:
329 link.getParent().removeLink(link)
330 elif link.getParent().getName() != linksData[link.getName()]["parent"]:
331 link.getParent().removeLink(link)
332 elif link.getName() not in linksData:
333 # link was removed from the list
334 self.removeLink(link)
336 #Now, update the system links
337 for name in linksDataOrderedKeys:
338 data = linksData[name]
339 link = self.getLinkByName(name)
340 if link:
341 # only update the caption if it has been already customized
342 if not link.wasChanged() or link.getCaption() == '':
343 link.setCaption(data["caption"], silent=True)
344 link.setURLHandler(data["URL"])
345 link.setDisplayTarget(data.get("displayTarget",""))
346 else:
347 #we must create the link
348 self._createSystemLink(name, linksData)
350 def _createSystemLink(self, name, linksData):
351 data = linksData.get(name, None)
352 if data is None:
353 raise MaKaCError(_("error in the system link structure of the menu"))
354 if data["parent"] == "":
355 #create the link at the fisrt level
356 link = SystemLink(name)
357 link.setCaption(data["caption"], silent=True)
358 link.setURLHandler(data["URL"])
359 self.addLink(link)
360 link.disable()
361 if data.get("visibilityByDefault", True):
362 link.enable()
363 else:
364 #We must check if the parent exist
365 parent = self.getLinkByName(data["parent"])
366 if not parent:
367 self._createSystemLink(data["parent"], linksData)
368 parent = self.getLinkByName(data["parent"])
369 #We can create the link under the parent
370 link = SystemLink(name)
371 link.setCaption(data["caption"], silent=True)
372 link.setURLHandler(data["URL"])
373 parent.addLink(link)
374 link.disable()
375 if data.get("visibilityByDefault", True):
376 link.enable()
378 def _generateNewLinkId( self ):
379 """Returns a new unique identifier for the current conference
380 contributions
382 return str(self._linkGenerator.newCount())
384 def linkHasToBeDisplayed(self, link):
385 if isinstance(link, SystemLink):
386 if link.getName()=="CFA" or link.getName()=="abstractsBook" or link.getName()=="mytracks" or link.getName()=="manageTrack":
387 return self.getConference().hasEnabledSection("cfa")
388 elif link.getName()=="registrationForm" or link.getName()=="registrants":
389 return self.getConference().hasEnabledSection("regForm")
390 else:
391 return True
392 else:
393 return True
395 def getLocator( self ):
396 """Gives back a globaly unique identification encapsulated in a Locator
397 object for the session instance
399 if self._parent == None:
400 return Locator()
401 lconf = self._parent.getConference().getLocator()
402 return lconf
404 def setParent(self, parent):
405 self._parent = parent
407 def getParent(self):
408 return self._parent
410 def getIndent(self):
411 return self._indent
413 def setIndent(self, indent):
414 self._indent = indent
416 def addLink(self, link):
417 self._listLink.append(link)
418 link.setParent(self)
419 id = link.getId()
420 if id == "":
421 id = self._generateNewLinkId()
422 link.setId(id)
423 self._p_changed = 1
425 def removeLink(self, link):
426 if link in self._listLink:
427 self._listLink.remove(link)
428 link.delete()
429 self._p_changed = 1
431 def upLink(self, link):
432 if link in self._listLink:
433 index = self._listLink.index(link)
434 newindex = index - 1
435 while newindex >= 0 and not self.linkHasToBeDisplayed(self._listLink[newindex]):
436 newindex -= 1
437 self._listLink.remove(link)
438 if newindex >= 0:
439 self._listLink.insert(newindex, link)
440 else:
441 self._listLink.append(link)
442 self._p_changed = 1
445 def downLink(self, link):
446 if link in self._listLink:
447 index = self._listLink.index(link)
448 newindex = index+1
449 while newindex < len(self._listLink) and not self.linkHasToBeDisplayed(self._listLink[newindex]):
450 newindex += 1
451 self._listLink.remove(link)
452 if newindex <= len(self._listLink):
453 self._listLink.insert(newindex, link)
454 else:
455 self._listLink.insert(0, link)
456 self._p_changed = 1
458 def getLinkById(self, id):
459 for link in self._listLink:
460 if link.getId() == id:
461 return link
462 ret = link.getLinkById(id)
463 if ret:
464 return ret
465 return None
467 def getLinkByName(self, name):
468 for link in self._listLink:
469 if link.getName() == name:
470 return link
471 ret = link.getLinkByName(name)
472 if ret:
473 return ret
474 return None
476 def getAllLinks(self):
477 l = []
478 for link in self._listLink:
479 if isinstance(link,Spacer):
480 continue
481 l.append(link)
482 l.extend(link._listLink)
483 return l
485 def getLinkList(self):
486 return self._listLink
488 def getEnabledLinkList(self):
489 l = []
490 for link in self._listLink:
491 if link.isEnabled():
492 l.append(link)
493 return l
495 def isCurrentItem(self, item):
496 return self.getCurrentItem() == item
498 def setCurrentItem(self, value):
499 self._v_currentItem = value
501 def getCurrentItem(self):
502 return getattr(self, '_v_currentItem', None)
504 def set_timetable_layout(self, layout):
505 self._timetable_layout = layout
507 def toggle_timetable_layout(self):
508 if self._timetable_layout == 'normal':
509 self.set_timetable_layout('room')
510 else:
511 self.set_timetable_layout('normal')
513 def get_timetable_layout(self):
514 try:
515 return self._timetable_layout
516 except AttributeError:
517 self._timetable_layout = 'normal'
518 return self._timetable_layout
520 def set_timetable_detailed_view(self, view):
521 self._timetable_detailed_view = view
523 def is_timetable_detailed_view(self):
524 try:
525 return self._timetable_detailed_view
526 except AttributeError:
527 self._timetable_detailed_view = False
528 return self._timetable_detailed_view
530 def __str__(self):
531 str = ""
532 for link in self._listLink:
533 if link.isEnabled():
534 str += "%s\n" % link
535 return str
538 class Spacer(Persistent):
539 Type = "spacer"
541 def __init__(self, name="", parent=None):
542 self._name = name
543 self._active = True
544 self._parent = parent
545 self._id = ""
546 self._v_visible=True
548 def clone(self, newMenu):
549 newSpacer = Spacer(name=self.getName(),parent=newMenu)
550 newSpacer.setId(self.getId())
551 newSpacer.setEnabled(self.isEnabled())
552 return newSpacer
554 def getParent(self):
555 return self._parent
557 def getId(self):
558 return self._id
560 def setId(self, id):
561 self._id = id
562 if self._name == "":
563 self._name = "spacer %s"%id
565 def getLocator( self ):
566 """Gives back a globaly unique identification encapsulated in a Locator
567 object for the session instance
569 if self._parent == None:
570 return Locator()
571 lparent = self._parent.getLocator()
572 lparent["linkId"] = self.getId()
573 return lparent
575 def getLinkById(self, id):
576 return None
578 def getLinkByName(self, name):
579 return None
581 def setParent(self, parent):
582 self._parent = parent
584 def getType(self):
585 return self.Type
587 def enable(self):
588 self._active = True
590 def disable(self):
591 self._active = False
593 def setEnabled(self, value):
594 if value:
595 self.enable()
596 else:
597 self.disable()
599 def isEnabled(self):
600 return self._active
602 def setName(self, name):
603 self._name = name
605 def getName(self):
606 return self._name
608 def __str__(self, indent=""):
609 str = """%s<br>\n"""%indent
610 return str
612 def isVisible(self):
613 try:
614 if self._v_visible:
615 pass
616 except AttributeError:
617 self._v_visible=True
618 return self._v_visible
620 def setVisible(self,newValue=True):
621 self._v_visible=newValue
623 def delete(self):
624 TrashCanManager().add(self)
626 def recover(self):
627 TrashCanManager().remove(self)
630 class Link(Persistent):
632 base class for the links of a menu
634 Type = "Link"
636 def __init__(self, name, parent=None):
637 self._name = name
638 self._listLink = []
639 self._active = True
640 self._parent = parent
641 self._id = ""
642 self._caption = ""
643 self._v_visible=True
644 self._displayTarget = ""
646 def getId(self):
647 return self._id
649 def setId(self, id):
650 self._id = id
652 def getParent(self):
653 return self._parent
655 def getLocator( self ):
656 """Gives back a globaly unique identification encapsulated in a Locator
657 object for the session instance
659 if self._parent == None:
660 return Locator()
661 lparent = self._parent.getLocator()
662 lparent["linkId"] = self.getId()
663 return lparent
665 def _generateNewLinkId( self ):
666 """Returns a new unique identifier for the current conference
667 contributions
669 if self._parent:
670 return self._parent._generateNewLinkId()
672 def setParent(self, parent):
673 self._parent = parent
675 def getType(self):
676 return self.Type
678 def getDisplayTarget(self):
679 try:
680 if self._displayTarget:
681 pass
682 except AttributeError, e:
683 self._displayTarget = "_blank"
684 return self._displayTarget
686 def setDisplayTarget(self, t):
687 self._displayTarget = t
689 def enable(self):
690 previousState = self._active
691 self._active = True
692 if not previousState:
693 for link in self._listLink:
694 link.enable()
695 self._p_changed = 1
696 self._parent.enable()
698 def disable(self):
699 self._active = False
700 for link in self._listLink:
701 link.disable()
702 self._p_changed = 1
704 def setEnabled(self, enable):
705 if enable:
706 self.enable()
707 else:
708 self.disable()
710 def isEnabled(self):
711 return self._active
713 def setName(self, name):
714 self._name = name
716 def getName(self):
717 return self._name
719 def setCaption(self, caption):
720 self._caption = caption
722 def getCaption(self):
723 return self._caption
725 def addLink(self, link):
726 self._listLink.append(link)
727 link.setParent(self)
728 id = link.getId()
729 if id == "":
730 id = self._generateNewLinkId()
731 link.setId(id)
732 self._p_changed = 1
734 def removeLink(self, link):
735 if link in self._listLink:
736 self._listLink.remove(link)
737 link.delete()
738 self._p_changed = 1
740 def upLink(self, link):
741 if link in self._listLink:
742 if self._listLink.index(link) != 0:
743 index = self._listLink.index(link)
744 sb = self._listLink.pop(index)
745 self._listLink.insert(index-1, sb)
746 self._p_changed = 1
748 def downLink(self, link):
749 if link in self._listLink:
750 if self._listLink.index(link) < len(self._listLink)-1:
751 index = self._listLink.index(link)
752 sb = self._listLink.pop(index)
753 self._listLink.insert(index+1, sb)
754 self._p_changed = 1
756 def getLinkByName(self, name):
757 for link in self._listLink:
758 if link.getName() == name:
759 return link
760 ret = link.getLinkByName(name)
761 if ret:
762 return ret
763 return None
765 def getLinkById(self, id):
766 for link in self._listLink:
767 if link.getId() == id:
768 return link
769 ret = link.getLinkById(id)
770 if ret:
771 return ret
772 return None
774 def getLinkList(self):
775 return self._listLink
777 def getEnabledLinkList(self):
778 l = []
779 for link in self._listLink:
780 if link.isEnabled():
781 l.append(link)
782 return l
784 def getURL(self):
785 return ""
787 def __str__(self, indent=""):
788 str = """%s<a href="%s">%s</a><br>\n"""%(indent, self.getURL(), self.getName())
789 for link in self._listLink:
790 if link.isEnabled():
791 str += "%s\n"%link.__str__(indent + "&nbsp;&nbsp;&nbsp;&nbsp;")
792 return str
794 def isVisible(self):
795 try:
796 if self._v_visible:
797 pass
798 except AttributeError:
799 self._v_visible=True
800 return self._v_visible
802 def setVisible(self,newValue=True):
803 self._v_visible=newValue
805 def delete(self):
806 for l in self.getLinkList()[:]:
807 self.removeLink(l)
808 TrashCanManager().add(self)
810 def recover(self):
811 TrashCanManager().remove(self)
813 def getMenu(self):
815 Go up till the "parent menu" is found
817 if isinstance(self._parent, Menu):
818 return self._parent
819 else:
820 return self._parent.getMenu()
822 class SystemLink(Link):
824 class for link which target a system part
825 The user cannot change the link data
826 The URL is dynamicly generated
828 Type = "system"
830 def __init__(self, name, parent=None, changed=False):
831 Link.__init__(self, name, parent)
833 # by default, this link will be updated when there are version
834 # changes that modify its default name
835 self._changed = changed
837 def clone(self, newMenu):
838 newLink = SystemLink(self.getName(), parent=newMenu, changed=self.wasChanged())
839 newLink.setEnabled(self.isEnabled())
840 newLink.setVisible(self.isVisible())
841 newLink.setId(self.getId())
842 newLink.setDisplayTarget(self.getDisplayTarget())
843 newLink.setCaption(self.getCaption(), silent=True)
844 newLink.setURLHandler(self.getURLHandler())
846 listLink = []
847 for link in self.getLinkList():
848 listLink.append(link.clone(newLink))
850 newLink._listLink = listLink
852 return newLink
854 def wasChanged(self):
855 # old conferences, before `_changed` was introduced
856 if hasattr(self, '_changed'):
857 return self._changed
858 else:
859 # for old conferences, just keeps things as people
860 # left them
861 return True
863 def _getURLObject(self):
864 # TOREMOVE: fix events with "absolute" URL
865 if not hasattr(self, '_URLHandler'):
866 self.getMenu().updateSystemLink()
867 if isinstance(self._URLHandler, basestring):
868 if self._URLHandler.startswith("http"): # Fix for hardcoded URLs
869 self.getMenu().updateSystemLink()
870 if '.' in self._URLHandler:
871 return EndpointURL(self._URLHandler,
872 urlHandlers.URLHandler._want_secure_url(),
873 urlHandlers.URLHandler._getParams(self.getMenu().getConference(), {}))
874 else:
875 handler = getattr(urlHandlers, self._URLHandler)
876 else:
877 handler = self._URLHandler
878 return handler.getURL(self.getMenu().getConference())
880 def getURL(self):
881 url = str(self._getURLObject())
882 if self._name == 'timetable':
883 menu = self.getMenu()
884 if menu.get_timetable_layout() == 'room':
885 url += '?ttLyt=room'
886 if menu.is_timetable_detailed_view():
887 startDate = menu.getConference().getSchedule().getAdjustedStartDate()
888 url += startDate.strftime('#%Y%m%d')
889 url += '.detailed'
890 return url
892 def getURLHandler(self):
893 if not hasattr(self, '_URLHandler'):
894 self.getMenu().updateSystemLink()
895 return self._URLHandler
897 def setURLHandler(self, url):
898 self._URLHandler = url
900 def getCaption(self):
901 return self._caption
903 def setCaption(self, caption, silent=False):
904 self._caption = caption
906 if not silent:
907 # if the caption was changed, do not update it when the default
908 # value get an update
909 self._changed = True
911 def isVisible(self):
912 return self._getURLObject().valid and super(SystemLink, self).isVisible()
915 class SystemLinkData(object):
916 def __init__(self, conf=None):
917 plugin_entries = None
918 if not hasattr(self, '_linkData') or not hasattr(self, '_linkDataOrderedKeys'):
919 plugin_entries = values_from_signal(signals.event.sidemenu.send())
920 #the following dict is used to update the system link of the menu. each new entry is added to the menu,
921 #and all entries in the menu whiche are not is this dict are removed.
922 if not hasattr(self, "_linkData"):
923 self._linkData = {
924 "overview": {
925 "caption": N_("Overview"),
926 "URL": 'UHConferenceOverview',
927 "parent": ""},
928 "programme": {
929 "caption": N_("Scientific Programme"),
930 "URL": 'UHConferenceProgram',
931 "parent": ""},
932 "CFA": {
933 "caption": N_("Call for Abstracts"),
934 "URL": 'UHConferenceCFA',
935 "parent": ""},
936 "ViewAbstracts": {
937 "caption": N_("View my Abstracts"),
938 "URL": 'UHUserAbstracts',
939 "parent": "CFA"},
940 "SubmitAbstract": {
941 "caption": N_("Submit Abstract"),
942 "URL": 'UHAbstractSubmission',
943 "parent": "CFA"},
944 "manageTrack": {
945 "caption": N_("Manage my Tracks"),
946 "URL": 'UHConfMyStuffMyTracks',
947 "parent": "programme"},
948 "timetable": {
949 "caption": N_("Timetable"),
950 "URL": 'UHConferenceTimeTable',
951 "parent": ""},
952 "contributionList": {
953 "caption": N_("Contribution List"),
954 "URL": 'UHContributionList',
955 "parent": ""},
956 "authorIndex": {
957 "caption": N_("Author List"),
958 "URL": 'UHConfAuthorIndex',
959 "parent": ""},
960 "speakerIndex": {
961 "caption": N_("Speaker List"),
962 "URL": 'UHConfSpeakerIndex',
963 "parent": "",
964 "visibilityByDefault": False},
965 "mystuff": {
966 "caption": N_("My Conference"),
967 "URL": 'UHConfMyStuff',
968 "parent": ""},
969 "mytracks": {
970 "caption": N_("My Tracks"),
971 "URL": 'UHConfMyStuffMyTracks',
972 "parent": "mystuff"},
973 "mysessions": {
974 "caption": N_("My Sessions"),
975 "URL": 'UHConfMyStuffMySessions',
976 "parent": "mystuff"},
977 "mycontribs": {
978 "caption": N_("My Contributions"),
979 "URL": 'UHConfMyStuffMyContributions',
980 "parent": "mystuff"},
981 "paperreviewing": {
982 "caption": N_("Paper Reviewing"),
983 "URL": 'UHPaperReviewingDisplay',
984 "parent": ""},
985 "managepaperreviewing": {
986 "caption": N_("Manage Paper Reviewing"),
987 "URL": 'UHConfModifReviewingPaperSetup',
988 "parent": "paperreviewing"},
989 "assigncontributions": {
990 "caption": N_("Assign Papers"),
991 "URL": 'UHConfModifReviewingAssignContributionsList',
992 "parent": "paperreviewing"},
993 "judgelist": {
994 "caption": N_("Referee Area"),
995 "URL": 'UHConfModifListContribToJudge',
996 "parent": "paperreviewing"},
997 "judgelistreviewer": {
998 "caption": N_("Content Reviewer Area"),
999 "URL": 'UHConfModifListContribToJudgeAsReviewer',
1000 "parent": "paperreviewing"},
1001 "judgelisteditor": {
1002 "caption": N_("Layout Reviewer Area"),
1003 "URL": 'UHConfModifListContribToJudgeAsEditor',
1004 "parent": "paperreviewing"},
1005 "uploadpaper": {
1006 "caption": N_("Upload Paper"),
1007 "URL": 'UHUploadPaper',
1008 "parent": "paperreviewing"},
1009 "downloadtemplate": {
1010 "caption": N_("Download Template"),
1011 "URL": 'UHDownloadPRTemplate',
1012 "parent": "paperreviewing"},
1013 "abstractsBook": {
1014 "caption": N_("Book of Abstracts"),
1015 "URL": 'UHConfAbstractBook',
1016 "parent": "",
1017 "displayTarget": "_blank"},
1018 "registrationForm": {
1019 "caption": N_("Registration"),
1020 "URL": 'UHConfRegistrationForm',
1021 "parent": ""},
1022 "registrants": {
1023 "caption": N_("Participant List"),
1024 "URL": 'UHConfRegistrantsList',
1025 "parent": "",
1026 "visibilityByDefault": False},
1027 "evaluation": {
1028 "caption": N_("Evaluation"),
1029 "URL": 'UHConfEvaluationMainInformation',
1030 "parent": ""},
1031 "newEvaluation": {
1032 "caption": N_("Evaluation Form"),
1033 "URL": 'UHConfEvaluationDisplay',
1034 "parent": "evaluation"},
1035 "viewMyEvaluation": {
1036 "caption": N_("Modify my Evaluation"),
1037 "URL": 'UHConfEvaluationDisplayModif',
1038 "parent": "evaluation"}
1040 for entry in plugin_entries:
1041 assert entry.name not in self._linkData
1042 self._linkData[entry.name] = {
1043 'caption': entry.caption,
1044 'URL': entry.endpoint,
1045 'parent': entry.parent
1048 #this ordered list allow us to keep the order we want for the menu
1049 if not hasattr(self, "_linkDataOrderedKeys"):
1050 self._linkDataOrderedKeys = ["overview",
1051 "programme",
1052 "CFA",
1053 "ViewAbstracts",
1054 "SubmitAbstract",
1055 "manageTrack",
1056 "timetable",
1057 "contributionList",
1058 "authorIndex",
1059 "speakerIndex",
1060 "mystuff",
1061 "mytracks",
1062 "mysessions",
1063 "mycontribs",
1064 "paperreviewing",
1065 "managepaperreviewing",
1066 "assigncontributions",
1067 "judgelist",
1068 "judgelistreviewer",
1069 "judgelisteditor",
1070 "uploadpaper",
1071 "downloadtemplate",
1072 "abstractsBook",
1073 "registrationForm",
1074 "registrants",
1075 "evaluation",
1076 "newEvaluation",
1077 "viewMyEvaluation"]
1078 self._linkDataOrderedKeys += [x.name for x in plugin_entries]
1080 def getLinkData(self):
1081 return self._linkData
1083 def getLinkDataOrderedKeys(self):
1084 self.__init__() # init self._linkDataOrderedKeys if it isn't defined.
1085 return self._linkDataOrderedKeys
1088 class ExternLink(Link):
1090 class for link create by the user to a fixed link
1092 Type = "extern"
1093 def __init__(self, name, URL):
1094 Link.__init__(self, name)
1095 self._URL = URL
1097 def clone(self, newMenu):
1098 newLink = ExternLink(self.getName(),self.getURL())
1099 newLink.setId(self.getId())
1100 newLink.setParent(newMenu)
1101 newLink.setEnabled(self.isEnabled())
1102 newLink.setCaption(self.getCaption())
1103 newLink.setDisplayTarget(self.getDisplayTarget())
1104 return newLink
1106 def getURL(self):
1107 return self._URL
1109 def setURL(self, URL):
1110 self._URL = URL
1112 class PageLink(Link):
1114 class for link create by the user to a fixed link
1116 Type = "page"
1118 def __init__(self, name, page):
1119 Link.__init__(self, name)
1120 self._page = page
1122 def clone(self, newMenu):
1123 conf = newMenu.getConference()
1124 intPagesMgr = internalPagesMgr.InternalPagesMgrRegistery().getInternalPagesMgr(conf)
1125 newPage = self.getPage().clone(conf)
1126 intPagesMgr.addPage(newPage)
1127 newLink = PageLink(self.getName(),newPage)
1128 newLink.setId(self.getId())
1129 newLink.setParent(newMenu)
1130 newLink.setEnabled(self.isEnabled())
1131 newLink.setCaption(self.getCaption())
1132 newLink.setDisplayTarget(self.getDisplayTarget())
1133 return newLink
1135 def setPage(self, page):
1136 self._page=page
1138 def getPage(self):
1139 return self._page
1141 def getURL(self):
1142 return urlHandlers.UHInternalPageDisplay.getURL(self._page)
1145 class _FormatDefaultData:
1147 def __init__(self):
1148 self._data={
1149 "titleBgColor":{"code":"",\
1150 "url":urlHandlers.UHConfModifFormatTitleBgColor}, \
1151 "titleTextColor":{"code":"",\
1152 "url":urlHandlers.UHConfModifFormatTitleTextColor}
1155 def getColor(self,key):
1156 return self._data[key]["code"]
1158 def getURL(self,key):
1159 return self._data[key]["url"]
1162 class Format(Persistent):
1164 def __init__(self):
1165 self._data={}
1166 self._data["titleBgColor"]=_FormatDefaultData().getColor("titleBgColor")
1167 self._data["titleTextColor"]=_FormatDefaultData().getColor("titleTextColor")
1168 self._p_changed = 1
1170 def getFormatOption(self,key):
1171 if self._data.has_key(key):
1172 code=self._data[key]
1173 url=_FormatDefaultData().getURL(key)
1174 return {"code":code,"url":url}
1175 return None
1177 def clone(self, newCdm):
1178 newFormat = newCdm.getFormat()
1179 newFormat.setColorCode("titleBgColor", self.getFormatOption("titleBgColor")["code"])
1180 newFormat.setColorCode("titleTextColor", self.getFormatOption("titleTextColor")["code"])
1181 return newFormat
1183 def setColorCode(self,key,color):
1184 if self._data.has_key(key):
1185 color=self._getCorrectColor(color)
1186 if color is None:
1187 return
1189 self._data[key]=color
1190 self._p_changed = 1
1192 def _getCorrectColor(self, color):
1193 if color == "":
1194 return ""
1196 if not color.startswith("#"):
1197 color = "#%s"%color
1198 m = re.match("^#[0-9A-Fa-f]{6}$", color)
1199 if m:
1200 return color
1201 return None
1203 def clearColorCode(self,key):
1204 self.setColorCode(key, "")
1206 class TickerTape(Persistent):
1208 def __init__(self):
1209 # active will be set to true everytime the now
1210 # happening is enabled or the setText is called
1211 # this to avoid having an extra button in the interface
1212 # for activating the TickerTape
1213 self._active = False
1214 self._text=""
1215 self._enabledNowPlaying = False
1216 self._enabledSimpleText = False
1218 def clone(self, newCdm):
1219 newTT = newCdm.getTickerTape()
1220 newTT.setText(self.getText())
1221 newTT.setActive(self.isActive())
1222 newTT.setNowHappeningEnabled(self.isNowHappeningEnabled())
1223 newTT.setSimpleTextEnabled(self.isSimpleTextEnabled())
1224 return newTT
1226 def getText(self):
1227 return self._text
1229 def setText(self, text):
1230 self._active=True
1231 self._text = text
1233 def isActive(self):
1234 return self._active
1236 def activate(self):
1237 self._active=True
1239 def deactivate(self):
1240 self._active=False
1242 def setActive(self, v):
1243 self._active=v
1245 def isNowHappeningEnabled(self):
1246 try:
1247 if self._enabledNowPlaying:
1248 pass
1249 except AttributeError, e:
1250 self._enabledNowPlaying=False
1251 return self._enabledNowPlaying and self._active
1253 def setNowHappeningEnabled(self, v):
1254 self._active = True
1255 self._enabledNowPlaying = v
1257 def isSimpleTextEnabled(self):
1258 try:
1259 if self._enabledSimpleText:
1260 pass
1261 except AttributeError, e:
1262 self._enabledSimpleText = False
1263 return self._enabledSimpleText and self._active
1265 def setSimpleTextEnabled(self, v):
1266 self._active = True
1267 self._enabledSimpleText=v
1269 class ImageWrapper(Persistent):
1271 It wraps a LocalFile class, just in case we need to add more info to this image
1272 in the future.
1275 def __init__(self, localFile):
1276 self._localFile = localFile
1278 def getId(self):
1279 return self._localFile.getId()
1281 def delete(self):
1282 self._localFile.delete()
1284 def getLocator(self):
1285 loc = self._localFile.getOwner().getLocator()
1286 loc["picId"] = self.getId()
1287 loc["picExt"] = self._localFile.getFileType().lower()
1288 return loc
1290 def clone(self):
1291 lf = self.getLocalFile().clone()
1292 iw = ImageWrapper(lf)
1293 return iw
1295 def getLocalFile(self):
1296 return self._localFile
1298 class ImagesManager(Persistent):
1300 This class manages all the images and pics used by a conference while displaying.
1301 We make difference between the "logo" of the conference and the rest of pictures.
1304 def __init__(self, conf):
1305 self._conf = conf
1306 self._logo = None
1307 self._picList = {}
1308 self._picsCounter = Counter()
1310 def clone(self, newCdm):
1311 newIM = newCdm.getImagesManager()
1312 newIM._conf = newCdm.getConference()
1314 for pic in self.getPicList().values():
1315 lf = pic.getLocalFile()
1316 f = LocalFile()
1317 f.setFileName( lf.getFileName() )
1318 f.setFilePath( lf.getFilePath() )
1319 newIM.addPic(f)
1321 #Logo is not being cloned so far.
1323 return newIM
1325 def notifyModification(self):
1326 self._p_changed = 1
1328 def getPicList(self):
1329 """ function for getting piclist """
1330 try:
1331 if self._picList:
1332 pass
1333 except:
1334 self._picList = {}
1335 return self._picList
1337 def _getPicsCounter(self):
1338 try:
1339 if self._picsCounter:
1340 pass
1341 except:
1342 self._picsCounter = Counter()
1343 return self._picsCounter
1345 def addPic( self, picFile ):
1346 """ function for adding new picture item """
1347 picId = self._getPicsCounter().newCount()
1348 if self.getPicList().has_key(picId) and self.getPicList()[picId] != None:
1349 raise MaKaCError("there is already a pic with the id %s"%picId)
1350 picFile.setOwner( self._conf )
1351 picFile.setId( picId )
1352 picFile.archive( self._conf._getRepository() )
1353 pic = ImageWrapper(picFile)
1354 self.getPicList()[picId] = pic
1355 self.notifyModification()
1356 return pic
1358 def getPic( self,picId ):
1359 if self.getPicList().has_key(picId):
1360 return self.getPicList()[picId]
1361 return None
1363 def removePic(self,picId):
1364 """ function for removing pictures, used in picture uploader """
1365 pic = self.getPic(picId)
1366 if pic is not None:
1367 self.getPicList()[picId].delete()
1368 del self.getPicList()[picId]
1369 self.notifyModification()
1371 # Logo should be migrated to this class in the near future.
1372 def setLogo( self, logoFile ):
1373 logoFile.setOwner( self._conf )
1374 logoFile.setId( "logo" )
1375 logoFile.archive( self._conf._getRepository() )
1376 if self._logo != None:
1377 self._logo.delete()
1378 self._logo = logoFile
1380 def getLogo( self ):
1381 return self._logo
1383 def getLogoURL( self ):
1384 try:
1385 if self._logo == None:
1386 return ""
1387 return self._logo.getURL()
1388 except AttributeError:
1389 self._logo = None
1390 return ""
1392 def removeLogo(self):
1393 if self._logo is None:
1394 return
1395 self._logo.delete()
1396 self._logo = None
1398 def recoverLogo(self, logo):
1399 logo.setOwner(self._conf)
1400 if self._logo != None:
1401 self._logo.delete()
1402 self._logo = logo
1403 logo.recover()
1405 class CSSWrapper(Persistent):
1407 This class will handle the CSS file that is going to be applied
1408 to the conference display. CSS file can be an upload file or a
1409 template we already have. The upload file is an object of the class
1410 LocalFile and the template is just a string with the id (name) of the
1411 template.
1412 The class encapsulates the CSS so the user does not care about if it is
1413 a template or a local file.
1416 def __init__(self, conf, css):
1417 self._conf = conf
1418 self._localFile = css
1420 def getId(self):
1421 return self._localFile.getId()
1423 def getLocator(self):
1424 loc = self._localFile.getOwner().getLocator()
1425 loc["cssId"] = self.getId()
1426 return loc
1428 def clone(self, newSM):
1429 f=None
1430 if self._localFile:
1431 f = LocalFile()
1432 f.setFileName( self._localFile.getFileName() )
1433 f.setFilePath( self._localFile.getFilePath() )
1434 f.setOwner( newSM._conf )
1435 f.setId( "css" )
1436 f.archive( newSM._conf._getRepository() )
1437 newCW = CSSWrapper(self._conf, f)
1438 return newCW
1440 def getURL(self):
1441 from MaKaC.webinterface.urlHandlers import UHConferenceCSS
1442 return UHConferenceCSS.getURL(self._conf)
1444 def getFileName(self, extension=True):
1445 fn =self._localFile.getFileName()
1446 if not extension:
1447 fn = fn.lower().replace(".css","")
1448 return fn
1450 def getFilePath(self):
1451 return self._localFile.getFilePath()
1453 def getSize(self):
1454 return self._localFile.getSize()
1456 def readBin(self):
1457 return self._localFile.readBin()
1459 def delete(self):
1460 self._localFile.delete()
1461 self._localFile=None
1463 class StyleManager(Persistent):
1465 This class manages the CSS customization for a conference.
1468 def __init__(self, conf):
1469 self._conf = conf
1470 self._css = None
1471 self._usingTemplate = None
1473 def clone(self, newCdm):
1474 newSM = newCdm.getStyleManager()
1475 newSM._conf = newCdm.getConference()
1476 newSM._usingTemplate = self._usingTemplate
1477 if self._css:
1478 newSM._css = self._css.clone(newSM)
1480 #Logo is not being cloned so far.
1482 return newSM
1484 def isUsingTemplate(self):
1485 return self._usingTemplate is not None
1487 def useLocalCSS(self):
1488 self._usingTemplate = None
1490 def setCSS( self, cssFile ):
1491 if isinstance(cssFile, str):
1492 # we will use a template but we keep the uploaded css file
1493 from indico.modules import ModuleHolder
1494 self._cssTplsModule = ModuleHolder().getById("cssTpls")
1495 self._usingTemplate = self._cssTplsModule.getCssTplById(cssFile)
1496 else:
1497 # uploaded file
1498 cssFile.setOwner( self._conf )
1499 cssFile.setId( "css" )
1500 cssFile.archive( self._conf._getRepository() )
1501 if self._css != None:
1502 self._css.delete()
1503 self._usingTemplate = None
1504 self._css = CSSWrapper(self._conf, cssFile)
1506 def getLocalCSS( self ):
1507 return self._css
1509 def getCSS(self):
1510 if self._usingTemplate:
1511 return self._usingTemplate
1512 return self.getLocalCSS()
1514 def getCSSURL( self ):
1515 if self.getCSS():
1516 return self.getCSS().getURL()
1517 return None
1519 def removeCSS(self):
1520 if self._css is not None:
1521 self._css.delete()
1522 self._css = None