001package jmri.jmrit.display.layoutEditor; 002 003import java.util.ArrayList; 004import java.util.List; 005import jmri.*; 006import jmri.NamedBean.BadNameException; 007 008/** 009 * The transit creation tool, is designed to be used by higher level tools to 010 * create transits between Beans. The higher level tools would already have a 011 * valid knowledge of the track layout and Sections, therefore this tool does 012 * little validation of sections being added to the transit. 013 * <hr> 014 * The tool currently only deals with SignalMasts, that have had logic created 015 * and also have a section associated between them. 016 * <hr> 017 * This file is part of JMRI. 018 * <p> 019 * JMRI is free software; you can redistribute it and/or modify it under the 020 * terms of version 2 of the GNU General Public License as published by the Free 021 * Software Foundation. See the "COPYING" file for a copy of this license. 022 * <p> 023 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 024 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 025 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 026 * 027 * @author Kevin Dickerson Copyright (C) 2011 028 * @author George Warner Copyright (c) 2017-2018 029 */ 030final public class TransitCreationTool { 031 032 public TransitCreationTool() { 033 } 034 035 ArrayList<NamedBean> list = new ArrayList<>(); 036 037 public void addNamedBean(NamedBean nb) throws JmriException { 038 if (!list.isEmpty()) { 039 if (list.get(list.size() - 1) == nb) { 040 log.debug("Bean is the same as the last one so will not add or error"); 041 return; 042 } 043 //Run through a series of checks that this bean is reachable from the previous 044 if ((nb instanceof SignalMast) && (list.get(list.size() - 1) instanceof SignalMast)) { 045 SignalMastLogicManager smlm = InstanceManager.getDefault(SignalMastLogicManager.class); 046 SignalMastLogic sml = smlm.getSignalMastLogic(((SignalMast) list.get(list.size() - 1))); 047 if (sml == null || !sml.isDestinationValid((SignalMast) nb)) { 048 String error = Bundle.getMessage("TCTErrorMastPairsNotValid", nb.getDisplayName(), list.get(list.size() - 1).getDisplayName()); 049 log.error("will throw {}", error); 050 throw new JmriException(error); 051 } 052 if (sml.getAssociatedSection((SignalMast) nb) == null) { 053 String error = Bundle.getMessage("TCTErrorMastPairsNoSection", list.get(list.size() - 1).getDisplayName(), nb.getDisplayName()); 054 log.error("will throw {}", error); 055 throw new JmriException(error); 056 } 057 } else { 058 //Need to add the method to get layout block connectivity. Also work checking that the Layout Block routing has been initialised. 059 } 060 } 061 list.add(nb); 062 } 063 064 public Transit createTransit() throws JmriException { 065 TransitManager tm = InstanceManager.getDefault(TransitManager.class); 066 String transitName = "From " + list.get(0).getDisplayName() + " to " + list.get(list.size() - 1).getDisplayName(); 067 Transit t; 068 try { 069 t = tm.createNewTransit(transitName); 070 } catch (BadNameException ex) { 071 log.error("Unable to create transit {} {}", transitName,ex.getMessage()); 072 throw new JmriException(Bundle.getMessage("TCTErrorUnableToCreate", transitName) + " " + ex.getLocalizedMessage()); 073 } 074 if (list.get(0) instanceof SignalMast) { 075 SignalMastLogicManager smlm = InstanceManager.getDefault(SignalMastLogicManager.class); 076 int seqNo = 1; 077 // Add stub block section if applicable 078 SignalMastLogic smlForFirstMast = smlm.getSignalMastLogic((SignalMast) list.get(0)); 079 if (smlForFirstMast != null) { 080 LayoutBlock layoutBlock = smlForFirstMast.getFacingBlock(); 081 if (layoutBlock!=null && layoutBlock.getNumberOfNeighbours() == 1) { 082 // A stub track block has one neighbor 083 SectionManager sectionManager = InstanceManager.getDefault(SectionManager.class); 084 for (Section section : sectionManager.getNamedBeanSet()) { 085 // Look for a user defined section that has one block that matches the layout block 086 if (section.getSectionType() == Section.USERDEFINED) { 087 if (section.getNumBlocks() == 1 && layoutBlock.getBlock().equals(section.getEntryBlock())) { 088 t.addTransitSection(new TransitSection(section, seqNo, Section.FORWARD)); 089 seqNo++; 090 break; 091 } 092 } 093 } 094 if (seqNo == 1) { 095 log.warn("Unable to find a stub block section for {}", layoutBlock.getDisplayName()); 096 } 097 } 098 } 099 for (int i = 1; i <= list.size() - 1; i++) { 100 SignalMastLogic sml = smlm.getSignalMastLogic((SignalMast) list.get(i - 1)); 101 if (sml==null){ 102 String error = "Cannot locate SML for SM " + list.get(i - 1).getDisplayName(); 103 log.error("will throw {}", error); 104 tm.deregister(t); 105 t.dispose(); 106 cancelTransitCreate(); 107 throw new JmriException(error); 108 } 109 Section sec = sml.getAssociatedSection((SignalMast) list.get(i)); 110 //In theory sec being null would already have been tested when the signal was added. 111 if (sec == null) { 112 String error = Bundle.getMessage("TCTErrorMastPairsNoSection", list.get(i - 1).getDisplayName(), list.get(i).getDisplayName()); 113 log.error("will throw {}", error); 114 tm.deregister(t); 115 t.dispose(); 116 cancelTransitCreate(); 117 throw new JmriException(error); 118 } 119 t.addTransitSection(new TransitSection(sec, seqNo, Section.FORWARD)); 120 seqNo++; 121 } 122 } 123 //Once created clear the list for a fresh start. 124 list = new ArrayList<>(); 125 return t; 126 } 127 128 public void cancelTransitCreate() { 129 list = new ArrayList<>(); 130 } 131 132 public List<NamedBean> getBeans() { 133 return list; 134 } 135 136 public boolean isToolInUse() { 137 return !list.isEmpty(); 138 } 139 140 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TransitCreationTool.class); 141}