private void openProgramLocations(List<ProgramLocator> locators) {
		if (locators.isEmpty()) {
			return;
		}
		Set<ProgramLocator> toOpen = new LinkedHashSet<>(locators); 	// preserve order

		// ensure already opened programs are visible in the tool
		Map<ProgramLocator, Program> alreadyOpen = getOpenPrograms(toOpen);
		makeVisibleInTool(alreadyOpen.values());
		toOpen.removeAll(alreadyOpen.keySet());

		// ensure cached programs are in the tool
		Map<ProgramLocator, Program> openedFromCache = openCachedProgramsInTool(toOpen);
		toOpen.removeAll(openedFromCache.keySet());

		// if nothing to open, make the first program in the list the current program
		if (toOpen.isEmpty()) {
			Program first = programMgr.getOpenProgram(locators.get(0));
			showProgram(first, locators.get(0), OPEN_CURRENT);
			return;
		}

		// Need to open at least one program. Make the first one to open the current program.
		OpenProgramTask task = new OpenProgramTask(new ArrayList<>(toOpen), this);
		new TaskLauncher(task, tool.getToolFrame());

		List<OpenProgramRequest> openProgramReqs = task.getOpenPrograms();

		int openState = OPEN_CURRENT;
		for (OpenProgramRequest programReq : openProgramReqs) {
			showProgram(programReq.getProgram(), programReq.getLocator(), openState);
			programReq.release();
			openState = OPEN_VISIBLE;
		}
	}
Start a transaction if one has not been started; needed when program properties are about to
change from the options editor.
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java