[FIX] Cloned conferences inheriting system links
[cds-indico.git] / indico / MaKaC / webinterface / displayMgr.py
blobd116576ddba4860e29248d71f2f5e96371bcfad2
1 # -*- coding: utf-8 -*-
2 ##
3 ##
4 ## This file is part of CDS Indico.
5 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6 ##
7 ## CDS Indico is free software; you can redistribute it and/or
8 ## modify it under the terms of the GNU General Public License as
9 ## published by the Free Software Foundation; either version 2 of the
10 ## License, or (at your option) any later version.
12 ## CDS Indico is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ## General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 from MaKaC.common import DBMgr
22 from BTrees import OOBTree
23 from persistent import Persistent
24 from MaKaC.common.Counter import Counter
25 from MaKaC.common.Locators import Locator
26 from MaKaC.webinterface import urlHandlers
27 from MaKaC.trashCan import TrashCanManager
28 import MaKaC.webinterface.internalPagesMgr as internalPagesMgr
29 from MaKaC.errors import MaKaCError
30 from MaKaC.conference import LocalFile
31 from MaKaC.plugins.base import Observable
32 import re
33 from MaKaC.i18n import _
35 class ConfDisplayMgrRegistery:
36 """
37 Class to get the DisplayMgr for a conference
38 """
40 def __init__(self):
41 self._displayMgrRegistery = None
43 def _getDisplayMgrRegistery( self ):
44 #DBMgr.getInstance().commit()
45 if not self._displayMgrRegistery:
46 db_root = DBMgr.getInstance().getDBConnection().root()
47 if db_root.has_key( "displayRegistery" ):
48 self._displayMgrRegistery = db_root["displayRegistery"]
49 else:
50 self._displayMgrRegistery = OOBTree.OOBTree()
51 db_root["displayRegistery"] = self._displayMgrRegistery
52 return self._displayMgrRegistery
55 def registerDisplayMgr( self, conference, dispMgr ):
56 """Associates a given conference with a confDispplayMgr
57 """
58 self._getDisplayMgrRegistery()[ conference.getId() ] = dispMgr
60 def getDisplayMgr( self, conference, update=False ):
61 """Gives back the webfactory associated with a given conference or None
62 if no association exists
63 """
64 if self._getDisplayMgrRegistery().has_key( conference.getId() ):
65 DM = self._getDisplayMgrRegistery()[ conference.getId() ]
66 # as the object can just coming out the database, we must update the system link of the menu
67 if update:
68 DM.getMenu().updateSystemLink()
69 return DM
70 DM = ConfDisplayMgr(conference, Menu(conference))
71 self.registerDisplayMgr(conference, DM)
72 # as the object just coming out the database, we must update the system link of the menu
73 DM.getMenu().updateSystemLink()
74 return DM
77 class DisplayMgr(Persistent):
78 """
79 base class for the DisplayMgr object
80 """
82 def __init__(self):
83 pass
85 class ConfDisplayMgr(DisplayMgr):
86 """
87 DisplayMgr for a conference
88 """
90 def __init__(self, conf, menu=None, format=None, tickerTape=None):
91 self._conf = conf
92 if menu:
93 self._menu = menu
94 else:
95 self._menu = Menu(self._conf, self)
96 if format:
97 self._format = format
98 else:
99 self._format = Format()
100 if tickerTape:
101 self._tickerTape = tickerTape
102 else:
103 self._tickerTape = TickerTape()
104 self._defaultstyle = ""
105 #################################
106 # Fermi timezone awareness #
107 #################################
108 self.defaulttimezone = ""
109 #################################
110 # Fermi timezone awareness(end) #
111 #################################
113 # Search is enabled, by default
114 self._searchEnabled = True
116 #Manager for all the images stored in the conference
117 self._imagesMngr = ImagesManager(conf)
119 #Manager for CSS file rendering the main display page for the conference
120 self._styleMngr = StyleManager(conf)
122 # Caption for the email support
123 self._supportEmailCaption = "Support"
125 # Displaying navigation bar
126 self._displayNavigationBar = True
128 def clone(self, conf):
129 newCdm = ConfDisplayMgrRegistery().getDisplayMgr(conf, update=False)
130 # default style
131 newCdm.setDefaultStyle(self.getDefaultStyle())
132 # clone the menu
133 self.getMenu().clone(newCdm)
134 # clone the format
135 self.getFormat().clone(newCdm)
136 # clone the tickertape
137 self.getTickerTape().clone(newCdm)
138 # clone the imagesmanager
139 self.getImagesManager().clone(newCdm)
140 # clone the imagesmanager
141 self.getStyleManager().clone(newCdm)
142 return newCdm
144 def getDefaultStyle( self ):
145 """Returns the default view of the conference"""
146 try:
147 return self._defaultstyle
148 except:
149 self._defaultstyle = ""
150 return self._defaultstyle
152 def setDefaultStyle( self, style ):
153 self._defaultstyle = style
155 #################################
156 # Fermi timezone awareness #
157 #################################
158 def getDefaultTimezone(self):
159 try:
160 return self._defaulttimezone
161 except:
162 self._defaulttimezone = ""
163 return self._defaulttimezone
165 def setDefaultTimezone(self, tz):
166 self._defaulttimezone = tz
168 #################################
169 # Fermi timezone awareness(end) #
170 #################################
173 def getDisplayNavigationBar(self):
174 if not hasattr(self, "_displayNavigationBar"):
175 self._displayNavigationBar = True
176 return self._displayNavigationBar
178 def setDisplayNavigationBar(self, value):
179 self._displayNavigationBar = value
181 def getMenu(self):
182 if self._menu.getParent() == None:
183 self._menu.setParent(self)
184 return self._menu
186 def getConference(self):
187 return self._conf
189 def getFormat(self):
190 try:
191 if self._format:
192 pass
193 except AttributeError, e:
194 self._format = Format()
195 return self._format
197 def getSearchEnabled(self):
198 # check if _SearchEnabled exists in the db structure
199 try:
200 return self._searchEnabled
201 except AttributeError:
202 self._searchEnabled = True
203 return self._searchEnabled
205 def setSearchEnabled(self, value):
206 self._searchEnabled = value
208 def getTickerTape(self):
209 try:
210 if self._tickerTape:
211 pass
212 except AttributeError, e:
213 self._tickerTape = TickerTape()
214 return self._tickerTape
216 def getImagesManager(self):
217 try:
218 if self._imagesMngr:
219 pass
220 except AttributeError, e:
221 self._imagesMngr = ImagesManager(self._conf)
222 return self._imagesMngr
224 def getStyleManager(self):
225 try:
226 if self._styleMngr:
227 pass
228 except AttributeError, e:
229 self._styleMngr = StyleManager(self._conf)
230 return self._styleMngr
232 def getSupportEmailCaption(self):
233 # check if _supportEmailCaption exists in the db
234 if not hasattr(self, "_supportEmailCaption"):
235 self._supportEmailCaption = "Support"
236 return self._supportEmailCaption
238 def setSupportEmailCaption(self, value):
239 self._supportEmailCaption = value
241 class Menu(Persistent):
243 class to configure a menu
246 def __init__(self, conf, parent=None):
247 self._listLink = []
248 self._parent = parent
249 self._conf = conf
250 self._indent = "    "
251 self._linkGenerator = Counter()
252 self._currentItem = None
254 def clone( self, cdm ):
255 newMenu = cdm.getMenu()
256 newMenu._linkGenerator = self._linkGenerator.clone()
257 newList = []
258 for link in self.getLinkList():
259 # TODO: remove this, as it is just a workaround caused by a previous
260 # version in which removed links were not properly destroyed
261 if hasattr(link, '_URL'):
262 newList.append(link.clone(newMenu))
263 if len(newList) != 0:
264 newMenu._listLink = newList
266 # change system links to new event id
267 newMenu.updateSystemLink()
269 return newMenu
271 def enable(self):
272 pass
274 def disable(self):
275 pass
277 def getName(self):
278 return ""
280 def getConference(self):
281 return self._conf
283 def updateSystemLink(self):
284 systemLinkData = SystemLinkData(self._conf)
285 linksData = systemLinkData.getLinkData()
286 linksDataOrderedKeys = systemLinkData.getLinkDataOrderedKeys()
288 #remove system links (and sublinks) which are not define in linksData
289 for link in self.getAllLinks()[:]:
290 if isinstance(link, SystemLink):
291 if link.getParent() is not None:
292 if not link.getName() in linksData:
293 link.getParent().removeLink(link)
294 elif link.getParent().getName() != linksData[link.getName()]["parent"]:
295 link.getParent().removeLink(link)
296 elif link.getName() not in linksData:
297 # link was removed from the list
298 self.removeLink(link)
300 #Now, update the system links
301 for name in linksDataOrderedKeys:
302 data = linksData[name]
303 link = self.getLinkByName(name)
304 if link:
305 # only update the caption if it has been already customized
306 if not link.wasChanged() or link.getCaption() == '':
307 link.setCaption(data["caption"], silent=True)
308 link.setURL(data["URL"])
309 link.setDisplayTarget(data.get("displayTarget",""))
310 else:
311 #we must create the link
312 self._createSystemLink(name, linksData)
314 def _createSystemLink(self, name, linksData):
315 data = linksData.get(name, None)
316 if data == None:
317 raise MaKaCError(_("error in the system link structure of the menu"))
318 if data["parent"] == "":
319 #create the link at the fisrt level
320 link = SystemLink(name)
321 link.setCaption(data["caption"], silent=True)
322 link.setURL(data["URL"])
323 self.addLink(link)
324 link.disable()
325 if data.get("visibilityByDefault", True):
326 link.enable()
327 else:
328 #We must check if the parent exist
329 parent = self.getLinkByName(data["parent"])
330 if not parent:
331 self._createSystemLink(data["parent"], linksData)
332 parent = self.getLinkByName(data["parent"])
333 #We can create the link under the parent
334 link = SystemLink(name)
335 link.setCaption(data["caption"], silent=True)
336 link.setURL(data["URL"])
337 parent.addLink(link)
338 link.disable()
339 if data.get("visibilityByDefault", True):
340 link.enable()
342 def _generateNewLinkId( self ):
343 """Returns a new unique identifier for the current conference
344 contributions
346 return str(self._linkGenerator.newCount())
348 def linkHasToBeDisplayed(self, link):
349 if isinstance(link, SystemLink):
350 if link.getName()=="CFA" or link.getName()=="abstractsBook" or link.getName()=="mytracks" or link.getName()=="manageTrack":
351 return self.getConference().hasEnabledSection("cfa")
352 elif link.getName()=="registrationForm" or link.getName()=="registrants":
353 return self.getConference().hasEnabledSection("regForm")
354 else:
355 return True
356 else:
357 return True
359 def getLocator( self ):
360 """Gives back a globaly unique identification encapsulated in a Locator
361 object for the session instance
363 if self._parent == None:
364 return Locator()
365 lconf = self._parent.getConference().getLocator()
366 return lconf
368 def setParent(self, parent):
369 self._parent = parent
371 def getParent(self):
372 return self._parent
374 def getIndent(self):
375 return self._indent
377 def setIndent(self, indent):
378 self._indent = indent
380 def addLink(self, link):
381 self._listLink.append(link)
382 link.setParent(self)
383 id = link.getId()
384 if id == "":
385 id = self._generateNewLinkId()
386 link.setId(id)
387 self._p_changed = 1
389 def removeLink(self, link):
390 if link in self._listLink:
391 self._listLink.remove(link)
392 link.setParent(None)
393 link.delete()
394 self._p_changed = 1
396 def upLink(self, link):
397 if link in self._listLink:
398 index = self._listLink.index(link)
399 newindex = index - 1
400 while newindex >= 0 and not self.linkHasToBeDisplayed(self._listLink[newindex]):
401 newindex -= 1
402 self._listLink.remove(link)
403 if newindex >= 0:
404 self._listLink.insert(newindex, link)
405 else:
406 self._listLink.append(link)
407 self._p_changed = 1
410 def downLink(self, link):
411 if link in self._listLink:
412 index = self._listLink.index(link)
413 newindex = index+1
414 while newindex < len(self._listLink) and not self.linkHasToBeDisplayed(self._listLink[newindex]):
415 newindex += 1
416 self._listLink.remove(link)
417 if newindex <= len(self._listLink):
418 self._listLink.insert(newindex, link)
419 else:
420 self._listLink.insert(0, link)
421 self._p_changed = 1
423 def getLinkById(self, id):
424 for link in self._listLink:
425 if link.getId() == id:
426 return link
427 ret = link.getLinkById(id)
428 if ret:
429 return ret
430 return None
432 def getLinkByName(self, name):
433 for link in self._listLink:
434 if link.getName() == name:
435 return link
436 ret = link.getLinkByName(name)
437 if ret:
438 return ret
439 return None
441 def getAllLinks(self):
442 l = []
443 for link in self._listLink:
444 if isinstance(link,Spacer):
445 continue
446 l.append(link)
447 l.extend(link._listLink)
448 return l
450 def getLinkList(self):
451 return self._listLink
453 def getEnabledLinkList(self):
454 l = []
455 for link in self._listLink:
456 if link.isEnabled():
457 l.append(link)
458 return l
460 def isCurrentItem(self, item):
461 return self._currentItem == item
463 def setCurrentItem(self, value):
464 self._currentItem = value
466 def getCurrentItem(self):
467 return self._currentItem
469 def __str__(self):
470 str = ""
471 for link in self._listLink:
472 if link.isEnabled():
473 str += "%s\n"%link
474 return str
476 class Spacer(Persistent):
477 Type = "spacer"
479 def __init__(self, name="", parent=None):
480 self._name = name
481 self._active = True
482 self._parent = parent
483 self._id = ""
484 self._v_visible=True
486 def clone(self, newMenu):
487 newSpacer = Spacer(name=self.getName(),parent=newMenu)
488 newSpacer.setId(self.getId())
489 newSpacer.setEnabled(self.isEnabled())
490 return newSpacer
492 def getParent(self):
493 return self._parent
495 def getId(self):
496 return self._id
498 def setId(self, id):
499 self._id = id
500 if self._name == "":
501 self._name = "spacer %s"%id
503 def getLocator( self ):
504 """Gives back a globaly unique identification encapsulated in a Locator
505 object for the session instance
507 if self._parent == None:
508 return Locator()
509 lparent = self._parent.getLocator()
510 lparent["linkId"] = self.getId()
511 return lparent
513 def getLinkById(self, id):
514 return None
516 def getLinkByName(self, name):
517 return None
519 def setParent(self, parent):
520 self._parent = parent
522 def getType(self):
523 return self.Type
525 def enable(self):
526 self._active = True
528 def disable(self):
529 self._active = False
531 def setEnabled(self, value):
532 if value:
533 self.enable()
534 else:
535 self.disable()
537 def isEnabled(self):
538 return self._active
540 def setName(self, name):
541 self._name = name
543 def getName(self):
544 return self._name
546 def __str__(self, indent=""):
547 str = """%s<br>\n"""%indent
548 return str
550 def isVisible(self):
551 try:
552 if self._v_visible:
553 pass
554 except AttributeError:
555 self._v_visible=True
556 return self._v_visible
558 def setVisible(self,newValue=True):
559 self._v_visible=newValue
561 def delete(self):
562 TrashCanManager().add(self)
564 def recover(self):
565 TrashCanManager().remove(self)
568 class Link(Persistent):
570 base class for the links of a menu
572 Type = "Link"
574 def __init__(self, name, parent=None):
575 self._name = name
576 self._listLink = []
577 self._active = True
578 self._parent = parent
579 self._id = ""
580 self._caption = ""
581 self._v_visible=True
582 self._displayTarget = ""
584 def getId(self):
585 return self._id
587 def setId(self, id):
588 self._id = id
590 def getParent(self):
591 return self._parent
593 def getLocator( self ):
594 """Gives back a globaly unique identification encapsulated in a Locator
595 object for the session instance
597 if self._parent == None:
598 return Locator()
599 lparent = self._parent.getLocator()
600 lparent["linkId"] = self.getId()
601 return lparent
603 def _generateNewLinkId( self ):
604 """Returns a new unique identifier for the current conference
605 contributions
607 if self._parent:
608 return self._parent._generateNewLinkId()
610 def setParent(self, parent):
611 self._parent = parent
613 def getType(self):
614 return self.Type
616 def getDisplayTarget(self):
617 try:
618 if self._displayTarget:
619 pass
620 except AttributeError, e:
621 self._displayTarget = "_blank"
622 return self._displayTarget
624 def setDisplayTarget(self, t):
625 self._displayTarget = t
627 def enable(self):
628 previousState = self._active
629 self._active = True
630 if not previousState:
631 for link in self._listLink:
632 link.enable()
633 self._p_changed = 1
634 self._parent.enable()
636 def disable(self):
637 self._active = False
638 for link in self._listLink:
639 link.disable()
640 self._p_changed = 1
642 def setEnabled(self, enable):
643 if enable:
644 self.enable()
645 else:
646 self.disable()
648 def isEnabled(self):
649 return self._active
651 def setName(self, name):
652 self._name = name
654 def getName(self):
655 return self._name
657 def setCaption(self, caption):
658 self._caption = caption
660 def getCaption(self):
661 return self._caption
663 def addLink(self, link):
664 self._listLink.append(link)
665 link.setParent(self)
666 id = link.getId()
667 if id == "":
668 id = self._generateNewLinkId()
669 link.setId(id)
670 self._p_changed = 1
672 def removeLink(self, link):
673 if link in self._listLink:
674 self._listLink.remove(link)
675 link.setParent(None)
676 link.delete()
677 self._p_changed = 1
679 def upLink(self, link):
680 if link in self._listLink:
681 if self._listLink.index(link) != 0:
682 index = self._listLink.index(link)
683 sb = self._listLink.pop(index)
684 self._listLink.insert(index-1, sb)
685 self._p_changed = 1
687 def downLink(self, link):
688 if link in self._listLink:
689 if self._listLink.index(link) < len(self._listLink)-1:
690 index = self._listLink.index(link)
691 sb = self._listLink.pop(index)
692 self._listLink.insert(index+1, sb)
693 self._p_changed = 1
695 def getLinkByName(self, name):
696 for link in self._listLink:
697 if link.getName() == name:
698 return link
699 ret = link.getLinkByName(name)
700 if ret:
701 return ret
702 return None
704 def getLinkById(self, id):
705 for link in self._listLink:
706 if link.getId() == id:
707 return link
708 ret = link.getLinkById(id)
709 if ret:
710 return ret
711 return None
713 def getLinkList(self):
714 return self._listLink
716 def getEnabledLinkList(self):
717 l = []
718 for link in self._listLink:
719 if link.isEnabled():
720 l.append(link)
721 return l
723 def getURL(self):
724 return ""
726 def __str__(self, indent=""):
728 str = """%s<a href="%s">%s</a><br>\n"""%(indent, self.getURL(), self.getName())
729 for link in self._listLink:
730 if link.isEnabled():
731 str += "%s\n"%link.__str__(indent + "&nbsp;&nbsp;&nbsp;&nbsp;")
732 return str
734 def isVisible(self):
735 try:
736 if self._v_visible:
737 pass
738 except AttributeError:
739 self._v_visible=True
740 return self._v_visible
742 def setVisible(self,newValue=True):
743 self._v_visible=newValue
745 def delete(self):
746 for l in self.getLinkList()[:]:
747 self.removeLink(l)
748 TrashCanManager().add(self)
750 def recover(self):
751 TrashCanManager().remove(self)
753 class SystemLink(Link):
755 class for link which target a system part
756 The user cannot change the link data
757 The URL is dynamicly generated
759 Type = "system"
761 def __init__(self, name, parent=None, changed=False):
762 Link.__init__(self, name, parent)
764 # by default, this link will be updated when there are version
765 # changes that modify its default name
766 self._changed = changed
768 def clone(self, newMenu):
769 newLink = SystemLink(self.getName(), parent=newMenu, changed=self.wasChanged())
770 newLink.setEnabled(self.isEnabled())
771 newLink.setVisible(self.isVisible())
772 newLink.setId(self.getId())
773 newLink.setDisplayTarget(self.getDisplayTarget())
774 newLink.setCaption(self.getCaption(), silent=True)
775 newLink.setURL(self.getURL())
777 listLink = []
778 for link in self.getLinkList():
779 listLink.append(link.clone(newLink))
781 newLink._listLink = listLink
783 return newLink
785 def wasChanged(self):
786 # old conferences, before `_changed` was introduced
787 if hasattr(self, '_changed'):
788 return self._changed
789 else:
790 # for old conferences, just keeps things as people
791 # left them
792 return True
794 def getURL(self):
795 return self._URL
797 def setURL(self, url):
798 self._URL = url
800 def getCaption(self):
801 return self._caption
803 def setCaption(self, caption, silent=False):
804 self._caption = caption
806 if not silent:
807 # if the caption was changed, do not update it when the default
808 # value get an update
809 self._changed = True
812 class SystemLinkData(Observable):
814 def __init__(self, conf=None):
815 #the following dict is used to update the system link of the menu. each new entry is added to the menu,
816 #and all entries in the menu whiche are not is this dict are removed.
817 if not hasattr(self, "_linkData"):
818 self._linkData = {
819 "overview": {\
820 "caption": "Overview", \
821 "URL": str(urlHandlers.UHConferenceOverview.getURL(conf)), \
822 "parent": ""}, \
823 "programme": { \
824 "caption": "Scientific Programme", \
825 "URL": str(urlHandlers.UHConferenceProgram.getURL(conf)), \
826 "parent": ""}, \
827 "CFA": { \
828 "caption": "Call for Abstracts", \
829 "URL": str(urlHandlers.UHConferenceCFA.getURL(conf)), \
830 "parent": ""}, \
831 "ViewAbstracts": { \
832 "caption": "View my abstracts", \
833 "URL": str(urlHandlers.UHUserAbstracts.getURL(conf)), \
834 "parent": "CFA"}, \
835 "SubmitAbstract": { \
836 "caption": "Submit a new abstract", \
837 "URL": str(urlHandlers.UHAbstractSubmission.getURL(conf)), \
838 "parent": "CFA"}, \
839 "manageTrack": { \
840 "caption": "Manage my track", \
841 "URL": str(urlHandlers.UHTrackModifAbstracts.getURL(conf)), \
842 "parent": "programme"}, \
843 "timetable": { \
844 "caption": "Timetable", \
845 "URL": str(urlHandlers.UHConferenceTimeTable.getURL( conf )), \
846 "parent": ""}, \
847 "contributionList": { \
848 "caption": "Contribution List", \
849 "URL": str(urlHandlers.UHContributionList.getURL( conf )), \
850 "parent": ""}, \
851 "authorIndex": { \
852 "caption": "Author index", \
853 "URL": str(urlHandlers.UHConfAuthorIndex.getURL( conf )), \
854 "parent": ""} ,\
855 "speakerIndex": { \
856 "caption": "Speaker index", \
857 "URL": str(urlHandlers.UHConfSpeakerIndex.getURL( conf )), \
858 "parent": "", \
859 "visibilityByDefault": False}, \
860 "mystuff": { \
861 "caption": "My conference", \
862 "URL": str(urlHandlers.UHConfMyStuff.getURL(conf)), \
863 "parent": ""}, \
864 "mytracks": { \
865 "caption": "My tracks", \
866 "URL": str(str(urlHandlers.UHConfMyStuffMyTracks.getURL(conf))), \
867 "parent": "mystuff"}, \
868 "mysessions": { \
869 "caption": "My sessions", \
870 "URL": str(str(urlHandlers.UHConfMyStuffMySessions.getURL(conf))), \
871 "parent": "mystuff"}, \
872 "mycontribs": { \
873 "caption": "My contributions", \
874 "URL": str(str(urlHandlers.UHConfMyStuffMyContributions.getURL(conf))), \
875 "parent": "mystuff"}, \
876 "paperreviewing": { \
877 "caption": "Paper Reviewing", \
878 "URL": str(urlHandlers.UHPaperReviewingDisplay.getURL(conf)), \
879 "parent": ""}, \
880 "managepaperreviewing": { \
881 "caption": "Manage Paper Reviewing", \
882 "URL": str(str(urlHandlers.UHConfModifReviewingPaperSetup.getURL(conf))), \
883 "parent": "paperreviewing"}, \
884 "assigncontributions": { \
885 "caption": "Assign papers", \
886 "URL": str(str(urlHandlers.UHConfModifReviewingAssignContributionsList.getURL(conf))), \
887 "parent": "paperreviewing"}, \
888 "judgelist": { \
889 "caption": "Referee Area", \
890 "URL": str(str(urlHandlers.UHConfModifListContribToJudge.getURL(conf))), \
891 "parent": "paperreviewing"}, \
892 "judgelistreviewer": { \
893 "caption": "Content Reviewer Area", \
894 "URL": str(str(urlHandlers.UHConfModifListContribToJudgeAsReviewer.getURL(conf))), \
895 "parent": "paperreviewing"}, \
896 "judgelisteditor": { \
897 "caption": "Layout Reviewer Area", \
898 "URL": str(str(urlHandlers.UHConfModifListContribToJudgeAsEditor.getURL(conf))), \
899 "parent": "paperreviewing"}, \
900 "uploadpaper": { \
901 "caption": "Upload paper", \
902 "URL": str(str(urlHandlers.UHUploadPaper.getURL(conf))), \
903 "parent": "paperreviewing"}, \
904 "downloadtemplate": { \
905 "caption": "Download template", \
906 "URL": str(str(urlHandlers.UHDownloadPRTemplate.getURL(conf))), \
907 "parent": "paperreviewing"}, \
908 "abstractsBook": { \
909 "caption": "Book of abstracts", \
910 "URL": str(urlHandlers.UHConfAbstractBook.getURL(conf)), \
911 "parent": "", \
912 "displayTarget": "_blank"}, \
913 "registrationForm": { \
914 "caption": "Registration", \
915 "URL": str(urlHandlers.UHConfRegistrationForm.getURL(conf)), \
916 "parent": ""}, \
917 "ViewMyRegistration": { \
918 "caption": "Modify my registration", \
919 "URL": str(urlHandlers.UHConfRegistrationFormModify.getURL(conf)), \
920 "parent": "registrationForm"}, \
921 "NewRegistration": { \
922 "caption": "Registration Form", \
923 "URL": str(urlHandlers.UHConfRegistrationFormDisplay.getURL(conf)), \
924 "parent": "registrationForm"}, \
925 "registrants": { \
926 "caption": "List of registrants", \
927 "URL": str(urlHandlers.UHConfRegistrantsList.getURL(conf)), \
928 "parent": "", \
929 "visibilityByDefault": False}, \
930 "evaluation": { \
931 "caption": "Evaluation", \
932 "URL": str(urlHandlers.UHConfEvaluationMainInformation.getURL(conf)), \
933 "parent": ""}, \
934 "newEvaluation": { \
935 "caption": "Evaluation Form", \
936 "URL": str(urlHandlers.UHConfEvaluationDisplay.getURL(conf)), \
937 "parent": "evaluation"}, \
938 "viewMyEvaluation": { \
939 "caption": "Modify my evaluation", \
940 "URL": str(urlHandlers.UHConfEvaluationDisplayModif.getURL(conf)), \
941 "parent": "evaluation"},
942 "collaboration": { \
943 "caption": "Video Services", \
944 "URL": str(urlHandlers.UHCollaborationDisplay.getURL(conf)), \
945 "parent": ""} \
947 self._notify('confDisplaySMFillDict', {'dict': self._linkData, 'conf': conf})
948 #this ordered list allow us to keep the order we want for the menu
949 if not hasattr(self, "_linkDataOrderedKeys"):
950 self._linkDataOrderedKeys = ["overview",
951 "programme",
952 "CFA",
953 "ViewAbstracts",
954 "SubmitAbstract",
955 "manageTrack",
956 "timetable",
957 "contributionList",
958 "authorIndex",
959 "speakerIndex",
960 "mystuff",
961 "mytracks",
962 "mysessions",
963 "mycontribs",
964 "paperreviewing",
965 "managepaperreviewing",
966 "assigncontributions",
967 "judgelist",
968 "judgelistreviewer",
969 "judgelisteditor",
970 "uploadpaper",
971 "downloadtemplate",
972 "abstractsBook",
973 "registrationForm",
974 "ViewMyRegistration",
975 "NewRegistration",
976 "registrants",
977 "evaluation",
978 "newEvaluation",
979 "viewMyEvaluation",
980 "collaboration"]
981 self._notify('confDisplaySMFillOrderedKeys', self._linkDataOrderedKeys)
984 def getLinkData(self):
985 return self._linkData
986 def getLinkDataOrderedKeys(self):
987 self.__init__() #init self._linkDataOrderedKeys if it isn't defined.
988 return self._linkDataOrderedKeys
991 class ExternLink(Link):
993 class for link create by the user to a fixed link
995 Type = "extern"
996 def __init__(self, name, URL):
997 Link.__init__(self, name)
998 self._URL = URL
1000 def clone(self, newMenu):
1001 newLink = ExternLink(self.getName(),self.getURL())
1002 newLink.setId(self.getId())
1003 newLink.setParent(newMenu)
1004 newLink.setEnabled(self.isEnabled())
1005 newLink.setCaption(self.getCaption())
1006 newLink.setDisplayTarget(self.getDisplayTarget())
1007 return newLink
1009 def getURL(self):
1010 return self._URL
1012 def setURL(self, URL):
1013 self._URL = URL
1015 class PageLink(Link):
1017 class for link create by the user to a fixed link
1019 Type = "page"
1021 def __init__(self, name, page):
1022 Link.__init__(self, name)
1023 self._page = page
1025 def clone(self, newMenu):
1026 conf = newMenu.getConference()
1027 intPagesMgr = internalPagesMgr.InternalPagesMgrRegistery().getInternalPagesMgr(conf)
1028 newPage = self.getPage().clone(conf)
1029 intPagesMgr.addPage(newPage)
1030 newLink = PageLink(self.getName(),newPage)
1031 newLink.setId(self.getId())
1032 newLink.setParent(newMenu)
1033 newLink.setEnabled(self.isEnabled())
1034 newLink.setCaption(self.getCaption())
1035 newLink.setDisplayTarget(self.getDisplayTarget())
1036 return newLink
1038 def setPage(self, page):
1039 self._page=page
1041 def getPage(self):
1042 return self._page
1044 def getURL(self):
1045 return urlHandlers.UHInternalPageDisplay.getURL(self._page)
1048 class _FormatDefaultData:
1050 def __init__(self):
1051 self._data={
1052 "titleBgColor":{"code":"",\
1053 "url":urlHandlers.UHConfModifFormatTitleBgColor}, \
1054 "titleTextColor":{"code":"",\
1055 "url":urlHandlers.UHConfModifFormatTitleTextColor}
1058 def getColor(self,key):
1059 return self._data[key]["code"]
1061 def getURL(self,key):
1062 return self._data[key]["url"]
1065 class Format(Persistent):
1067 def __init__(self):
1068 self._data={}
1069 self._data["titleBgColor"]=_FormatDefaultData().getColor("titleBgColor")
1070 self._data["titleTextColor"]=_FormatDefaultData().getColor("titleTextColor")
1071 self._p_changed = 1
1073 def getFormatOption(self,key):
1074 if self._data.has_key(key):
1075 code=self._data[key]
1076 url=_FormatDefaultData().getURL(key)
1077 return {"code":code,"url":url}
1078 return None
1080 def clone(self, newCdm):
1081 newFormat = newCdm.getFormat()
1082 newFormat.setColorCode("titleBgColor", self.getFormatOption("titleBgColor")["code"])
1083 newFormat.setColorCode("titleTextColor", self.getFormatOption("titleTextColor")["code"])
1084 return newFormat
1086 def setColorCode(self,key,color):
1087 if self._data.has_key(key):
1088 color=self._getCorrectColor(color)
1089 if color is None:
1090 return
1092 self._data[key]=color
1093 self._p_changed = 1
1095 def _getCorrectColor(self, color):
1096 if color == "":
1097 return ""
1099 if not color.startswith("#"):
1100 color = "#%s"%color
1101 m = re.match("^#[0-9A-Fa-f]{6}$", color)
1102 if m:
1103 return color
1104 return None
1106 class TickerTape(Persistent):
1108 def __init__(self):
1109 # active will be set to true everytime the now
1110 # happening is enabled or the setText is called
1111 # this to avoid having an extra button in the interface
1112 # for activating the TickerTape
1113 self._active = False
1114 self._text=""
1115 self._enabledNowPlaying = False
1116 self._enabledSimpleText = False
1118 def clone(self, newCdm):
1119 newTT = newCdm.getTickerTape()
1120 newTT.setText(self.getText())
1121 newTT.setActive(self.isActive())
1122 newTT.setNowHappeningEnabled(self.isNowHappeningEnabled())
1123 newTT.setSimpleTextEnabled(self.isSimpleTextEnabled())
1124 return newTT
1126 def getText(self):
1127 return self._text
1129 def setText(self, text):
1130 self._active=True
1131 self._text = text
1133 def isActive(self):
1134 return self._active
1136 def activate(self):
1137 self._active=True
1139 def deactivate(self):
1140 self._active=False
1142 def setActive(self, v):
1143 self._active=v
1145 def isNowHappeningEnabled(self):
1146 try:
1147 if self._enabledNowPlaying:
1148 pass
1149 except AttributeError, e:
1150 self._enabledNowPlaying=False
1151 return self._enabledNowPlaying and self._active
1153 def setNowHappeningEnabled(self, v):
1154 self._active = True
1155 self._enabledNowPlaying = v
1157 def isSimpleTextEnabled(self):
1158 try:
1159 if self._enabledSimpleText:
1160 pass
1161 except AttributeError, e:
1162 self._enabledSimpleText = False
1163 return self._enabledSimpleText and self._active
1165 def setSimpleTextEnabled(self, v):
1166 self._enabledSimpleText=v
1168 class ImageWrapper(Persistent):
1170 It wraps a LocalFile class, just in case we need to add more info to this image
1171 in the future.
1174 def __init__(self, localFile):
1175 self._localFile = localFile
1177 def getId(self):
1178 return self._localFile.getId()
1180 def delete(self):
1181 self._localFile.delete()
1183 def getLocator(self):
1184 loc = self._localFile.getOwner().getLocator()
1185 loc["picId"] = self.getId()
1186 return loc
1188 def clone(self):
1189 lf=self.getLocalFile().clone()
1190 iw = ImageWraper(lf)
1191 return iw
1193 def getLocalFile(self):
1194 return self._localFile
1196 class ImagesManager(Persistent):
1198 This class manages all the images and pics used by a conference while displaying.
1199 We make difference between the "logo" of the conference and the rest of pictures.
1202 def __init__(self, conf):
1203 self._conf = conf
1204 self._logo = None
1205 self._picList = {}
1206 self._picsCounter = Counter()
1208 def clone(self, newCdm):
1209 newIM = newCdm.getImagesManager()
1210 newIM._conf = newCdm.getConference()
1212 for pic in self.getPicList().values():
1213 lf = pic.getLocalFile()
1214 f = LocalFile()
1215 f.setFileName( lf.getFileName() )
1216 f.setFilePath( lf.getFilePath() )
1217 newIM.addPic(f)
1219 #Logo is not being cloned so far.
1221 return newIM
1223 def notifyModification(self):
1224 self._p_changed = 1
1226 def getPicList(self):
1227 """ function for getting piclist """
1228 try:
1229 if self._picList:
1230 pass
1231 except:
1232 self._picList = {}
1233 return self._picList
1235 def _getPicsCounter(self):
1236 try:
1237 if self._picsCounter:
1238 pass
1239 except:
1240 self._picsCounter = Counter()
1241 return self._picsCounter
1243 def addPic( self, picFile ):
1244 """ function for adding new picture item """
1245 picId = self._getPicsCounter().newCount()
1246 if self.getPicList().has_key(picId) and self.getPicList()[picId] != None:
1247 raise MaKaCError("there is already a pic with the id %s"%picId)
1248 picFile.setOwner( self._conf )
1249 picFile.setId( picId )
1250 picFile.archive( self._conf._getRepository() )
1251 pic = ImageWrapper(picFile)
1252 self.getPicList()[picId] = pic
1253 self.notifyModification()
1254 return pic
1256 def getPic( self,picId ):
1257 if self.getPicList().has_key(picId):
1258 return self.getPicList()[picId]
1259 return None
1261 def removePic(self,picId):
1262 """ function for removing pictures, used in picture uploader """
1263 pic = self.getPic(picId)
1264 if pic is not None:
1265 self.getPicList()[picId].delete()
1266 del self.getPicList()[picId]
1267 self.notifyModification()
1269 # Logo should be migrated to this class in the near future.
1270 def setLogo( self, logoFile ):
1271 logoFile.setOwner( self._conf )
1272 logoFile.setId( "logo" )
1273 logoFile.archive( self._conf._getRepository() )
1274 if self._logo != None:
1275 self._logo.delete()
1276 self._logo = logoFile
1278 def getLogo( self ):
1279 return self._logo
1281 def getLogoURL( self ):
1282 try:
1283 if self._logo == None:
1284 return ""
1285 return self._logo.getURL()
1286 except AttributeError:
1287 self._logo = None
1288 return ""
1290 def removeLogo(self):
1291 if self._logo is None:
1292 return
1293 self._logo.delete()
1294 self._logo = None
1296 def recoverLogo(self, logo):
1297 logo.setOwner(self._conf)
1298 if self._logo != None:
1299 self._logo.delete()
1300 self._logo = logo
1301 logo.recover()
1303 class CSSWrapper(Persistent):
1305 This class will handle the CSS file that is going to be applied
1306 to the conference display. CSS file can be an upload file or a
1307 template we already have. The upload file is an object of the class
1308 LocalFile and the template is just a string with the id (name) of the
1309 template.
1310 The class encapsulates the CSS so the user does not care about if it is
1311 a template or a local file.
1314 def __init__(self, conf, css):
1315 self._conf = conf
1316 self._localFile = css
1318 def getId(self):
1319 return self._localFile.getId()
1321 def getLocator(self):
1322 loc = self._localFile.getOwner().getLocator()
1323 loc["cssId"] = self.getId()
1324 return loc
1326 def clone(self, newSM):
1327 f=None
1328 if self._localFile:
1329 f = LocalFile()
1330 f.setFileName( self._localFile.getFileName() )
1331 f.setFilePath( self._localFile.getFilePath() )
1332 f.setOwner( newSM._conf )
1333 f.setId( "css" )
1334 f.archive( newSM._conf._getRepository() )
1335 newCW = CSSWrapper(self._conf, f)
1336 return newCW
1338 def getURL(self):
1339 from MaKaC.webinterface.urlHandlers import UHConferenceCSS
1340 return UHConferenceCSS.getURL(self._conf)
1342 def getFileName(self, extension=True):
1343 fn =self._localFile.getFileName()
1344 if not extension:
1345 fn = fn.lower().replace(".css","")
1346 return fn
1348 def getSize(self):
1349 return self._localFile.getSize()
1351 def readBin(self):
1352 return self._localFile.readBin()
1354 def delete(self):
1355 self._localFile.delete()
1356 self._localFile=None
1358 class StyleManager(Persistent):
1360 This class manages the CSS customization for a conference.
1363 def __init__(self, conf):
1364 self._conf = conf
1365 self._css = None
1366 self._usingTemplate = None
1368 def clone(self, newCdm):
1369 newSM = newCdm.getStyleManager()
1370 newSM._conf = newCdm.getConference()
1371 newSM._usingTemplate = self._usingTemplate
1372 if self._css:
1373 newSM._css = self._css.clone(newSM)
1375 #Logo is not being cloned so far.
1377 return newSM
1379 def isUsingTemplate(self):
1380 return self._usingTemplate is not None
1382 def useLocalCSS(self):
1383 self._usingTemplate = None
1385 def setCSS( self, cssFile ):
1386 if isinstance(cssFile, str):
1387 # we will use a template but we keep the uploaded css file
1388 from indico.modules import ModuleHolder
1389 self._cssTplsModule = ModuleHolder().getById("cssTpls")
1390 self._usingTemplate = self._cssTplsModule.getCssTplById(cssFile)
1391 else:
1392 # uploaded file
1393 cssFile.setOwner( self._conf )
1394 cssFile.setId( "css" )
1395 cssFile.archive( self._conf._getRepository() )
1396 if self._css != None:
1397 self._css.delete()
1398 self._usingTemplate = None
1399 self._css = CSSWrapper(self._conf, cssFile)
1401 def getLocalCSS( self ):
1402 return self._css
1404 def getCSS(self):
1405 if self._usingTemplate:
1406 return self._usingTemplate
1407 return self.getLocalCSS()
1409 def getCSSURL( self ):
1410 if self.getCSS():
1411 return self.getCSS().getURL()
1412 return None
1414 def removeCSS(self):
1415 if self._css is not None:
1416 self._css.delete()
1417 self._css = None