/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.modules.qpool.ui; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.NewControllerFactory; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.stack.BreadcrumbPanel; import org.olat.core.gui.components.stack.BreadcrumbPanelAware; import org.olat.core.gui.components.stack.PopEvent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.gui.media.MediaResource; import org.olat.core.id.Identity; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; import org.olat.core.util.resource.OresHelper; import org.olat.fileresource.types.ImsQTI21Resource; import org.olat.group.BusinessGroup; import org.olat.group.model.BusinessGroupSelectionEvent; import org.olat.group.ui.main.SelectBusinessGroupController; import org.olat.ims.qti.fileresource.SurveyFileResource; import org.olat.ims.qti.fileresource.TestFileResource; import org.olat.ims.qti.qpool.QTIQPoolServiceProvider; import org.olat.ims.qti.questionimport.ItemAndMetadata; import org.olat.ims.qti.questionimport.ItemsPackage; import org.olat.ims.qti21.pool.QTI21QPoolServiceProvider; import org.olat.ims.qti21.questionimport.AssessmentItemAndMetadata; import org.olat.ims.qti21.questionimport.AssessmentItemsPackage; import org.olat.ims.qti21.questionimport.ImportOptions; import org.olat.ims.qti21.questionimport.QImport_1_InputStep; import org.olat.modules.qpool.ExportFormatOptions; import org.olat.modules.qpool.Pool; import org.olat.modules.qpool.QItemFactory; import org.olat.modules.qpool.QPoolSPI; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionItemCollection; import org.olat.modules.qpool.QuestionItemShort; import org.olat.modules.qpool.QuestionPoolModule; import org.olat.modules.qpool.model.QItemList; import org.olat.modules.qpool.ui.events.QItemCreationCmdEvent; import org.olat.modules.qpool.ui.events.QItemEdited; import org.olat.modules.qpool.ui.events.QItemEvent; import org.olat.modules.qpool.ui.events.QPoolEvent; import org.olat.modules.qpool.ui.events.QPoolSelectionEvent; import org.olat.modules.qpool.ui.metadata.MetadataBulkChangeController; import org.olat.modules.qpool.ui.wizard.Export_1_TypeStep; import org.olat.modules.qpool.ui.wizard.ImportAuthor_1_ChooseMemberStep; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.controllers.EntryChangedEvent; import org.olat.repository.controllers.ReferencableEntriesSearchController; import org.olat.repository.controllers.RepositorySearchController.Can; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.ui.author.CreateEntryController; import org.springframework.beans.factory.annotation.Autowired; /** * * This controller wrap the table of qitems and decorate it with * features like copy, delete...<br/> * * Initial date: 22.01.2013<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class QuestionListController extends AbstractItemListController implements BreadcrumbPanelAware, Activateable2 { private FormLink list, exportItem, shareItem, removeItem, newItem, copyItem, convertItem, deleteItem, authorItem, importItem, bulkChange; private BreadcrumbPanel stackPanel; private RenameController renameCtrl; private CloseableModalController cmc; private CloseableModalController cmcShareItemToSource; private DialogBoxController confirmCopyBox; private DialogBoxController confirmDeleteBox; private DialogBoxController confirmRemoveBox; private DialogBoxController confirmDeleteSourceBox; private ShareItemOptionController shareItemsCtrl; private ShareItemSourceOptionController shareItemsToSourceCtrl; private PoolsController selectPoolCtrl; private SelectBusinessGroupController selectGroupCtrl; private CreateCollectionController createCollectionCtrl; private CollectionListController chooseCollectionCtrl; private StepsMainRunController exportWizard; private StepsMainRunController importAuthorsWizard; private StepsMainRunController excelImportWizard; private ImportController importItemCtrl; private CollectionTargetController listTargetCtrl; private ShareTargetController shareTargetCtrl; private CreateEntryController addController; private QuestionItemDetailsController currentDetailsCtrl; private LayoutMain3ColsController currentMainDetailsCtrl; private MetadataBulkChangeController bulkChangeCtrl; private ImportSourcesController importSourcesCtrl; private NewItemOptionsController newItemOptionsCtrl; private CloseableCalloutWindowController calloutCtrl; private ReferencableEntriesSearchController importTestCtrl; private ConversionConfirmationController conversionConfirmationCtrl; private QuestionItemCollection itemCollection; private boolean itemCollectionDirty = false; @Autowired private QuestionPoolModule qpoolModule; @Autowired private RepositoryManager repositoryManager; @Autowired private RepositoryHandlerFactory repositoryHandlerFactory; public QuestionListController(UserRequest ureq, WindowControl wControl, QuestionItemsSource source, String key) { super(ureq, wControl, source, key); } @Override protected void initButtons(UserRequest ureq, FormItemContainer formLayout) { list = uifactory.addFormLink("list", formLayout, Link.BUTTON); exportItem = uifactory.addFormLink("export.item", formLayout, Link.BUTTON); shareItem = uifactory.addFormLink("share.item", formLayout, Link.BUTTON); if(getSource().isRemoveEnabled()) { removeItem = uifactory.addFormLink("unshare.item", formLayout, Link.BUTTON); } newItem = uifactory.addFormLink("new.item", formLayout, Link.BUTTON); copyItem = uifactory.addFormLink("copy", formLayout, Link.BUTTON); convertItem = uifactory.addFormLink("convert.item", formLayout, Link.BUTTON); importItem = uifactory.addFormLink("import.item", formLayout, Link.BUTTON); authorItem = uifactory.addFormLink("author.item", formLayout, Link.BUTTON); if(getSource().isDeleteEnabled()) { deleteItem = uifactory.addFormLink("delete.item", formLayout, Link.BUTTON); } bulkChange = uifactory.addFormLink("bulk.change", formLayout, Link.BUTTON); } public QuestionItemCollection getItemCollection() { return itemCollection; } public void setItemCollection(QuestionItemCollection itemCollection) { this.itemCollection = itemCollection; } @Override public void setBreadcrumbPanel(BreadcrumbPanel stackPanel) { this.stackPanel = stackPanel; if(stackPanel != null) { stackPanel.addListener(this); } } @Override public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { if(entries == null || entries.isEmpty()) return; ContextEntry entry = entries.get(0); String type = entry.getOLATResourceable().getResourceableTypeName(); if("QuestionItem".equals(type)) { Long itemKey = entry.getOLATResourceable().getResourceableId(); ItemRow row = getModel().getObjectByKey(itemKey); if(row == null) { //TODO xhr } else { doSelect(ureq, row); } } } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source instanceof FormLink) { FormLink link = (FormLink)source; if(link == list) { doList(ureq); } else if(link == exportItem) { List<QuestionItemShort> items = getSelectedShortItems(false); if(items.size() > 0) { doExport(ureq, items); } else { showWarning("error.select.one"); } } else if(link == shareItem) { doShare(ureq); } else if(link == removeItem) { List<QuestionItemShort> items = getSelectedShortItems(false); if(items.size() > 0) { doConfirmRemove(ureq, items); } else { showWarning("error.select.one"); } } else if(link == copyItem) { List<QuestionItemShort> items = getSelectedShortItems(false); if(items.size() > 0) { doConfirmCopy(ureq, items); } else { showWarning("error.select.one"); } } else if(link == convertItem) { List<QuestionItemShort> items = getSelectedShortItems(false); if(items.size() > 0) { doConfirmConversion(ureq, items); } else { showWarning("error.select.one"); } } else if(link == deleteItem) { List<QuestionItemShort> items = getSelectedShortItems(true); if(items.size() > 0) { doConfirmDelete(ureq, items); } else { showWarning("error.select.one"); } } else if(link == authorItem) { List<QuestionItemShort> items = getSelectedShortItems(false); if(items.size() > 0) { doChooseAuthoren(ureq, items); } else { showWarning("error.select.one"); } } else if(link == importItem) { doOpenImport(ureq); } else if(link == newItem) { doChooseNewItemType(ureq); } else if(link == bulkChange) { List<QuestionItemShort> items = getSelectedShortItems(true); if(items.size() > 0) { doBulkChange(ureq, items); } else { showWarning("error.select.one"); } } } super.formInnerEvent(ureq, source, event); } @Override public void event(UserRequest ureq, Component source, Event event) { if(source == stackPanel) { if(itemCollectionDirty && event instanceof PopEvent) { PopEvent pe = (PopEvent)event; Controller mainCtrl = pe.getController(); if(mainCtrl != null && mainCtrl.isControllerListeningTo(this)) { reloadData(); itemCollectionDirty = false; } } } else { super.event(ureq, source, event); } } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(source == shareTargetCtrl) { List<QuestionItemShort> items = getSelectedShortItems(false); calloutCtrl.deactivate(); if(items.isEmpty()) { showWarning("error.select.one"); } else if(ShareTargetController.SHARE_GROUP_CMD.equals(event.getCommand())) { doSelectGroup(ureq, items); } else if(ShareTargetController.SHARE_POOL_CMD.equals(event.getCommand())) { doSelectPool(ureq, items); } } else if(source == selectPoolCtrl) { cmc.deactivate(); if(event instanceof QPoolSelectionEvent) { QPoolSelectionEvent qpe = (QPoolSelectionEvent)event; List<Pool> pools = qpe.getPools(); if(pools.size() > 0) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)selectPoolCtrl.getUserObject(); doShareItemsToGroups(ureq, items, null, pools); } } } else if(source == importSourcesCtrl) { calloutCtrl.deactivate(); if(ImportSourcesController.IMPORT_FILE.equals(event.getCommand())) { doOpenFileImport(ureq); } else if(ImportSourcesController.IMPORT_REPO.equals(event.getCommand())) { doOpenRepositoryImport(ureq); } else if(ImportSourcesController.IMPORT_EXCEL_QTI_12.equals(event.getCommand())) { doOpenExcelImportQTI12(ureq); } else if(ImportSourcesController.IMPORT_EXCEL_QTI_21.equals(event.getCommand())) { doOpenExcelImportQTI21(ureq); } } else if(source == newItemOptionsCtrl) { cmc.deactivate(); if(event instanceof QItemCreationCmdEvent) { QItemCreationCmdEvent qicce = (QItemCreationCmdEvent)event; doCreateNewItem(ureq, qicce.getTitle(), qicce.getFactory()); } } else if(source == selectGroupCtrl) { cmc.deactivate(); if(event instanceof BusinessGroupSelectionEvent) { BusinessGroupSelectionEvent bge = (BusinessGroupSelectionEvent)event; List<BusinessGroup> groups = bge.getGroups(); if(groups.size() > 0) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)selectGroupCtrl.getUserObject(); doShareItemsToGroups(ureq, items, groups, null); } } } else if(source == shareItemsCtrl) { if(event instanceof QPoolEvent) { fireEvent(ureq, event); } cmc.deactivate(); cleanUp(); } else if(source == listTargetCtrl) { List<QuestionItemShort> items = getSelectedShortItems(false); calloutCtrl.deactivate(); if(CollectionTargetController.ADD_TO_LIST_POOL_CMD.equals(event.getCommand())) { if(items.isEmpty()) { showWarning("error.select.one"); } else { doChooseCollection(ureq, items); } } else if(CollectionTargetController.NEW_LIST_CMD.equals(event.getCommand())) { doAskCollectionName(ureq, items); } else if(CollectionTargetController.RENAME_LIST_CMD.equals(event.getCommand())) { doOpenRenameCallout(ureq); } else if(CollectionTargetController.DELETE_LIST_CMD.equals(event.getCommand())) { doConfirmDeleteSource(ureq); } } else if(source == createCollectionCtrl) { if(Event.DONE_EVENT == event) { List<QuestionItemShort> items = createCollectionCtrl.getUserObject(); String collectionName = createCollectionCtrl.getName(); doCreateCollection(ureq, collectionName, items); } cmc.deactivate(); cleanUp(); } if(source == confirmDeleteSourceBox) { boolean delete = DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event); if(delete) { doDeleteItemCollection(ureq); } } else if(source == renameCtrl) { cmc.deactivate(); if(Event.CHANGED_EVENT == event) { String newName = renameCtrl.getName(); doRenameItemCollection(ureq, newName); } } else if(source == chooseCollectionCtrl) { cmc.deactivate(); cleanUp(); } else if(source == exportWizard) { if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { getWindowControl().pop(); removeAsListenerAndDispose(exportWizard); StepsRunContext runContext = exportWizard.getRunContext(); exportWizard = null; if(event == Event.CHANGED_EVENT) { doExecuteExport(ureq, runContext); } } } else if(source == excelImportWizard) { if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { getWindowControl().pop(); removeAsListenerAndDispose(excelImportWizard); excelImportWizard = null; } } else if(source == importAuthorsWizard) { if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { getWindowControl().pop(); removeAsListenerAndDispose(importAuthorsWizard); importAuthorsWizard = null; } } else if(source == importItemCtrl) { if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { getItemsTable().reset(); } cmc.deactivate(); cleanUp(); } else if(source == importTestCtrl) { RepositoryEntry re = importTestCtrl.getSelectedEntry(); cmc.deactivate(); cleanUp(); if(event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { doImportResource(ureq, re); } } else if(source == shareItemsToSourceCtrl) { if(QPoolEvent.ITEM_SHARED.equals(event.getCommand())) { getItemsTable().reset(); } cmcShareItemToSource.deactivate(); cleanUp(); } else if(source == bulkChangeCtrl) { if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { updateRows(bulkChangeCtrl.getUpdatedItems()); fireEvent(ureq, new QPoolEvent(QPoolEvent.BULK_CHANGE)); } cmc.deactivate(); cleanUp(); } else if(source == confirmCopyBox) { if(DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)confirmCopyBox.getUserObject(); doCopy(ureq, items); } } else if(source == conversionConfirmationCtrl) { if(event == Event.DONE_EVENT) { List<QuestionItemShort> items = conversionConfirmationCtrl.getSelectedItems(); String format = conversionConfirmationCtrl.getSelectedFormat(); doConvert(ureq, items, format); } cmc.deactivate(); cleanUp(); } else if(source == confirmDeleteBox) { if(DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)confirmDeleteBox.getUserObject(); doDelete(items); } } else if(source == confirmRemoveBox) { if(DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event)) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)confirmRemoveBox.getUserObject(); doRemove(items); } } else if(source == currentDetailsCtrl) { if(event instanceof QItemEvent) { QItemEvent qce = (QItemEvent)event; if("copy-item".equals(qce.getCommand())) { stackPanel.popUpToRootController(ureq); doSelect(ureq, qce.getItem(), true); } else if("previous".equals(qce.getCommand())) { doPrevious(ureq, qce.getItem()); } else if("next".equals(qce.getCommand())) { doNext(ureq, qce.getItem()); } } else if(event instanceof QItemEdited) { itemCollectionDirty = true; } else if (event instanceof QPoolEvent) { QPoolEvent qce = (QPoolEvent)event; if(QPoolEvent.ITEM_DELETED.equals(qce.getCommand())) { fireEvent(ureq, qce); } } } else if(source == addController) { if(event instanceof EntryChangedEvent) { cmc.deactivate(); cleanUp(); EntryChangedEvent addEvent = (EntryChangedEvent)event; Long repoEntryKey = addEvent.getRepositoryEntryKey(); doExportToRepositoryEntry(ureq, repoEntryKey); } else if(event == Event.CANCELLED_EVENT) { cmc.deactivate(); cleanUp(); } } else if(source == cmc) { cleanUp(); } super.event(ureq, source, event); } private void cleanUp() { removeAsListenerAndDispose(cmc); removeAsListenerAndDispose(addController); removeAsListenerAndDispose(bulkChangeCtrl); removeAsListenerAndDispose(importItemCtrl); removeAsListenerAndDispose(importTestCtrl); removeAsListenerAndDispose(selectGroupCtrl); removeAsListenerAndDispose(createCollectionCtrl); removeAsListenerAndDispose(conversionConfirmationCtrl); cmc = null; addController = null; bulkChangeCtrl = null; importItemCtrl = null; importTestCtrl = null; selectGroupCtrl = null; createCollectionCtrl = null; conversionConfirmationCtrl = null; } protected void updateRows(List<QuestionItem> items) { List<Integer> rowIndex = getIndex(items); getModel().reload(rowIndex); getItemsTable().getComponent().setDirty(true); } private void doNext(UserRequest ureq, QuestionItem item) { ItemRow row = getRowByItemKey(item.getKey()); ItemRow nextRow = getModel().getNextObject(row); if(nextRow != null) { QuestionItem nextItem = qpoolService.loadItemById(nextRow.getKey()); stackPanel.popUpToRootController(ureq); doSelect(ureq, nextItem, nextRow.isEditable()); } } private void doPrevious(UserRequest ureq, QuestionItem item) { ItemRow row = getRowByItemKey(item.getKey()); ItemRow previousRow = getModel().getPreviousObject(row); if(previousRow != null) { QuestionItem previousItem = qpoolService.loadItemById(previousRow.getKey()); stackPanel.popUpToRootController(ureq); doSelect(ureq, previousItem, previousRow.isEditable()); } } private void doBulkChange(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(bulkChangeCtrl); bulkChangeCtrl = new MetadataBulkChangeController(ureq, getWindowControl(), items); listenTo(bulkChangeCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), bulkChangeCtrl.getInitialComponent(), true, translate("bulk.change")); cmc.activate(); listenTo(cmc); } private void doChooseNewItemType(UserRequest ureq) { removeAsListenerAndDispose(newItemOptionsCtrl); newItemOptionsCtrl = new NewItemOptionsController(ureq, getWindowControl()); listenTo(newItemOptionsCtrl); removeAsListenerAndDispose(cmc); cmc = new CloseableModalController(getWindowControl(), translate("close"), newItemOptionsCtrl.getInitialComponent(), true, translate("new.item")); cmc.activate(); listenTo(cmc); } private void doCreateNewItem(UserRequest ureq, String title, QItemFactory factory) { QuestionItem item = factory.createItem(getIdentity(), title, getLocale()); List<QuestionItem> newItems = Collections.singletonList(item); getSource().postImport(newItems, false); getItemsTable().reset(); QPoolEvent qce = new QPoolEvent(QPoolEvent.ITEM_CREATED); fireEvent(ureq, qce); List<ContextEntry> entries = BusinessControlFactory.getInstance().createCEListFromResourceType("Edit"); doSelect(ureq, item, true).activate(ureq, entries, null); } private void doOpenImport(UserRequest ureq) { String title = translate("import"); removeAsListenerAndDispose(importSourcesCtrl); importSourcesCtrl = new ImportSourcesController(ureq, getWindowControl()); listenTo(importSourcesCtrl); removeAsListenerAndDispose(calloutCtrl); calloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), importSourcesCtrl.getInitialComponent(), importItem, title, true, null); listenTo(calloutCtrl); calloutCtrl.activate(); } private void doOpenFileImport(UserRequest ureq) { removeAsListenerAndDispose(importItemCtrl); importItemCtrl = new ImportController(ureq, getWindowControl(), getSource()); listenTo(importItemCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), importItemCtrl.getInitialComponent(), true, translate("import.item")); cmc.activate(); listenTo(cmc); } private void doImportResource(UserRequest ureq, RepositoryEntry repositoryEntry) { List<QuestionItem> importItems = null; if(ImsQTI21Resource.TYPE_NAME.equals(repositoryEntry.getOlatResource().getResourceableTypeName())) { QTI21QPoolServiceProvider spi = CoreSpringFactory.getImpl(QTI21QPoolServiceProvider.class); importItems = spi.importRepositoryEntry(getIdentity(), repositoryEntry, getLocale()); } else { QTIQPoolServiceProvider spi = (QTIQPoolServiceProvider)CoreSpringFactory.getBean("qtiPoolServiceProvider"); importItems = spi.importRepositoryEntry(getIdentity(), repositoryEntry, getLocale()); } if(getSource().askEditable()) { removeAsListenerAndDispose(shareItemsToSourceCtrl); shareItemsToSourceCtrl = new ShareItemSourceOptionController(ureq, getWindowControl(), importItems, getSource()); listenTo(shareItemsToSourceCtrl); removeAsListenerAndDispose(cmcShareItemToSource); cmcShareItemToSource = new CloseableModalController(getWindowControl(), translate("close"), shareItemsToSourceCtrl.getInitialComponent(), true, translate("import.item")); cmcShareItemToSource.activate(); listenTo(cmcShareItemToSource); } else { int postImported = getSource().postImport(importItems, true); if(postImported > 0) { getItemsTable().reset(); } if(importItems.isEmpty()) { showWarning("import.failed"); } else { showInfo("import.success", Integer.toString(importItems.size())); getItemsTable().reset(); } } } private void doOpenRepositoryImport(UserRequest ureq) { removeAsListenerAndDispose(importTestCtrl); String[] allowed = new String[]{ ImsQTI21Resource.TYPE_NAME, TestFileResource.TYPE_NAME, SurveyFileResource.TYPE_NAME }; importTestCtrl = new ReferencableEntriesSearchController(getWindowControl(), ureq, allowed, null, translate("import.repository"), false, false, false, true, Can.copyable); listenTo(importTestCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), importTestCtrl.getInitialComponent(), true, translate("import.repository")); cmc.setContextHelp(getTranslator(),"Data Management#qb_share"); cmc.activate(); listenTo(cmc); } private void doOpenExcelImportQTI12(UserRequest ureq) { removeAsListenerAndDispose(excelImportWizard); final ItemsPackage importPackage = new ItemsPackage(); Step additionalStep = null; if(getSource().askEditable()) { additionalStep = new EditableStep(ureq); } final org.olat.ims.qti.questionimport.ImportOptions options = new org.olat.ims.qti.questionimport.ImportOptions(); options.setShuffle(true); Step start = new org.olat.ims.qti.questionimport.QImport_1_InputStep(ureq, importPackage, options, additionalStep); StepRunnerCallback finish = new StepRunnerCallback() { @Override public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) { List<ItemAndMetadata> itemsToImport = importPackage.getItems(); QTIQPoolServiceProvider spi = CoreSpringFactory.getImpl (QTIQPoolServiceProvider.class); List<QuestionItem> importItems = spi.importBeecomItem(getIdentity(), itemsToImport, getLocale()); boolean editable = true; if(getSource().askEditable()) { Object editableCtx = runContext.get("editable"); editable = (editableCtx instanceof Boolean) ? ((Boolean)editableCtx).booleanValue() : false; } int postImported = getSource().postImport(importItems, editable); if(postImported > 0) { getItemsTable().reset(); } return StepsMainRunController.DONE_MODIFIED; } }; excelImportWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("import.excellike.12"), "o_sel_qpool_excel_import_wizard"); listenTo(excelImportWizard); getWindowControl().pushAsModalDialog(excelImportWizard.getInitialComponent()); } private void doOpenExcelImportQTI21(UserRequest ureq) { removeAsListenerAndDispose(excelImportWizard); Step additionalStep = null; if(getSource().askEditable()) { additionalStep = new EditableStep(ureq); } final AssessmentItemsPackage importPackage = new AssessmentItemsPackage(); final ImportOptions options = new ImportOptions(); options.setShuffle(true); Step start = new QImport_1_InputStep(ureq, importPackage, options, additionalStep); StepRunnerCallback finish = new StepRunnerCallback() { @Override public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) { QTI21QPoolServiceProvider spi = CoreSpringFactory.getImpl(QTI21QPoolServiceProvider.class); List<AssessmentItemAndMetadata> items = importPackage.getItems(); List<QuestionItem> importItems = new ArrayList<>(); for(AssessmentItemAndMetadata item:items) { QuestionItem importedItem = spi.importExcelItem(getIdentity(), item, getLocale()); if(importedItem != null) { importItems.add(importedItem); } } boolean editable = true; if(getSource().askEditable()) { Object editableCtx = runContext.get("editable"); editable = (editableCtx instanceof Boolean) ? ((Boolean)editableCtx).booleanValue() : false; } int postImported = getSource().postImport(importItems, editable); if(postImported > 0) { getItemsTable().reset(); } return StepsMainRunController.DONE_MODIFIED; } }; excelImportWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("import.excellike.21"), "o_sel_qpool_excel_import_wizard"); listenTo(excelImportWizard); getWindowControl().pushAsModalDialog(excelImportWizard.getInitialComponent()); } protected void doList(UserRequest ureq) { String title = translate("filter.view"); removeAsListenerAndDispose(listTargetCtrl); listTargetCtrl = new CollectionTargetController(ureq, getWindowControl(), itemCollection != null); listenTo(listTargetCtrl); removeAsListenerAndDispose(calloutCtrl); calloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), listTargetCtrl.getInitialComponent(), list, title, true, null); listenTo(calloutCtrl); calloutCtrl.activate(); } private void doAskCollectionName(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(createCollectionCtrl); createCollectionCtrl = new CreateCollectionController(ureq, getWindowControl()); createCollectionCtrl.setUserObject(items); listenTo(createCollectionCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), createCollectionCtrl.getInitialComponent(), true, translate("create.list")); cmc.activate(); listenTo(cmc); } private void doChooseCollection(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(chooseCollectionCtrl); chooseCollectionCtrl = new CollectionListController(ureq, getWindowControl()); chooseCollectionCtrl.setUserObject(items); listenTo(chooseCollectionCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), chooseCollectionCtrl.getInitialComponent(), true, translate("add.to.list")); cmc.activate(); listenTo(cmc); } /** * Test only QTI 1.2 * @param ureq * @param items */ private void doExport(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(exportWizard); Step start = new Export_1_TypeStep(ureq, items); StepRunnerCallback finish = new StepRunnerCallback() { @Override public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) { return StepsMainRunController.DONE_MODIFIED; } }; exportWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("export.item"), "o_sel_qpool_export_1_wizard"); listenTo(exportWizard); getWindowControl().pushAsModalDialog(exportWizard.getInitialComponent()); } private void doExecuteExport(UserRequest ureq, StepsRunContext runContext) { ExportFormatOptions format = (ExportFormatOptions)runContext.get("format"); @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)runContext.get("itemsToExport"); switch(format.getOutcome()) { case download: { MediaResource mr = qpoolService.export(items, format, getLocale()); if(mr != null) { ureq.getDispatchResult().setResultingMediaResource(mr); } break; } case repository: { doExportToRepository(ureq, items, format.getResourceTypeFormat()); break; } } } private void doExportToRepository(UserRequest ureq, List<QuestionItemShort> items, String type) { removeAsListenerAndDispose(cmc); removeAsListenerAndDispose(addController); RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type); addController = handler.createCreateRepositoryEntryController(ureq, getWindowControl()); addController.setCreateObject(new QItemList(items)); listenTo(addController); cmc = new CloseableModalController(getWindowControl(), translate("close"), addController.getInitialComponent()); listenTo(cmc); cmc.activate(); } private void doExportToRepositoryEntry(UserRequest ureq, Long repoEntryKey) { RepositoryEntry re = repositoryManager.lookupRepositoryEntry(repoEntryKey, false); if(re != null) { WindowControl wControl = BusinessControlFactory.getInstance() .createBusinessWindowControl(getWindowControl(), re, OresHelper.createOLATResourceableType("Editor")); NewControllerFactory.getInstance().launch(ureq, wControl); } } private void doCreateCollection(UserRequest ureq, String name, List<QuestionItemShort> items) { QuestionItemCollection coll = qpoolService.createCollection(getIdentity(), name, items); fireEvent(ureq, new QPoolEvent(QPoolEvent.COLL_CREATED, coll.getKey())); } private void doChooseAuthoren(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(importAuthorsWizard); Step start = new ImportAuthor_1_ChooseMemberStep(ureq, items); StepRunnerCallback finish = new StepRunnerCallback() { @Override public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) { addAuthors(runContext); return StepsMainRunController.DONE_MODIFIED; } }; importAuthorsWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("author.item"), "o_sel_qpool_import_1_wizard"); listenTo(importAuthorsWizard); getWindowControl().pushAsModalDialog(importAuthorsWizard.getInitialComponent()); } private void addAuthors(StepsRunContext runContext) { @SuppressWarnings("unchecked") List<QuestionItemShort> items = (List<QuestionItemShort>)runContext.get("items"); @SuppressWarnings("unchecked") List<Identity> authors = (List<Identity>)runContext.get("members"); qpoolService.addAuthors(authors, items); } private void doConfirmDelete(UserRequest ureq, List<QuestionItemShort> items) { StringBuilder sb = new StringBuilder(); for(QuestionItemShort item:items) { if(sb.length() > 0) sb.append(", "); sb.append(StringHelper.escapeHtml(item.getTitle())); } String msg; if(items.size() > 1) { msg = translate("confirm.delete.plural", sb.toString()); } else { msg = translate("confirm.delete", sb.toString()); } confirmDeleteBox = activateYesNoDialog(ureq, null, msg, confirmDeleteBox); confirmDeleteBox.setCssClass("o_error"); confirmDeleteBox.setUserObject(items); } private void doDelete(List<QuestionItemShort> items) { qpoolService.deleteItems(items); getItemsTable().reset(true, true, true); showInfo("item.deleted"); } protected void doShare(UserRequest ureq) { String title = translate("filter.view"); removeAsListenerAndDispose(shareTargetCtrl); shareTargetCtrl = new ShareTargetController(ureq, getWindowControl()); listenTo(shareTargetCtrl); removeAsListenerAndDispose(calloutCtrl); calloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), shareTargetCtrl.getInitialComponent(), shareItem, title, true, null); listenTo(calloutCtrl); calloutCtrl.activate(); } private void doConfirmRemove(UserRequest ureq, List<QuestionItemShort> items) { String text = translate("confirm.unshare", new String[]{ getSource().getName() }); confirmRemoveBox = activateYesNoDialog(ureq, null, text, confirmRemoveBox); confirmRemoveBox.setUserObject(items); confirmRemoveBox.setContextHelp("Data Management#qb_remove"); } protected void doRemove(List<QuestionItemShort> items) { getSource().removeFromSource(items); getItemsTable().reset(); showInfo("item.deleted"); } private void doOpenRenameCallout(UserRequest ureq) { removeAsListenerAndDispose(renameCtrl); renameCtrl = new RenameController(ureq, getWindowControl()); listenTo(renameCtrl); removeAsListenerAndDispose(cmc); cmc = new CloseableModalController(getWindowControl(), translate("close"), renameCtrl.getInitialComponent(), true, translate("rename.collection")); cmc.activate(); listenTo(cmc); } private void doRenameItemCollection(UserRequest ureq, String newName) { itemCollection = qpoolService.renameCollection(itemCollection, newName); fireEvent(ureq, new QPoolEvent(QPoolEvent.COLL_CHANGED, itemCollection.getKey())); } private void doConfirmDeleteSource(UserRequest ureq) { confirmDeleteSourceBox = activateYesNoDialog(ureq, null, translate("confirm.delete.source"), confirmDeleteSourceBox); } private void doDeleteItemCollection(UserRequest ureq) { qpoolService.deleteCollection(itemCollection); fireEvent(ureq, new QPoolEvent(QPoolEvent.COLL_DELETED)); } protected void doSelectGroup(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(selectGroupCtrl); selectGroupCtrl = new SelectBusinessGroupController(ureq, getWindowControl()); selectGroupCtrl.setUserObject(items); listenTo(selectGroupCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), selectGroupCtrl.getInitialComponent(), true, translate("select.group")); cmc.setContextHelp(getTranslator(), "Data Management#qb_share"); cmc.activate(); listenTo(cmc); } protected void doSelectPool(UserRequest ureq, List<QuestionItemShort> items) { removeAsListenerAndDispose(selectPoolCtrl); selectPoolCtrl = new PoolsController(ureq, getWindowControl()); selectPoolCtrl.setUserObject(items); listenTo(selectPoolCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), selectPoolCtrl.getInitialComponent(), true, translate("select.pool")); cmc.activate(); listenTo(cmc); } protected void doConfirmCopy(UserRequest ureq, List<QuestionItemShort> items) { String title = translate("copy"); String text = translate("copy.confirmation"); confirmCopyBox = activateYesNoDialog(ureq, title, text, confirmCopyBox); confirmCopyBox.setUserObject(items); } protected void doCopy(UserRequest ureq, List<QuestionItemShort> items) { List<QuestionItem> copies = qpoolService.copyItems(getIdentity(), items); getItemsTable().reset(); showInfo("item.copied", Integer.toString(copies.size())); fireEvent(ureq, new QPoolEvent(QPoolEvent.EDIT)); } protected void doConfirmConversion(UserRequest ureq, List<QuestionItemShort> items) { Map<String,List<QuestionItemShort>> formatToItems = new HashMap<>(); List<QPoolSPI> spies = qpoolModule.getQuestionPoolProviders(); for(QuestionItemShort item:items) { for(QPoolSPI sp:spies) { if(sp != null && sp.isConversionPossible(item)) { List<QuestionItemShort> convertItems; if(formatToItems.containsKey(sp.getFormat())) { convertItems = formatToItems.get(sp.getFormat()); } else { convertItems = new ArrayList<>(items.size()); formatToItems.put(sp.getFormat(), convertItems); } convertItems.add(item); } } } if(formatToItems.isEmpty()) { showWarning("convert.item.not.possible"); } else { conversionConfirmationCtrl = new ConversionConfirmationController(ureq, getWindowControl(), formatToItems); listenTo(conversionConfirmationCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), conversionConfirmationCtrl.getInitialComponent(), true, translate("convert.item")); cmc.activate(); listenTo(cmc); } } protected void doConvert(UserRequest ureq, List<QuestionItemShort> items, String format) { QPoolSPI sp = qpoolModule.getQuestionPoolProvider(format); int count = 0; for(QuestionItemShort item:items) { QuestionItem convertedQuestion = sp.convert(getIdentity(), item, getLocale()); if(convertedQuestion != null) { count++; } } if(count == items.size()) { showInfo("convert.item.successful", new String[]{ Integer.toString(count)} ); } else { int errors = items.size() - count; showWarning("convert.item.warning", new String[]{ Integer.toString(errors), Integer.toString(items.size()) } ); } getItemsTable().reset(); fireEvent(ureq, new QPoolEvent(QPoolEvent.EDIT)); } private void doShareItemsToGroups(UserRequest ureq, List<QuestionItemShort> items, List<BusinessGroup> groups, List<Pool> pools) { removeAsListenerAndDispose(shareItemsCtrl); shareItemsCtrl = new ShareItemOptionController(ureq, getWindowControl(), items, groups, pools); listenTo(shareItemsCtrl); cmc = new CloseableModalController(getWindowControl(), translate("close"), shareItemsCtrl.getInitialComponent(), true, translate("share.item")); cmc.activate(); listenTo(cmc); } @Override protected void doSelect(UserRequest ureq, ItemRow row) { QuestionItem item = qpoolService.loadItemById(row.getKey()); doSelect(ureq, item, row.isEditable()); } protected QuestionItemDetailsController doSelect(UserRequest ureq, QuestionItem item, boolean editable) { removeAsListenerAndDispose(currentDetailsCtrl); removeAsListenerAndDispose(currentMainDetailsCtrl); WindowControl bwControl = addToHistory(ureq, item, null); currentDetailsCtrl = new QuestionItemDetailsController(ureq, bwControl, item, editable, getSource().isDeleteEnabled()); currentDetailsCtrl.setBreadcrumbPanel(stackPanel); listenTo(currentDetailsCtrl); currentMainDetailsCtrl = new LayoutMain3ColsController(ureq, getWindowControl(), currentDetailsCtrl); listenTo(currentMainDetailsCtrl); stackPanel.pushController(item.getTitle(), currentMainDetailsCtrl); return currentDetailsCtrl; } }