classdef mcuPath % Класс для работы с путями файлов и папок в маске Simulink % Обеспечивает преобразование путей, добавление в таблицы и параметры methods(Static) %% GET PATH FROM PARAM - получение путей из параметров маски function path = get(paramName) % Получение значения пути из параметра маски % paramName - имя параметра маски содержащего путь % Возвращает строку с путём (абсолютным или относительным) blockPath = gcb; path = get_param(blockPath, paramName); end %% ADD PATH TO TABLE - добавление путей в табличные параметры function addSourceFileTable(targetParamName, message) % Добавление исходных файлов в таблицу через диалог выбора % targetParamName - имя табличного параметра маски % message - сообщение в диалоге выбора % Открываем проводник для выбора файлов с фильтрами [files, pathstr] = uigetfile({ ... '*.c;*.cpp', 'Исходные файлы (*.c, *.cpp)'; ... '*.obj;*.lib', 'Библиотеки (*.obj, *.lib)'; ... '*.*', 'Все файлы (*.*)'}, ... message, ... 'MultiSelect', 'on'); % Разрешаем множественный выбор if isequal(files, 0) return; % Пользователь отменил выбор end % Нормализуем входные данные: один файл -> cell array if ischar(files) files = {files}; end % Читаем текущее содержимое таблицы oldTable = customtable.parse(targetParamName); % Добавляем новые пути, проверяя уникальность for i = 1:numel(files) fullpath = fullfile(pathstr, files{i}); % Преобразуем абсолютный путь в относительный rel = mcuPath.absoluteToRelativePath(fullpath); % Добавляем только если путь ещё не существует в таблице if ~any(strcmp(rel, oldTable)) oldTable{end+1, 1} = rel; end end % Сохраняем обновленную таблицу обратно в параметр маски customtable.collect(targetParamName, oldTable); end function addPathTable(targetParamName, message) % Добавление путей к папкам в таблицу через диалог выбора % targetParamName - имя табличного параметра маски % message - сообщение в диалоге выбора % Открываем проводник для выбора папки pathstr = uigetdir(pwd, message); if isequal(pathstr, 0) return; % Пользователь отменил выбор end % Читаем текущее содержимое таблицы oldTable = customtable.parse(targetParamName); % Преобразуем абсолютный путь в относительный rel = mcuPath.absoluteToRelativePath(pathstr); % Проверяем наличие пути в таблице и добавляем если нужно if ~any(strcmp(rel, oldTable)) oldTable{end+1, 1} = rel; end % Сохраняем обновленную таблицу customtable.collect(targetParamName, oldTable); end %% ADD PATH TO EDIT - добавление путей в текстовые параметры function addPath(targetParamName, message) % Добавление пути к папке в текстовый параметр маски % targetParamName - имя параметра маски для пути % message - сообщение в диалоге выбора (не используется) block = gcb; mask = Simulink.Mask.get(block); % Открываем окно выбора папки folderPath = uigetdir('', 'Выберите папку'); % Проверка на отмену выбора if isequal(folderPath, 0) return; end % Преобразуем абсолютный путь в относительный rel = mcuPath.absoluteToRelativePath(folderPath); % Устанавливаем значение параметра маски param = mask.getParameter(targetParamName); param.Value = rel; end function addAnyFile(targetParamName, message) % Добавление пути к файлу в текстовый параметр маски % targetParamName - имя параметра маски для пути к файлу % message - сообщение в диалоге выбора (не используется) block = gcbh; mask = Simulink.Mask.get(block); % Открываем проводник для выбора любого файла [file, path] = uigetfile({'*.*','Все файлы (*.*)'}, 'Выберите файл'); if isequal(file, 0) || isequal(path, 0) return; % Пользователь отменил выбор end % Формируем полный путь и преобразуем в относительный fullFilePath = fullfile(path, file); rel = mcuPath.absoluteToRelativePath(fullFilePath); % Устанавливаем значение параметра маски param = mask.getParameter(targetParamName); param.Value = rel; end %% GET PATH STRING - утилиты преобразования путей function absPath = getAbsolutePath(relPath) % Преобразование относительного пути в абсолютный % relPath - относительный или абсолютный путь % Возвращает абсолютный путь в канонической форме % Проверка: абсолютный ли путь уже if ispc % Для Windows: путь начинается с буквы диска или \\ isAbsolute = ~isempty(regexp(relPath, '^[a-zA-Z]:[\\/]', 'once')) || startsWith(relPath, '\\'); else % Для Unix: путь начинается с / isAbsolute = startsWith(relPath, '/'); end if isAbsolute % Канонизируем абсолютный путь (убираем ./, ../ и т.п.) absPath = char(java.io.File(relPath).getCanonicalPath()); else % Строим абсолютный путь относительно текущей директории cwd = pwd; combined = fullfile(cwd, relPath); absPath = char(java.io.File(combined).getCanonicalPath()); end end function rel = absoluteToRelativePath(pathstr) % Преобразование абсолютного пути в относительный относительно текущей директории % pathstr - абсолютный путь для преобразования % Возвращает относительный путь % % Примеры: % Если путь в текущей директории -> './filename' % Если путь выше -> '../parent/filename' % Если путь совпадает с текущей директорией -> '.' % Получаем текущую рабочую директорию cwd = pwd; % Преобразуем оба пути в канонические абсолютные пути fullpath = char(java.io.File(pathstr).getCanonicalPath()); cwd = char(java.io.File(cwd).getCanonicalPath()); % Разбиваем пути на части по разделителю файловой системы targetParts = strsplit(fullpath, filesep); baseParts = strsplit(cwd, filesep); % Находим длину общего префикса (совпадающих частей пути) j = 1; while j <= min(length(targetParts), length(baseParts)) && strcmpi(targetParts{j}, baseParts{j}) j = j + 1; end % Формируем количество подъемов ".." для выхода из базовой директории numUps = length(baseParts) - (j - 1); ups = repmat({'..'}, 1, numUps); % Оставшаяся часть целевого пути после общего префикса rest = targetParts(j:end); % Объединяем части для получения относительного пути relParts = [ups, rest]; rel = fullfile(relParts{:}); % Если путь пустой - это текущая директория if isempty(rel) rel = '.'; end % Если путь не содержит ".." и начинается внутри текущей директории - добавляем './' if ~isempty(rest) && isempty(ups) rel = fullfile('.', rel); end end end end