/****************************************************************************
|
**
|
** Copyright (C) 2022 The Qt Company Ltd.
|
** Contact: https://www.qt.io/licensing/
|
**
|
** This file is part of the Qt VS Tools.
|
**
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
** Commercial License Usage
|
** Licensees holding valid commercial Qt licenses may use this file in
|
** accordance with the commercial license agreement provided with the
|
** Software or, alternatively, in accordance with the terms contained in
|
** a written agreement between you and The Qt Company. For licensing terms
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
** information use the contact form at https://www.qt.io/contact-us.
|
**
|
** GNU General Public License Usage
|
** Alternatively, this file may be used under the terms of the GNU
|
** General Public License version 3 as published by the Free Software
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
** included in the packaging of this file. Please review the following
|
** information to ensure the GNU General Public License requirements will
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
**
|
** $QT_END_LICENSE$
|
**
|
****************************************************************************/
|
|
using System;
|
using System.Collections.Generic;
|
using Microsoft.VisualStudio.Shell;
|
using Microsoft.VisualStudio.VCProjectEngine;
|
using Microsoft.Win32;
|
using QtVsTools.Core;
|
|
namespace QtVsTools.Common
|
{
|
public static class QtVSIPSettingsShared
|
{
|
private static readonly Dictionary<string, string> mocDirCache
|
= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
private static readonly Dictionary<string, string> uicDirCache
|
= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
private static readonly Dictionary<string, string> rccDirCache
|
= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
public static string GetDirectory(EnvDTE.Project project, string type)
|
{
|
ThreadHelper.ThrowIfNotOnUIThread();
|
|
// check for directory in following order:
|
// - stored in project
|
// - stored in cache
|
// - retrieve from moc/uic steps
|
// - fall-back on hard-coded directory
|
|
var fullName = project?.FullName;
|
if (string.IsNullOrEmpty(fullName))
|
return GetDirectory(type); // - fall-back on hard-coded directory
|
|
if (project.Globals.get_VariablePersists(type)) // - stored in project
|
return HelperFunctions.NormalizeRelativeFilePath(project.Globals[type] as string);
|
|
switch (type) { // - stored in cache
|
case Resources.mocDirKeyword:
|
if (mocDirCache.ContainsKey(fullName))
|
return mocDirCache[fullName];
|
break;
|
case Resources.uicDirKeyword:
|
if (uicDirCache.ContainsKey(fullName))
|
return uicDirCache[fullName];
|
break;
|
case Resources.rccDirKeyword:
|
if (rccDirCache.ContainsKey(fullName))
|
return rccDirCache[fullName];
|
break;
|
default:
|
return GetDirectory(type); // - fall-back on hard-coded directory
|
}
|
|
try {
|
string configName = null;
|
string platformName = null;
|
QtCustomBuildTool tool = null;
|
foreach (VCFile vcfile in (project.Object as VCProject).Files as IVCCollection) {
|
var name = vcfile?.Name;
|
if (string.IsNullOrEmpty(name))
|
continue;
|
if (!(HelperFunctions.IsHeaderFile(name) || HelperFunctions.IsMocFile(name)
|
|| HelperFunctions.IsUicFile(name) || HelperFunctions.IsQrcFile(name)))
|
continue;
|
|
foreach (VCFileConfiguration config in vcfile?.FileConfigurations as IVCCollection) {
|
if (HelperFunctions.IsConfExcludeFromSolution(config))
|
continue;
|
tool = new QtCustomBuildTool(config);
|
if (tool == null)
|
continue;
|
configName = config.Name.Remove(config.Name.IndexOf('|'));
|
var vcConfig = config.ProjectConfiguration as VCConfiguration;
|
platformName = (vcConfig.Platform as VCPlatform).Name;
|
var cmd = tool.CommandLine;
|
if (cmd.Contains("moc.exe") || cmd.Contains("uic.exe") || cmd.Contains("rcc.exe"))
|
break;
|
tool = null;
|
}
|
|
if (tool != null)
|
break;
|
}
|
|
if (tool == null)
|
return GetDirectory(type); // - fall-back on hard-coded directory
|
|
var dir = ".";
|
var lastindex = tool.Outputs.LastIndexOf('\\');
|
if (tool.Outputs.LastIndexOf('/') > lastindex)
|
lastindex = tool.Outputs.LastIndexOf('/');
|
|
if (lastindex != -1)
|
dir = tool.Outputs.Substring(0, lastindex);
|
dir = dir.Replace("\"", "");
|
|
if (type == Resources.mocDirKeyword) {
|
int index = dir.IndexOf(configName, StringComparison.OrdinalIgnoreCase);
|
if (index != -1)
|
dir = dir.Replace(dir.Substring(index, configName.Length), "$(ConfigurationName)");
|
|
index = dir.IndexOf(platformName, StringComparison.OrdinalIgnoreCase);
|
if (index != -1)
|
dir = dir.Replace(dir.Substring(index, platformName.Length), "$(PlatformName)");
|
dir = HelperFunctions.NormalizeRelativeFilePath(dir);
|
|
mocDirCache.Add(fullName, dir);
|
} else if (type == Resources.uicDirKeyword) {
|
dir = HelperFunctions.NormalizeRelativeFilePath(dir);
|
uicDirCache.Add(fullName, dir);
|
} else if (type == Resources.rccDirKeyword) {
|
dir = HelperFunctions.NormalizeRelativeFilePath(dir);
|
rccDirCache.Add(fullName, dir);
|
} else {
|
dir = HelperFunctions.NormalizeRelativeFilePath(dir);
|
}
|
|
CleanUpCache(project);
|
return dir; // - retrieved from moc/uic/rcc steps
|
} catch { }
|
return GetDirectory(type); // - fall-back on hard-coded directory
|
}
|
|
private const string registryPath = "SOFTWARE\\" + Resources.registryPackagePath;
|
|
public static string GetDirectory(string type)
|
{
|
try {
|
var key = Registry.CurrentUser.OpenSubKey(registryPath);
|
if (key != null) {
|
if (key.GetValue(type, null) is string path)
|
return HelperFunctions.NormalizeRelativeFilePath(path);
|
}
|
} catch { }
|
if (type == Resources.mocDirKeyword)
|
return Resources.generatedFilesDir + "\\$(ConfigurationName)";
|
return Resources.generatedFilesDir;
|
}
|
|
public static string GetOption(EnvDTE.Project project, string type)
|
{
|
ThreadHelper.ThrowIfNotOnUIThread();
|
|
// check for directory in following order:
|
// - stored in project
|
// - globally defined default option
|
// - empty options
|
if (project != null && project.Globals.get_VariablePersists(type))
|
return project.Globals[type] as string;
|
return GetOption(type);
|
}
|
|
public static string GetOption(string type)
|
{
|
try {
|
var key = Registry.CurrentUser.OpenSubKey(registryPath);
|
if (key != null) {
|
if (key.GetValue(type, null) is string opt)
|
return opt;
|
}
|
} catch { }
|
return null;
|
}
|
|
public static bool GetBoolValue(EnvDTE.Project project, string type)
|
{
|
ThreadHelper.ThrowIfNotOnUIThread();
|
|
// check for directory in following order:
|
// - stored in project
|
// - globally defined default option
|
// - empty options
|
if (project != null && project.Globals.get_VariablePersists(type))
|
return Convert.ToInt32(project.Globals[type] as string) > 0;
|
return GetBoolValue(type, false);
|
}
|
|
public static bool GetBoolValue(string key, bool defaultValue)
|
{
|
var regKey = Registry.CurrentUser.OpenSubKey(registryPath);
|
if (regKey == null)
|
return defaultValue;
|
return ((int)regKey.GetValue(key, defaultValue ? 1 : 0)) > 0;
|
}
|
|
public static bool ValueExists(string key)
|
{
|
var regKey = Registry.CurrentUser.OpenSubKey(registryPath);
|
if (regKey != null) {
|
foreach (var s in regKey.GetValueNames()) {
|
if (s == key)
|
return true;
|
}
|
}
|
return false;
|
}
|
|
public static string GetProjectQtSetting(EnvDTE.Project project, string propertyName)
|
{
|
ThreadHelper.ThrowIfNotOnUIThread();
|
|
var activeConfig = project?.ConfigurationManager?.ActiveConfiguration;
|
if (activeConfig == null)
|
return null;
|
var activeConfigId = $"{activeConfig.ConfigurationName}|{activeConfig.PlatformName}";
|
|
try {
|
var props = project.Object as VCProject as IVCBuildPropertyStorage;
|
return props?.GetPropertyValue(propertyName, activeConfigId, "ProjectFile");
|
} catch {
|
return null;
|
}
|
}
|
|
public static void CleanUpCache(EnvDTE.Project project)
|
{
|
ThreadHelper.ThrowIfNotOnUIThread();
|
|
var projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
foreach (var p in HelperFunctions.ProjectsInSolution(project.DTE))
|
projects.Add(p.FullName);
|
|
mocDirCache.RemoveValues(projects);
|
uicDirCache.RemoveValues(projects);
|
rccDirCache.RemoveValues(projects);
|
}
|
|
static void RemoveValues(this Dictionary<string, string> cache, HashSet<string> projects)
|
{
|
foreach (var key in cache.Keys) {
|
if (projects.Contains(key))
|
cache.Remove(key);
|
}
|
}
|
}
|
}
|