diff options
| author | Tannin <Tannin@Serenity> | 2013-02-03 12:49:25 +0100 |
|---|---|---|
| committer | Tannin <Tannin@Serenity> | 2013-02-03 12:49:25 +0100 |
| commit | 981f8b3acf7e76f27c02f4ced80d55b424cc7497 (patch) | |
| tree | 0f504d99d1e5fe197258febff3c147d0725abda4 | |
initial commit to mercurial repository.
Corresponds to MO version 0.12.6
278 files changed, 79248 insertions, 0 deletions
diff --git a/src/Doxyfile b/src/Doxyfile new file mode 100644 index 00000000..15fd698b --- /dev/null +++ b/src/Doxyfile @@ -0,0 +1,1824 @@ +# Doxyfile 1.8.1.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Mod Organizer UI" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.12.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "The user interface to mod organizer" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = "../../../../../../Program Files (x86)/Graphviz 2.28/bin" + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/src/ModOrganizer.pro b/src/ModOrganizer.pro new file mode 100644 index 00000000..3d7e2656 --- /dev/null +++ b/src/ModOrganizer.pro @@ -0,0 +1,21 @@ +TEMPLATE = subdirs
+CONFIG += ordered
+
+
+SUBDIRS = shared \
+ uibase \
+ organizer \
+ hookdll \
+ archive \
+ helper \
+ plugins \
+ proxydll
+
+hookdll.depends = shared
+organizer.depends = shared, uibase
+
+CONFIG(debug, debug|release) {
+ DESTDIR = outputd
+} else {
+ DESTDIR = output
+}
\ No newline at end of file diff --git a/src/activatemodsdialog.cpp b/src/activatemodsdialog.cpp new file mode 100644 index 00000000..fe085c49 --- /dev/null +++ b/src/activatemodsdialog.cpp @@ -0,0 +1,102 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "activatemodsdialog.h"
+#include "ui_activatemodsdialog.h"
+
+#include <QComboBox>
+#include <QLabel>
+
+ActivateModsDialog::ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent)
+ : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog)
+{
+ ui->setupUi(this);
+
+ QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
+ QHeaderView *headerView = modsTable->horizontalHeader();
+#if QT_VERSION >= 0x050000
+ headerView->setSectionResizeMode(0, QHeaderView::Stretch);
+ headerView->setSectionResizeMode(1, QHeaderView::Interactive);
+#else
+ headerView->setResizeMode(0, QHeaderView::Stretch);
+ headerView->setResizeMode(1, QHeaderView::Interactive);
+#endif
+
+ int row = 0;
+
+ modsTable->setRowCount(missingPlugins.size());
+
+ for (std::map<QString, std::vector<QString> >::const_iterator espIter = missingPlugins.begin();
+ espIter != missingPlugins.end(); ++espIter, ++row) {
+ modsTable->setCellWidget(row, 0, new QLabel(espIter->first));
+ if (espIter->second.size() == 0) {
+ modsTable->setCellWidget(row, 1, new QLabel(tr("not found")));
+ } else {
+ QComboBox* combo = new QComboBox();
+ for (std::vector<QString>::const_iterator modIter = espIter->second.begin();
+ modIter != espIter->second.end(); ++modIter) {
+ combo->addItem(*modIter);
+ }
+ modsTable->setCellWidget(row, 1, combo);
+ }
+ }
+}
+
+
+ActivateModsDialog::~ActivateModsDialog()
+{
+ delete ui;
+}
+
+
+void ActivateModsDialog::on_buttonBox_accepted()
+{
+}
+
+
+std::set<QString> ActivateModsDialog::getModsToActivate()
+{
+ std::set<QString> result;
+ QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
+
+ for (int row = 0; row < modsTable->rowCount(); ++row) {
+ QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
+ if (comboBox != NULL) {
+ result.insert(comboBox->currentText());
+ }
+ }
+ return result;
+}
+
+
+std::set<QString> ActivateModsDialog::getESPsToActivate()
+{
+ std::set<QString> result;
+ QTableWidget *modsTable = findChild<QTableWidget*>("modsTable");
+
+ for (int row = 0; row < modsTable->rowCount(); ++row) {
+ QComboBox *comboBox = dynamic_cast<QComboBox*>(modsTable->cellWidget(row, 1));
+ if (comboBox != NULL) {
+ QLabel *espName = dynamic_cast<QLabel*>(modsTable->cellWidget(row, 0));
+
+ result.insert(espName->text());
+ }
+ }
+ return result;
+}
diff --git a/src/activatemodsdialog.h b/src/activatemodsdialog.h new file mode 100644 index 00000000..acb01f4e --- /dev/null +++ b/src/activatemodsdialog.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ACTIVATEMODSDIALOG_H
+#define ACTIVATEMODSDIALOG_H
+
+#include "tutorabledialog.h"
+#include <map>
+#include <set>
+
+namespace Ui {
+ class ActivateModsDialog;
+}
+
+/**
+ * @brief Dialog that is used to batch activate/deactivate mods and plugins
+ **/
+class ActivateModsDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief constructor
+ *
+ * @param missingPlugins a map containing missing plugins that need to be activated
+ * @param parent ... Defaults to 0.
+ **/
+ explicit ActivateModsDialog(const std::map<QString, std::vector<QString> > &missingPlugins, QWidget *parent = 0);
+ ~ActivateModsDialog();
+
+ /**
+ * @brief get a list of mods that the user chose to activate
+ *
+ * @note This can of ocurse only be called after the dialog has been displayed
+ *
+ * @return set< QString > the mods to activate
+ **/
+ std::set<QString> getModsToActivate();
+
+ /**
+ * @brief get a list of plugins that should be activated
+ *
+ * @return set< QString > the plugins to activate. This contains only plugins that become available after enabling the mods retrieved with getModsToActivate
+ **/
+ std::set<QString> getESPsToActivate();
+
+private slots:
+ void on_buttonBox_accepted();
+
+private:
+ Ui::ActivateModsDialog *ui;
+};
+
+#endif // ACTIVATEMODSDIALOG_H
diff --git a/src/activatemodsdialog.ui b/src/activatemodsdialog.ui new file mode 100644 index 00000000..f6124bbc --- /dev/null +++ b/src/activatemodsdialog.ui @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ActivateModsDialog</class>
+ <widget class="QDialog" name="ActivateModsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>562</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Activate Mods</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTableWidget" name="modsTable">
+ <property name="toolTip">
+ <string>This is a list of esps and esms that were active when the save game was created.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></string>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Missing ESP</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Mod</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ <property name="centerButtons">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ActivateModsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ActivateModsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/app_icon.rc b/src/app_icon.rc new file mode 100644 index 00000000..2550f49d --- /dev/null +++ b/src/app_icon.rc @@ -0,0 +1,3 @@ +#include "version.rc"
+
+ IDI_ICON1 ICON DISCARDABLE "mo_icon.ico"
diff --git a/src/archivetree.cpp b/src/archivetree.cpp new file mode 100644 index 00000000..0484b241 --- /dev/null +++ b/src/archivetree.cpp @@ -0,0 +1,98 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "archivetree.h"
+#include <QDragMoveEvent>
+
+ArchiveTree::ArchiveTree(QWidget *parent) :
+ QTreeWidget(parent)
+{
+}
+
+
+bool ArchiveTree::testMovePossible(QTreeWidgetItem *source, QTreeWidgetItem *target)
+{
+ if ((target == NULL) ||
+ (source == NULL)) {
+ return false;
+ }
+
+ if ((source == target) ||
+ (source->parent() == target)) {
+ return false;
+ }
+
+ return true;
+}
+
+void ArchiveTree::dragEnterEvent(QDragEnterEvent *event)
+{
+ QTreeWidgetItem *source = this->currentItem();
+ if ((source == NULL) || (source->parent() == NULL)) {
+ // can't change top level
+ event->ignore();
+ return;
+ } else {
+ QTreeWidget::dragEnterEvent(event);
+ }
+
+}
+
+void ArchiveTree::dragMoveEvent(QDragMoveEvent *event)
+{
+ if (!testMovePossible(this->currentItem(), itemAt(event->pos()))) {
+ event->ignore();
+ } else {
+ QTreeWidget::dragMoveEvent(event);
+ }
+}
+
+
+void ArchiveTree::dropEvent(QDropEvent *event)
+{
+ event->ignore();
+
+ QTreeWidgetItem *target = itemAt(event->pos());
+
+ QList<QTreeWidgetItem*> sourceItems = this->selectedItems();
+ for (QList<QTreeWidgetItem*>::iterator iter = sourceItems.begin();
+ iter != sourceItems.end(); ++iter) {
+ QTreeWidgetItem *source = *iter;
+ if ((source->parent() != NULL) && + testMovePossible(source, target)) { + source->parent()->removeChild(source); + if (target->data(0, Qt::UserRole).toInt() != 0) { + // target is a file + if (target->parent() == NULL) { + // this should really not happen, how should a + // file get to the top level?
+ return;
+ }
+ int index = target->parent()->indexOfChild(target);
+ target->parent()->insertChild(index, source);
+ emit changed();
+ } else {
+ // target is a directory
+ target->insertChild(target->childCount(), source);
+ emit changed();
+ }
+ }
+ }
+
+}
diff --git a/src/archivetree.h b/src/archivetree.h new file mode 100644 index 00000000..775bf8b9 --- /dev/null +++ b/src/archivetree.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ARCHIVETREE_H
+#define ARCHIVETREE_H
+
+#include <QTreeWidget>
+
+/**
+ * @brief QT tree widget used to display the content of an archive in the manual installation dialog
+ **/
+class ArchiveTree : public QTreeWidget
+{
+
+ Q_OBJECT
+
+public:
+
+ explicit ArchiveTree(QWidget *parent = 0);
+
+signals:
+
+ void changed();
+
+public slots:
+
+protected:
+
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dragMoveEvent(QDragMoveEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+
+private:
+
+ bool testMovePossible(QTreeWidgetItem *source, QTreeWidgetItem *target);
+
+};
+
+#endif // ARCHIVETREE_H
diff --git a/src/baincomplexinstallerdialog.cpp b/src/baincomplexinstallerdialog.cpp new file mode 100644 index 00000000..c21fa5ad --- /dev/null +++ b/src/baincomplexinstallerdialog.cpp @@ -0,0 +1,120 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "baincomplexinstallerdialog.h"
+#include "textviewer.h"
+#include "ui_baincomplexinstallerdialog.h"
+
+#include <QDir>
+
+BainComplexInstallerDialog::BainComplexInstallerDialog(DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent)
+ : TutorableDialog("BainInstaller", parent), ui(new Ui::BainComplexInstallerDialog), m_Manual(false)
+{
+ ui->setupUi(this);
+
+ ui->nameEdit->setText(modName);
+
+ for (DirectoryTree::const_node_iterator iter = tree->nodesBegin(); iter != tree->nodesEnd(); ++iter) {
+ const QString &dirName = (*iter)->getData().name;
+ if ((dirName.compare("fomod", Qt::CaseInsensitive) == 0) ||
+ (dirName.startsWith("--"))) {
+ continue;
+ }
+
+ QListWidgetItem *item = new QListWidgetItem(ui->optionsList);
+ item->setText((*iter)->getData().name);
+ item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+ item->setCheckState(item->text().mid(0, 2) == "00" ? Qt::Checked : Qt::Unchecked);
+ item->setData(Qt::UserRole, qVariantFromValue((void*)(*iter)));
+ ui->optionsList->addItem(item);
+ }
+
+ ui->packageBtn->setEnabled(hasPackageTXT);
+}
+
+
+BainComplexInstallerDialog::~BainComplexInstallerDialog()
+{
+ delete ui;
+}
+
+
+QString BainComplexInstallerDialog::getName() const
+{
+ return ui->nameEdit->text();
+}
+
+
+void BainComplexInstallerDialog::moveTreeUp(DirectoryTree *target, DirectoryTree::Node *child)
+{
+ for (DirectoryTree::const_node_iterator iter = child->nodesBegin();
+ iter != child->nodesEnd();) {
+ target->addNode(*iter, true);
+ iter = child->detach(iter);
+ }
+
+ for (DirectoryTree::const_leaf_reverse_iterator iter = child->leafsRBegin();
+ iter != child->leafsREnd(); ++iter) {
+ target->addLeaf(*iter);
+ }
+}
+
+
+DirectoryTree *BainComplexInstallerDialog::updateTree(DirectoryTree *tree)
+{
+ DirectoryTree *newTree = new DirectoryTree;
+
+ for (DirectoryTree::const_node_reverse_iterator iter = tree->nodesRBegin();
+ iter != tree->nodesREnd();) {
+ QList<QListWidgetItem*> items = ui->optionsList->findItems((*iter)->getData().name, Qt::MatchFixedString);
+ if ((items.count() == 1) && (items.at(0)->checkState() == Qt::Checked)) {
+ moveTreeUp(newTree, *iter);
+ }
+ iter = tree->erase(iter);
+ }
+
+ return newTree;
+}
+
+
+void BainComplexInstallerDialog::on_okBtn_clicked()
+{
+ this->accept();
+}
+
+
+void BainComplexInstallerDialog::on_cancelBtn_clicked()
+{
+ this->reject();
+}
+
+
+void BainComplexInstallerDialog::on_manualBtn_clicked()
+{
+ m_Manual = true;
+ this->reject();
+}
+
+void BainComplexInstallerDialog::on_packageBtn_clicked()
+{
+ TextViewer viewer(this);
+ viewer.setDescription("");
+ viewer.addFile(QDir::tempPath().append("/package.txt"), false);
+ viewer.exec();
+}
diff --git a/src/baincomplexinstallerdialog.h b/src/baincomplexinstallerdialog.h new file mode 100644 index 00000000..c2f74745 --- /dev/null +++ b/src/baincomplexinstallerdialog.h @@ -0,0 +1,95 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef BAINCOMPLEXINSTALLERDIALOG_H
+#define BAINCOMPLEXINSTALLERDIALOG_H
+
+
+#include "mytree.h"
+#include "installdialog.h"
+#include "tutorabledialog.h"
+
+
+namespace Ui {
+class BainComplexInstallerDialog;
+}
+
+
+/**
+ * @brief Dialog to choose from options offered by a (complex) bain package
+ **/
+class BainComplexInstallerDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief Constructor
+ *
+ * @param tree the directory tree of the archive. The caller is resonsible to verify this actually qualifies as a bain installer
+ * @param modName proposed name for the mod. The dialog allows the user to change this
+ * @param hasPackageTXT set to true if a package.txt is available for this archive. The file has to be unpacked to QDir::tempPath before displaying the dialog!
+ * @param parent parent widget
+ **/
+ explicit BainComplexInstallerDialog(DirectoryTree *tree, const QString &modName, bool hasPackageTXT, QWidget *parent);
+ ~BainComplexInstallerDialog();
+
+ /**
+ * @return bool true if the user requested the manual dialog
+ **/
+ bool manualRequested() const { return m_Manual; }
+
+ /**
+ * @return QString the (user-modified) name to be used for the mod
+ **/
+ QString getName() const;
+
+ /**
+ * @brief retrieve the updated archive tree from the dialog. The caller is responsible to delete the returned tree.
+ *
+ * @note This call is destructive on the input tree!
+ *
+ * @param tree input tree. (TODO isn't this the same as the tree passed in the constructor?)
+ * @return DataTree* a new tree with only the selected options and directories arranged correctly. The caller takes custody of this pointer!
+ **/
+ DirectoryTree *updateTree(DirectoryTree *tree);
+
+private slots:
+
+ void on_manualBtn_clicked();
+
+ void on_okBtn_clicked();
+
+ void on_cancelBtn_clicked();
+
+ void on_packageBtn_clicked();
+
+private:
+
+ void moveTreeUp(DirectoryTree *target, DirectoryTree::Node *child);
+
+private:
+
+ Ui::BainComplexInstallerDialog *ui;
+
+ bool m_Manual;
+
+};
+
+#endif // BAINCOMPLEXINSTALLERDIALOG_H
diff --git a/src/baincomplexinstallerdialog.ui b/src/baincomplexinstallerdialog.ui new file mode 100644 index 00000000..d290aa58 --- /dev/null +++ b/src/baincomplexinstallerdialog.ui @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BainComplexInstallerDialog</class>
+ <widget class="QDialog" name="BainComplexInstallerDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>365</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>BAIN Package Installer</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="optionsList">
+ <property name="toolTip">
+ <string>Components of this package.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Components of this package.
+If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="packageBtn">
+ <property name="toolTip">
+ <string>The package.txt is often part of BAIN packages and contains details about the options available.</string>
+ </property>
+ <property name="whatsThis">
+ <string>The package.txt is often part of BAIN packages and contains details about the options available.</string>
+ </property>
+ <property name="text">
+ <string>Package.txt</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="manualBtn">
+ <property name="toolTip">
+ <string>Opens a Dialog that allows custom modifications.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Opens a Dialog that allows custom modifications.</string>
+ </property>
+ <property name="text">
+ <string>Manual</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okBtn">
+ <property name="text">
+ <string>Ok</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/bbcode.cpp b/src/bbcode.cpp new file mode 100644 index 00000000..5f134d78 --- /dev/null +++ b/src/bbcode.cpp @@ -0,0 +1,209 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "bbcode.h"
+
+#include <QRegExp>
+#include <map>
+#include <algorithm>
+
+
+namespace BBCode {
+
+
+class BBCodeMap {
+
+ typedef std::map<QString, std::pair<QRegExp, QString> > TagMap;
+
+public:
+
+ static BBCodeMap &instance() {
+ static BBCodeMap s_Instance;
+ return s_Instance;
+ }
+
+ QString convertTag(const QString &input, int &length)
+ {
+ // extract the tag name
+ m_TagNameExp.indexIn(input, 1, QRegExp::CaretAtOffset);
+ QString tagName = m_TagNameExp.cap(0).toLower();
+ //qDebug("tag name %s", tagName.toUtf8().constData());
+ TagMap::iterator tagIter = m_TagMap.find(tagName);
+ if (tagIter != m_TagMap.end()) {
+ // recognized tag
+ if (tagName.endsWith('=')) {
+ tagName.chop(1);
+ }
+ QString closeTag = tagName == "*" ? "<br/>"
+ : QString("[/%1]").arg(tagName);
+
+ int closeTagPos = input.indexOf(closeTag, 0, Qt::CaseInsensitive);
+ //qDebug("close tag %s at %d", closeTag.toUtf8().constData(), closeTagPos);
+
+ if (closeTagPos > -1) {
+ length = closeTagPos + closeTag.length();
+ QString temp = input.mid(0, length);
+ if (tagIter->second.first.indexIn(temp) == 0) {
+ return temp.replace(tagIter->second.first, tagIter->second.second);
+ } else {
+ // expression doesn't match. either the input string is invalid
+ // or the expression is
+ qWarning("%s doesn't match the expression for %s",
+ temp.toUtf8().constData(), tagName.toUtf8().constData());
+ length = 0;
+ return QString();
+ }
+ }
+ }
+
+ // not a recognized tag or tag invalid
+ length = 0;
+ return QString();
+ }
+
+private:
+ BBCodeMap()
+ : m_TagNameExp("^[a-zA-Z*]*=?")
+ {
+ m_TagMap["b"] = std::make_pair(QRegExp("\\[b\\](.*)\\[/b\\]"),
+ "<b>\\1</b>");
+ m_TagMap["i"] = std::make_pair(QRegExp("\\[i\\](.*)\\[/i\\]"),
+ "<i>\\1</i>");
+ m_TagMap["u"] = std::make_pair(QRegExp("\\[u\\](.*)\\[/u\\]"),
+ "<u>\\1</u>");
+ m_TagMap["s"] = std::make_pair(QRegExp("\\[s\\](.*)\\[/s\\]"),
+ "<s>\\1</s>");
+ m_TagMap["sub"] = std::make_pair(QRegExp("\\[sub\\](.*)\\[/sub\\]"),
+ "<sub>\\1</sub>");
+ m_TagMap["sup"] = std::make_pair(QRegExp("\\[sup\\](.*)\\[/sup\\]"),
+ "<sup>\\1</sup>");
+ m_TagMap["size="] = std::make_pair(QRegExp("\\[size=([^\\]]*)\\](.*)\\[/size\\]"),
+ "<font size=\"\\1\">\\2</font>");
+ m_TagMap["color="] = std::make_pair(QRegExp("\\[color=([^\\]]*)\\](.*)\\[/color\\]"),
+ "<font style=\"color: #\\1;\">\\2</font>");
+ m_TagMap["font="] = std::make_pair(QRegExp("\\[font=([^\\]]*)\\](.*)\\[/font\\]"),
+ "<font face=\\1>\\2</font>");
+ m_TagMap["center"] = std::make_pair(QRegExp("\\[center\\](.*)\\[/center\\]"),
+ "<div align=\"center\">\\1</div>");
+ m_TagMap["quote"] = std::make_pair(QRegExp("\\[quote\\](.*)\\[/quote\\]"),
+ "<blockquote>\"\\1\"</blockquote>");
+ m_TagMap["quote="] = std::make_pair(QRegExp("\\[quote=([^\\]]*)\\](.*)\\[/quote\\]"),
+ "<blockquote>\"\\2\"<br/><span>--\\1</span></blockquote></p>");
+ m_TagMap["code"] = std::make_pair(QRegExp("\\[code\\](.*)\\[/code\\]"),
+ "<pre>\\1</pre>");
+ m_TagMap["heading"]= std::make_pair(QRegExp("\\[heading\\](.*)\\[/heading\\]"),
+ "<h2><strong>\\1</strong></h2>");
+
+ // lists
+ m_TagMap["list"] = std::make_pair(QRegExp("\\[list\\](.*)\\[/list\\]"),
+ "<ul>\\1</ul>");
+ m_TagMap["list="] = std::make_pair(QRegExp("\\[list.*\\](.*)\\[/list\\]"),
+ "<ol>\\1</ol>");
+ m_TagMap["ul"] = std::make_pair(QRegExp("\\[ul\\](.*)\\[/ul\\]"),
+ "<ul>\\1</ul>");
+ m_TagMap["ol"] = std::make_pair(QRegExp("\\[ol\\](.*)\\[/ol\\]"),
+ "<ol>\\1</ol>");
+ m_TagMap["li"] = std::make_pair(QRegExp("\\[li\\](.*)\\[/li\\]"),
+ "<li>\\1</li>");
+ m_TagMap["*"] = std::make_pair(QRegExp("\\[\\*\\](.*)<br/>"),
+ "<li>\\1</li>");
+
+ // tables
+ m_TagMap["table"] = std::make_pair(QRegExp("\\[table\\](.*)\\[/table\\]"),
+ "<table>\\1</table>");
+ m_TagMap["tr"] = std::make_pair(QRegExp("\\[tr\\](.*)\\[/tr\\]"),
+ "<tr>\\1</tr>");
+ m_TagMap["th"] = std::make_pair(QRegExp("\\[th\\](.*)\\[/th\\]"),
+ "<th>\\1</th>");
+ m_TagMap["td"] = std::make_pair(QRegExp("\\[td\\](.*)\\[/td\\]"),
+ "<td>\\1</td>");
+
+ // web content
+ m_TagMap["url"] = std::make_pair(QRegExp("\\[url\\](.*)\\[/url\\]"),
+ "<a href=\"\\1\">\\1</a>");
+ m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
+ "<a href=\"\\1\">\\2</a>");
+ m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"),
+ "<img src=\"\\1\"/>");
+ m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"),
+ "<img src=\"\\2\" align=\"\\1\" />");
+ m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
+ "<a href=\"mailto:\\1\">\\2</a>");
+ m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
+ "<a href=\"http://www.youtube.com/v/\\1\">http://www.youtube.com/v/\\1</a>");
+
+ // make all patterns non-greedy and case-insensitive
+ for (TagMap::iterator iter = m_TagMap.begin(); iter != m_TagMap.end(); ++iter) {
+ iter->second.first.setCaseSensitivity(Qt::CaseInsensitive);
+ iter->second.first.setMinimal(true);
+ }
+ }
+
+
+private:
+ QRegExp m_TagNameExp;
+ TagMap m_TagMap;
+};
+
+
+QString convertToHTML(const QString &inputParam)
+{
+ // this code goes over the input string once and replaces all bbtags
+ // it encounters. This function is called recursively for every replaced
+ // string to convert nested tags.
+ //
+ // This could be implemented simpler by applying a set of regular expressions
+ // for each recognized bb-tag one after the other but that would probably be
+ // very inefficient (O(n^2)).
+
+ QString input = inputParam.mid(0).replace("\r\n", "<br/>");
+ input.replace("\\\"", "\"").replace("\\'", "'");
+
+ QString result;
+ int lastBlock = 0;
+ int pos = 0;
+
+ // iterate over the input buffer
+ while ((pos = input.indexOf('[', lastBlock)) != -1) {
+ // append everything between the previous tag-block and the current one
+ result.append(input.midRef(lastBlock, pos - lastBlock));
+
+ // convert the tag and content if necessary
+ int length = -1;
+ QString replacement = BBCodeMap::instance().convertTag(input.mid(pos), length);
+ if (length != 0) {
+ QString temp = convertToHTML(replacement);
+ result.append(temp);
+ // length contains the number of characters in the original tag
+ pos += length;
+ } else {
+ // nothing replaced
+ result.append('[');
+ ++pos;
+ }
+ lastBlock = pos;
+ }
+
+ // append the remainder (everything after the last tag)
+ result.append(input.midRef(lastBlock));
+ return result;
+}
+
+} // namespace BBCode
+
diff --git a/src/bbcode.h b/src/bbcode.h new file mode 100644 index 00000000..eec8e657 --- /dev/null +++ b/src/bbcode.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef BBCODE_H
+#define BBCODE_H
+
+
+#include <QString>
+
+
+namespace BBCode {
+
+/**
+ * @brief convert a string with BB Code-Tags to HTML
+ * @param input the input string with BB tags
+ * @param replaceOccured if not NULL, this parameter will be set to true if any bb tags were replaced
+ * @return the same string in html representation
+ **/
+QString convertToHTML(const QString &input);
+
+}
+
+
+#endif // BBCODE_H
diff --git a/src/categories.cpp b/src/categories.cpp new file mode 100644 index 00000000..133778c4 --- /dev/null +++ b/src/categories.cpp @@ -0,0 +1,270 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "categories.h"
+#include <utility.h>
+#include "report.h"
+#include <gameinfo.h>
+#include <QObject>
+#include <QFile>
+#include <QDir>
+#include <QList>
+
+
+CategoryFactory* CategoryFactory::s_Instance = NULL;
+
+
+CategoryFactory::CategoryFactory()
+{
+ reset();
+
+ QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
+
+ if (!categoryFile.open(QIODevice::ReadOnly)) {
+ loadDefaultCategories();
+ } else {
+ int lineNum = 0;
+ while (!categoryFile.atEnd()) {
+ QByteArray line = categoryFile.readLine();
+ ++lineNum;
+ QList<QByteArray> cells = line.split('|');
+ if (cells.count() != 4) {
+ qCritical("invalid category line %d: %s (%d cells)",
+ lineNum, line.constData(), cells.count());
+ } else {
+ std::vector<int> nexusIDs;
+ if (cells[2].length() > 0) {
+ QList<QByteArray> nexusIDStrings = cells[2].split(',');
+ for (QList<QByteArray>::iterator iter = nexusIDStrings.begin();
+ iter != nexusIDStrings.end(); ++iter) {
+ bool ok = false;
+ int temp = iter->toInt(&ok);
+ if (!ok) {
+ qCritical("invalid id %s", iter->constData());
+ }
+ nexusIDs.push_back(temp);
+ }
+ }
+ bool cell0Ok = true;
+ bool cell3Ok = true;
+ int id = cells[0].toInt(&cell0Ok);
+ int parentID = cells[3].trimmed().toInt(&cell3Ok);
+ if (!cell0Ok || !cell3Ok) {
+ qCritical("invalid category line %d: %s",
+ lineNum, line.constData());
+ }
+ addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID);
+ }
+ }
+ categoryFile.close();
+ }
+ std::sort(m_Categories.begin(), m_Categories.end());
+ setParents();
+}
+
+
+CategoryFactory &CategoryFactory::instance()
+{
+ if (s_Instance == NULL) {
+ s_Instance = new CategoryFactory;
+ }
+ return *s_Instance;
+}
+
+
+void CategoryFactory::reset()
+{
+ m_Categories.clear();
+ addCategory(0, "None", MakeVector<int>(2, 28, 87), 0);
+}
+
+
+void CategoryFactory::setParents()
+{
+ for (std::vector<Category>::iterator iter = m_Categories.begin();
+ iter != m_Categories.end(); ++iter) {
+ iter->m_HasChildren = false;
+ }
+
+ for (std::vector<Category>::const_iterator categoryIter = m_Categories.begin();
+ categoryIter != m_Categories.end(); ++categoryIter) {
+ if (categoryIter->m_ParentID != 0) {
+ std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(categoryIter->m_ParentID);
+ if (iter != m_IDMap.end()) {
+ m_Categories[iter->second].m_HasChildren = true;
+ }
+ }
+ }
+}
+
+
+void CategoryFactory::saveCategories()
+{
+ QFile categoryFile(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/categories.dat"));
+
+ if (!categoryFile.open(QIODevice::WriteOnly)) {
+ reportError(QObject::tr("Failed to save custom categories"));
+ return;
+ }
+
+ categoryFile.resize(0);
+ for (std::vector<Category>::const_iterator iter = m_Categories.begin();
+ iter != m_Categories.end(); ++iter) {
+ if (iter->m_ID == 0) {
+ continue;
+ }
+ QByteArray line;
+ line.append(QByteArray::number(iter->m_ID)).append("|")
+ .append(iter->m_Name.toUtf8()).append("|")
+ .append(VectorJoin(iter->m_NexusIDs, ",")).append("|")
+ .append(QByteArray::number(iter->m_ParentID)).append("\n");
+ categoryFile.write(line);
+ }
+ categoryFile.close();
+}
+
+
+void CategoryFactory::addCategory(int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
+{
+ int index = m_Categories.size();
+ m_Categories.push_back(Category(index, id, name, nexusIDs, parentID));
+ for (std::vector<int>::const_iterator iter = nexusIDs.begin();
+ iter != nexusIDs.end(); ++iter) {
+ m_NexusMap[*iter] = index;
+ }
+ m_IDMap[id] = index;
+}
+
+
+void CategoryFactory::loadDefaultCategories()
+{
+ // the order here is relevant as it defines the order in which the
+ // mods appear in the combo box
+ addCategory(1, "Animations", MakeVector<int>(1, 51), 0);
+ addCategory(2, "Armour", MakeVector<int>(1, 54), 0);
+ addCategory(3, "Audio", MakeVector<int>(1, 61), 0);
+ addCategory(5, "Clothing", MakeVector<int>(1, 60), 0);
+ addCategory(6, "Collectables", MakeVector<int>(1, 92), 0);
+ addCategory(7, "Creatures", MakeVector<int>(2, 83, 65), 0);
+ addCategory(8, "Factions", MakeVector<int>(1, 25), 0);
+ addCategory(9, "Gameplay", MakeVector<int>(1, 24), 0);
+ addCategory(10, "Hair", MakeVector<int>(1, 26), 0);
+ addCategory(11, "Items", MakeVector<int>(2, 27, 85), 0);
+ addCategory(19, "Weapons", MakeVector<int>(2, 36, 55), 11);
+ addCategory(12, "Locations", MakeVector<int>(7, 22, 30, 70, 88, 89, 90, 91), 0);
+ addCategory(4, "Cities", MakeVector<int>(1, 53), 12);
+ addCategory(20, "Magic", MakeVector<int>(3, 75, 93, 94), 0);
+ addCategory(21, "Models & Textures", MakeVector<int>(1, 29), 0);
+ addCategory(13, "NPCs", MakeVector<int>(1, 33), 0);
+ addCategory(14, "Patches", MakeVector<int>(2, 79, 84), 0);
+ addCategory(15, "Quests", MakeVector<int>(1, 35), 0);
+ addCategory(16, "Races & Classes", MakeVector<int>(1, 34), 0);
+ addCategory(22, "Skills", MakeVector<int>(1, 73), 0);
+ addCategory(17, "UI", MakeVector<int>(1, 42), 0);
+ addCategory(18, "Visuals", MakeVector<int>(1, 62), 0);
+}
+
+
+int CategoryFactory::getParentID(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_ParentID;
+}
+
+
+bool CategoryFactory::categoryExists(int id) const
+{
+ return m_IDMap.find(id) != m_IDMap.end();
+}
+
+
+bool CategoryFactory::isDecendantOf(int id, int parentID) const
+{
+ std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(id);
+ if (iter != m_IDMap.end()) {
+ unsigned int index = iter->second;
+ if (m_Categories[index].m_ParentID == 0) {
+ return false;
+ } else if (m_Categories[index].m_ParentID == parentID) {
+ return true;
+ } else {
+ return isDecendantOf(m_Categories[index].m_ParentID, parentID);
+ }
+ } else {
+ qWarning("%d is no valid category id", id);
+ return false;
+ }
+}
+
+
+bool CategoryFactory::hasChildren(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_HasChildren;
+}
+
+
+QString CategoryFactory::getCategoryName(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_Name;
+}
+
+
+int CategoryFactory::getCategoryID(unsigned int index) const
+{
+ if ((index < 0) || (index >= m_Categories.size())) {
+ throw MyException(QObject::tr("invalid index %1").arg(index));
+ }
+
+ return m_Categories[index].m_ID;
+}
+
+
+int CategoryFactory::getCategoryIndex(int ID) const
+{
+ std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(ID);
+ if (iter == m_IDMap.end()) {
+ throw MyException(QObject::tr("invalid category id %1").arg(ID));
+ }
+ return iter->second;
+}
+
+
+
+unsigned int CategoryFactory::resolveNexusID(int nexusID) const
+{
+ std::map<int, unsigned int>::const_iterator iter = m_NexusMap.find(nexusID);
+ if (iter != m_NexusMap.end()) {
+ qDebug("nexus category id %d maps to internal %d", nexusID, iter->second);
+ return iter->second;
+ } else {
+ qDebug("nexus category id %d not mapped", nexusID);
+ return 0U;
+ }
+}
diff --git a/src/categories.h b/src/categories.h new file mode 100644 index 00000000..e6978259 --- /dev/null +++ b/src/categories.h @@ -0,0 +1,180 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CATEGORIES_H
+#define CATEGORIES_H
+
+
+#include <QString>
+#include <vector>
+#include <map>
+
+
+/**
+ * @brief Manage the available mod categories
+ * @warning member functions of this class currently use a wild mix of ids and indexes to look up categories,
+ * optimized to where the request comes from. Therefore be very careful which of the two you have available
+ **/
+class CategoryFactory {
+
+ friend class CategoriesDialog;
+
+public:
+
+ static const int CATEGORY_NONE = 0;
+
+ static const int CATEGORY_SPECIAL_FIRST = 10000;
+ static const int CATEGORY_SPECIAL_CHECKED = CATEGORY_SPECIAL_FIRST;
+ static const int CATEGORY_SPECIAL_UNCHECKED = 10001;
+ static const int CATEGORY_SPECIAL_UPDATEAVAILABLE = 10002;
+ static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
+ static const int CATEGORY_SPECIAL_CONFLICT = 10004;
+
+public:
+
+ /**
+ * @brief reset the list of categories
+ **/
+ void reset();
+
+ /**
+ * @brief save the categories to the categories.dat file
+ **/
+ void saveCategories();
+
+ /**
+ * @brief retrieve the number of available categories
+ *
+ * @return unsigned int number of categories
+ **/
+ unsigned numCategories() const { return m_Categories.size(); }
+
+ /**
+ * @brief get the id of the parent category
+ *
+ * @param index the index to look up
+ * @return int id of the parent category
+ **/
+ int getParentID(unsigned int index) const;
+
+ /**
+ * @brief determine if a category exists (by id)
+ *
+ * @param id the id to check for existance
+ * @return true if the category exists, false otherwise
+ **/
+ bool categoryExists(int id) const;
+
+ /**
+ * @brief test if a category is child of a second one
+ * @param id the presumed child id
+ * @param parentID the parent id to test for
+ * @return true if id is a child of parentID
+ **/
+ bool isDecendantOf(int id, int parentID) const;
+
+ /**
+ * @brief test if the specified category has child categories
+ *
+ * @param index index of the category to look up
+ * @return bool true if the category has child categories
+ **/
+ bool hasChildren(unsigned int index) const;
+
+ /**
+ * @brief retrieve the name of a category
+ *
+ * @param index index of the category to look up
+ * @return QString name of the category
+ **/
+ QString getCategoryName(unsigned int index) const;
+
+ /**
+ * @brief look up the id of a category by its index
+ *
+ * @param index index of the category to look up
+ * @return int id of the category
+ **/
+ int getCategoryID(unsigned int index) const;
+
+ /**
+ * @brief look up the index of a category by its id
+ *
+ * @param id index of the category to look up
+ * @return unsigned int index of the category
+ **/
+ int getCategoryIndex(int ID) const;
+
+ /**
+ * @brief retrieve the index of a category by its nexus id
+ *
+ * @param nexusID nexus id of the category to look up
+ * @return unsigned int index of the category or 0 if no category matches
+ **/
+ unsigned int resolveNexusID(int nexusID) const;
+
+public:
+
+ /**
+ * @brief retrieve a reference to the singleton instance
+ *
+ * @return the reference to the singleton
+ **/
+ static CategoryFactory &instance();
+
+private:
+
+ struct Category {
+ Category(int sortValue, int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
+ : m_SortValue(sortValue), m_ID(id), m_Name(name), m_HasChildren(false),
+ m_NexusIDs(nexusIDs), m_ParentID(parentID) {}
+ int m_SortValue;
+ int m_ID;
+ int m_ParentID;
+ bool m_HasChildren;
+ QString m_Name;
+ std::vector<int> m_NexusIDs;
+
+ friend bool operator<(const Category &LHS, const Category &RHS) {
+ return LHS.m_SortValue < RHS.m_SortValue;
+ }
+ };
+
+private:
+
+ CategoryFactory();
+
+ void loadDefaultCategories();
+
+ void addCategory(int id, const QString &name, const std::vector<int> &nexusID, int parentID);
+
+ void setParents();
+
+private:
+
+ static CategoryFactory *s_Instance;
+
+ std::vector<Category> m_Categories;
+ std::map<int, unsigned int> m_IDMap;
+ std::map<int, unsigned int> m_NexusMap;
+
+};
+
+
+#endif // CATEGORIES_H
diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp new file mode 100644 index 00000000..8a634dd8 --- /dev/null +++ b/src/categoriesdialog.cpp @@ -0,0 +1,242 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "categoriesdialog.h"
+#include "ui_categoriesdialog.h"
+#include "categories.h"
+#include "utility.h"
+#include <QItemDelegate>
+#include <QRegExpValidator>
+#include <QLineEdit>
+#include <QMenu>
+
+
+class NewIDValidator : public QIntValidator {
+public:
+ NewIDValidator(const std::set<int> &ids)
+ : m_UsedIDs(ids) {}
+ virtual State validate(QString &input, int &pos) const {
+ State intRes = QIntValidator::validate(input, pos);
+ if (intRes == Acceptable) {
+ bool ok = false;
+ int id = input.toInt(&ok);
+ if (m_UsedIDs.find(id) != m_UsedIDs.end()) {
+ return QValidator::Intermediate;
+ }
+ }
+ return intRes;
+ }
+private:
+ const std::set<int> &m_UsedIDs;
+};
+
+
+class ExistingIDValidator : public QIntValidator {
+public:
+ ExistingIDValidator(const std::set<int> &ids)
+ : m_UsedIDs(ids) {}
+ virtual State validate(QString &input, int &pos) const {
+ State intRes = QIntValidator::validate(input, pos);
+ if (intRes == Acceptable) {
+ bool ok = false;
+ int id = input.toInt(&ok);
+ if ((id == 0) || (m_UsedIDs.find(id) != m_UsedIDs.end())) {
+ return QValidator::Acceptable;
+ } else {
+ return QValidator::Intermediate;
+ }
+ } else {
+ return intRes;
+ }
+ }
+private:
+ const std::set<int> &m_UsedIDs;
+};
+
+
+class ValidatingDelegate : public QItemDelegate {
+
+public:
+ ValidatingDelegate(QObject *parent, QValidator *validator)
+ : QItemDelegate(parent), m_Validator(validator) {}
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const
+ {
+ QLineEdit *edit = new QLineEdit(parent);
+ edit->setValidator(m_Validator);
+ return edit;
+ }
+ virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
+ {
+ QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
+ int pos = 0;
+ if (m_Validator->validate(edit->text(), pos) == QValidator::Acceptable) {
+ QItemDelegate::setModelData(editor, model, index);
+ }
+ }
+private:
+ QValidator *m_Validator;
+};
+
+
+CategoriesDialog::CategoriesDialog(QWidget *parent)
+ : TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog)
+{
+ ui->setupUi(this);
+ fillTable();
+ connect(ui->categoriesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int,int)));
+}
+
+CategoriesDialog::~CategoriesDialog()
+{
+ delete ui;
+}
+
+
+void CategoriesDialog::cellChanged(int row, int)
+{
+ int currentID = ui->categoriesTable->item(row, 0)->text().toInt();
+ if (currentID > m_HighestID) {
+ m_HighestID = currentID;
+ }
+}
+
+
+void CategoriesDialog::commitChanges()
+{
+ CategoryFactory &categories = CategoryFactory::instance();
+ categories.reset();
+
+ for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
+ int index = ui->categoriesTable->verticalHeader()->logicalIndex(i);
+ QString nexusIDString = ui->categoriesTable->item(index, 2)->text();
+ QStringList nexusIDStringList = nexusIDString.split(',', QString::SkipEmptyParts);
+ std::vector<int> nexusIDs;
+ for (QStringList::iterator iter = nexusIDStringList.begin();
+ iter != nexusIDStringList.end(); ++iter) {
+ nexusIDs.push_back(iter->toInt());
+ }
+
+ categories.addCategory(
+ ui->categoriesTable->item(index, 0)->text().toInt(),
+ ui->categoriesTable->item(index, 1)->text(),
+ nexusIDs,
+ ui->categoriesTable->item(index, 3)->text().toInt());
+ }
+ categories.setParents();
+
+ categories.saveCategories();
+}
+
+
+void CategoriesDialog::refreshIDs()
+{
+ m_HighestID = 0;
+ for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) {
+ int id = ui->categoriesTable->item(i, 0)->text().toInt();
+ if (id > m_HighestID) {
+ m_HighestID = id;
+ }
+ m_IDs.insert(id);
+ }
+}
+
+
+void CategoriesDialog::fillTable()
+{
+ CategoryFactory &categories = CategoryFactory::instance();
+ QTableWidget *table = ui->categoriesTable;
+
+#if QT_VERSION >= 0x050000
+ table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
+ table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
+ table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
+ table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
+ table->verticalHeader()->setSectionsMovable(true);
+ table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
+#else
+ table->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
+ table->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
+ table->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
+ table->horizontalHeader()->setResizeMode(3, QHeaderView::Fixed);
+ table->verticalHeader()->setMovable(true);
+ table->verticalHeader()->setResizeMode(QHeaderView::Fixed);
+#endif
+
+
+ table->setItemDelegateForColumn(0, new ValidatingDelegate(this, new NewIDValidator(m_IDs)));
+ table->setItemDelegateForColumn(2, new ValidatingDelegate(this, new QRegExpValidator(QRegExp("([0-9]+)?(,[0-9]+)*"), this)));
+ table->setItemDelegateForColumn(3, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs)));
+
+ int row = 0;
+ for (std::vector<CategoryFactory::Category>::const_iterator iter = categories.m_Categories.begin();
+ iter != categories.m_Categories.end(); ++iter, ++row) {
+ const CategoryFactory::Category &category = *iter;
+ if (category.m_ID == 0) {
+ --row;
+ continue;
+ }
+ table->insertRow(row);
+// table->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
+
+ QScopedPointer<QTableWidgetItem> idItem(new QTableWidgetItem());
+ idItem->setData(Qt::DisplayRole, category.m_ID);
+
+ QScopedPointer<QTableWidgetItem> nameItem(new QTableWidgetItem(category.m_Name));
+ QScopedPointer<QTableWidgetItem> nexusIDItem(new QTableWidgetItem(VectorJoin(category.m_NexusIDs, ",")));
+ QScopedPointer<QTableWidgetItem> parentIDItem(new QTableWidgetItem());
+ parentIDItem->setData(Qt::DisplayRole, category.m_ParentID);
+
+ table->setItem(row, 0, idItem.take());
+ table->setItem(row, 1, nameItem.take());
+ table->setItem(row, 2, nexusIDItem.take());
+ table->setItem(row, 3, parentIDItem.take());
+ }
+
+ refreshIDs();
+}
+
+
+void CategoriesDialog::addCategory_clicked()
+{
+ int row = m_ContextRow >= 0 ? m_ContextRow : 0;
+ ui->categoriesTable->insertRow(row);
+ ui->categoriesTable->setVerticalHeaderItem(row, new QTableWidgetItem(" "));
+ ui->categoriesTable->setItem(row, 0, new QTableWidgetItem(QString::number(++m_HighestID)));
+ ui->categoriesTable->setItem(row, 1, new QTableWidgetItem("new"));
+ ui->categoriesTable->setItem(row, 2, new QTableWidgetItem(""));
+ ui->categoriesTable->setItem(row, 3, new QTableWidgetItem("0"));
+}
+
+
+void CategoriesDialog::removeCategory_clicked()
+{
+ ui->categoriesTable->removeRow(m_ContextRow);
+}
+
+
+void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint &pos)
+{
+ m_ContextRow = ui->categoriesTable->rowAt(pos.y());
+ QMenu menu;
+ menu.addAction(tr("Add"), this, SLOT(addCategory_clicked()));
+ menu.addAction(tr("Remove"), this, SLOT(removeCategory_clicked()));
+
+ menu.exec(ui->categoriesTable->mapToGlobal(pos));
+}
diff --git a/src/categoriesdialog.h b/src/categoriesdialog.h new file mode 100644 index 00000000..34007e77 --- /dev/null +++ b/src/categoriesdialog.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CATEGORIESDIALOG_H
+#define CATEGORIESDIALOG_H
+
+#include "tutorabledialog.h"
+#include <set>
+
+namespace Ui {
+class CategoriesDialog;
+}
+
+/**
+ * @brief Dialog that allows users to configure mod categories
+ **/
+class CategoriesDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+
+ explicit CategoriesDialog(QWidget *parent = 0);
+ ~CategoriesDialog();
+
+ /**
+ * @brief store changes here to the global categories store (categories.h)
+ *
+ **/
+ void commitChanges();
+
+private slots:
+
+ void on_categoriesTable_customContextMenuRequested(const QPoint &pos);
+ void addCategory_clicked();
+ void removeCategory_clicked();
+ void cellChanged(int row, int column);
+
+private:
+
+ void refreshIDs();
+ void fillTable();
+
+private:
+
+ Ui::CategoriesDialog *ui;
+ int m_ContextRow;
+
+ int m_HighestID;
+ std::set<int> m_IDs;
+
+};
+
+#endif // CATEGORIESDIALOG_H
+
diff --git a/src/categoriesdialog.ui b/src/categoriesdialog.ui new file mode 100644 index 00000000..582a7608 --- /dev/null +++ b/src/categoriesdialog.ui @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CategoriesDialog</class>
+ <widget class="QDialog" name="CategoriesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>553</width>
+ <height>444</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Categories</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTableWidget" name="categoriesTable">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="dragEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::NoDragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::IgnoreAction</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="gridStyle">
+ <enum>Qt::DashLine</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderDefaultSectionSize">
+ <number>100</number>
+ </attribute>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderMinimumSectionSize">
+ <number>26</number>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>ID</string>
+ </property>
+ <property name="toolTip">
+ <string>Internal ID for the category.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="toolTip">
+ <string>Name of the Categorie used for display.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Name of the Categorie used for display.</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Nexus IDs</string>
+ </property>
+ <property name="toolTip">
+ <string>Comma-Separated list of Nexus IDs to be matched to the internal ID.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Parent ID</string>
+ </property>
+ <property name="toolTip">
+ <string>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CategoriesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>CategoriesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/credentialsdialog.cpp b/src/credentialsdialog.cpp new file mode 100644 index 00000000..d9438c75 --- /dev/null +++ b/src/credentialsdialog.cpp @@ -0,0 +1,53 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "credentialsdialog.h"
+#include "ui_credentialsdialog.h"
+
+CredentialsDialog::CredentialsDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::CredentialsDialog)
+{
+ ui->setupUi(this);
+}
+
+CredentialsDialog::~CredentialsDialog()
+{
+ delete ui;
+}
+
+QString CredentialsDialog::username() const
+{
+ return ui->usernameEdit->text();
+}
+
+QString CredentialsDialog::password() const
+{
+ return ui->passwordEdit->text();
+}
+
+bool CredentialsDialog::store() const
+{
+ return ui->rememberCheck->isChecked();
+}
+
+bool CredentialsDialog::neverAsk() const
+{
+ return ui->dontaskBox->isChecked();
+}
diff --git a/src/credentialsdialog.h b/src/credentialsdialog.h new file mode 100644 index 00000000..1d65447b --- /dev/null +++ b/src/credentialsdialog.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CREDENTIALSDIALOG_H
+#define CREDENTIALSDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class CredentialsDialog;
+}
+
+class CredentialsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CredentialsDialog(QWidget *parent = 0);
+ ~CredentialsDialog();
+
+ QString username() const;
+ QString password() const;
+
+ bool store() const;
+ bool neverAsk() const;
+
+private:
+ Ui::CredentialsDialog *ui;
+};
+
+#endif // CREDENTIALSDIALOG_H
diff --git a/src/credentialsdialog.ui b/src/credentialsdialog.ui new file mode 100644 index 00000000..3dd9a62a --- /dev/null +++ b/src/credentialsdialog.ui @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CredentialsDialog</class>
+ <widget class="QDialog" name="CredentialsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>282</width>
+ <height>156</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Login</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>This feature may not work unless you're logged in with Nexus</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="usernameEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="passwordEdit">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="rememberCheck">
+ <property name="text">
+ <string>Remember</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QCheckBox" name="dontaskBox">
+ <property name="text">
+ <string>Never ask again</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CredentialsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>CredentialsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp new file mode 100644 index 00000000..30ea46ae --- /dev/null +++ b/src/directoryrefresher.cpp @@ -0,0 +1,103 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "directoryrefresher.h"
+#include "utility.h"
+#include "report.h"
+#include <gameinfo.h>
+#include <QDir>
+
+
+DirectoryRefresher::DirectoryRefresher()
+ : m_DirectoryStructure(NULL)
+{
+}
+
+DirectoryEntry *DirectoryRefresher::getDirectoryStructure()
+{
+ QMutexLocker locker(&m_RefreshLock);
+ DirectoryEntry *result = m_DirectoryStructure;
+ m_DirectoryStructure = NULL;
+ return result;
+}
+
+void DirectoryRefresher::setMods(const std::vector<std::tuple<QString, QString, int> > &mods)
+{
+ QMutexLocker locker(&m_RefreshLock);
+ m_Mods = mods;
+}
+
+
+void DirectoryRefresher::cleanStructure(DirectoryEntry *structure)
+{
+ static wchar_t *files[] = { L"meta.ini", L"readme.txt" };
+ for (int i = 0; i < sizeof(files) / sizeof(wchar_t*); ++i) {
+ structure->removeFile(files[i]);
+ }
+
+ static wchar_t *dirs[] = { L"fomod" };
+ for (int i = 0; i < sizeof(files) / sizeof(wchar_t*); ++i) {
+ structure->removeDir(dirs[i]);
+ }
+}
+
+void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory)
+{
+ std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory));
+
+ directoryStructure->addFromOrigin(ToWString(modName), directoryW, priority);
+ QDir dir(directory);
+ QFileInfoList bsaFiles = dir.entryInfoList(QStringList("*.bsa"), QDir::Files);
+ foreach (QFileInfo file, bsaFiles) {
+ directoryStructure->addFromBSA(ToWString(modName), directoryW,
+ ToWString(QDir::toNativeSeparators(file.absoluteFilePath())), priority);
+ }
+}
+
+void DirectoryRefresher::refresh()
+{
+ QMutexLocker locker(&m_RefreshLock);
+
+ delete m_DirectoryStructure;
+
+ m_DirectoryStructure = new DirectoryEntry(L"data", NULL, 0);
+
+ // TODO what was the point of having the priority in this tuple? the list is already sorted by priority
+ std::vector<std::tuple<QString, QString, int> >::const_iterator iter = m_Mods.begin();
+
+ //TODO i is the priority here, where higher = more important. the input vector is also sorted by priority but inverted!
+ for (int i = 1; iter != m_Mods.end(); ++iter, ++i) {
+ QString modName = std::get<0>(*iter);
+ try {
+ addModToStructure(m_DirectoryStructure, modName, i, std::get<1>(*iter));
+ } catch (const std::exception &e) {
+ emit error(tr("failed to read bsa: %1").arg(e.what()));
+ }
+ emit progress((i * 100) / m_Mods.size() + 1);
+ }
+
+ std::wstring dataDirectory = GameInfo::instance().getGameDirectory() + L"\\data";
+ m_DirectoryStructure->addFromOrigin(L"data", dataDirectory, 0);
+
+ emit progress(100);
+
+ cleanStructure(m_DirectoryStructure);
+
+ emit refreshed();
+}
diff --git a/src/directoryrefresher.h b/src/directoryrefresher.h new file mode 100644 index 00000000..47259fdd --- /dev/null +++ b/src/directoryrefresher.h @@ -0,0 +1,106 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DIRECTORYREFRESHER_H
+#define DIRECTORYREFRESHER_H
+
+#include <QObject>
+#include <directoryentry.h>
+#include <vector>
+#include <QMutex>
+#include <tuple>
+
+
+/**
+ * @brief used to asynchronously generate the virtual view of the combined data directory
+ **/
+class DirectoryRefresher : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ **/
+ DirectoryRefresher();
+
+ /**
+ * @brief retrieve the updated directory structure
+ *
+ * returns a pointer to the updated directory structure. DirectoryRefresher
+ * deletes its own pointer and the caller takes custody of the pointer
+ *
+ * @return updated directory structure
+ **/
+ DirectoryEntry *getDirectoryStructure();
+
+ /**
+ * @brief sets up the mods to be included in the directory structure
+ *
+ * @param mods list of the mods to include
+ **/
+ void setMods(const std::vector<std::tuple<QString, QString, int> > &mods);
+
+ /**
+ * @brief sets up the directory where mods are stored
+ * @param modDirectory the mod directory
+ * @note this function could be obsoleted easily by storing absolute paths in the parameter to setMods. This is legacy
+ */
+ void setModDirectory(const QString &modDirectory);
+
+ /**
+ * @brief remove files from the directory structure that are known to be irrelevant to the game
+ * @param the structure to clean
+ */
+ static void cleanStructure(DirectoryEntry *structure);
+
+ /**
+ * @brief add files for a mod to the directory structure, including bsas
+ * @param modName
+ * @param priorityBSA
+ * @param directory
+ * @param priorityDir
+ */
+ static void addModToStructure(DirectoryEntry *directoryStructure, const QString &modName, int priority, const QString &directory);
+
+public slots:
+
+ /**
+ * @brief generate a directory structure from the mods set earlier
+ **/
+ void refresh();
+
+signals:
+
+ void progress(int progress);
+ void error(const QString &error);
+ void refreshed();
+
+private:
+
+ std::vector<std::tuple<QString, QString, int> > m_Mods;
+ DirectoryEntry *m_DirectoryStructure;
+ QMutex m_RefreshLock;
+
+};
+
+#endif // DIRECTORYREFRESHER_H
diff --git a/src/downloadlist.cpp b/src/downloadlist.cpp new file mode 100644 index 00000000..a7f0869f --- /dev/null +++ b/src/downloadlist.cpp @@ -0,0 +1,106 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "downloadlist.h"
+#include "downloadmanager.h"
+#include <QEvent>
+
+#include <QSortFilterProxyModel>
+
+
+DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
+ : QAbstractTableModel(parent), m_Manager(manager)
+{
+ connect(m_Manager, SIGNAL(update(int)), this, SLOT(update(int)));
+ connect(m_Manager, SIGNAL(aboutToUpdate()), this, SLOT(aboutToUpdate()));
+}
+
+
+int DownloadList::rowCount(const QModelIndex&) const
+{
+ return m_Manager->numTotalDownloads();
+}
+
+int DownloadList::columnCount(const QModelIndex&) const
+{
+ return 3;
+}
+
+
+QModelIndex DownloadList::index(int row, int column, const QModelIndex&) const
+{
+ return createIndex(row, column, row);
+}
+
+
+QModelIndex DownloadList::parent(const QModelIndex&) const
+{
+ return QModelIndex();
+}
+
+
+QVariant DownloadList::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if ((role == Qt::DisplayRole) &&
+ (orientation == Qt::Horizontal)) {
+ switch (section) {
+ case 0: return tr("Name");
+ case 1: return tr("Filetime");
+ default: return tr("Done");
+ }
+ } else {
+ return QAbstractItemModel::headerData(section, orientation, role);
+ }
+}
+
+
+QVariant DownloadList::data(const QModelIndex &index, int role) const
+{
+ if (role == Qt::DisplayRole) {
+ return index.row();
+ } else if (role == Qt::ToolTipRole) {
+ if (m_Manager->isInfoIncomplete(index.row())) {
+ return tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
+ } else {
+ NexusInfo info = m_Manager->getNexusInfo(index.row());
+ return QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
+ }
+ } else {
+ return QVariant();
+ }
+}
+
+
+void DownloadList::aboutToUpdate()
+{
+ emit beginResetModel();
+}
+
+
+void DownloadList::update(int row)
+{
+ if (row < 0) {
+ emit endResetModel();
+ } else if (row < this->rowCount()) {
+ emit dataChanged(this->index(row, 0, QModelIndex()), this->index(row, 1, QModelIndex()));
+ } else {
+ qCritical("invalid row %d in download list, update failed", row);
+ }
+}
+
diff --git a/src/downloadlist.h b/src/downloadlist.h new file mode 100644 index 00000000..abd177b2 --- /dev/null +++ b/src/downloadlist.h @@ -0,0 +1,92 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DOWNLOADLIST_H
+#define DOWNLOADLIST_H
+
+#include <QAbstractTableModel>
+
+
+class DownloadManager;
+
+
+/**
+ * @brief model of the list of active and completed downloads
+ **/
+class DownloadList : public QAbstractTableModel
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param manager the download manager processing downloads
+ * @param parent parent object Defaults to 0.
+ **/
+ explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
+
+ /**
+ * @brief retrieve the number of rows to display. Invoked by Qt
+ *
+ * @param parent not relevant for this implementation
+ * @return number of rows to display
+ **/
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual int columnCount(const QModelIndex &parent) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ /**
+ * @brief retrieve the data to display in a specific row. Invoked by Qt
+ *
+ * @param index location to look up
+ * @param role ... Defaults to Qt::DisplayRole.
+ * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
+ **/
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+signals:
+
+public slots:
+
+ /**
+ * @brief used to inform the model that data has changed
+ *
+ * @param row the row that changed. This can be negative to update the whole view
+ **/
+ void update(int row);
+
+ void aboutToUpdate();
+
+private:
+
+private:
+
+ DownloadManager *m_Manager;
+
+};
+
+#endif // DOWNLOADLIST_H
diff --git a/src/downloadlistsortproxy.cpp b/src/downloadlistsortproxy.cpp new file mode 100644 index 00000000..7efbd78f --- /dev/null +++ b/src/downloadlistsortproxy.cpp @@ -0,0 +1,55 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "downloadlistsortproxy.h" + +DownloadListSortProxy::DownloadListSortProxy(const DownloadManager *manager, QObject *parent) + : QSortFilterProxyModel(parent), m_Manager(manager), m_CurrentFilter() +{ +} + +void DownloadListSortProxy::updateFilter(const QString &filter) +{ + m_CurrentFilter = filter; + invalidateFilter(); +} + +bool DownloadListSortProxy::lessThan(const QModelIndex &left, + const QModelIndex &right) const +{ + int leftIndex = sourceModel()->data(left).toInt(); + int rightIndex = sourceModel()->data(right).toInt(); + + if (left.column() == 0) { + return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0; + } else if (left.column() == 1) { + return leftIndex < rightIndex; + } else { + return m_Manager->getState(leftIndex) < m_Manager->getState(rightIndex); + } +} + + +bool DownloadListSortProxy::filterAcceptsRow(int source_row, const QModelIndex&) const +{ + if (m_CurrentFilter.length() == 0) { + return true; + } + return m_Manager->getFileName(source_row).contains(m_CurrentFilter, Qt::CaseInsensitive); +} diff --git a/src/downloadlistsortproxy.h b/src/downloadlistsortproxy.h new file mode 100644 index 00000000..36c72609 --- /dev/null +++ b/src/downloadlistsortproxy.h @@ -0,0 +1,56 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DOWNLOADLISTSORTPROXY_H
+#define DOWNLOADLISTSORTPROXY_H
+
+
+#include <QSortFilterProxyModel>
+#include "downloadmanager.h"
+
+
+class DownloadListSortProxy : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ + explicit DownloadListSortProxy(const DownloadManager *manager, QObject *parent = 0); + +public slots: + + void updateFilter(const QString &filter); + +protected: + + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; + +signals: + +public slots:
+
+private: + + const DownloadManager *m_Manager; + QString m_CurrentFilter; + + +}; + +#endif // DOWNLOADLISTSORTPROXY_H diff --git a/src/downloadlistwidget.cpp b/src/downloadlistwidget.cpp new file mode 100644 index 00000000..3bd9df3a --- /dev/null +++ b/src/downloadlistwidget.cpp @@ -0,0 +1,242 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "downloadlistwidget.h"
+#include "ui_downloadlistwidget.h"
+#include "downloadmanager.h"
+#include <QPainter>
+#include <QMouseEvent>
+#include <QMenu>
+#include <QMessageBox>
+#include <QSortFilterProxyModel>
+
+
+DownloadListWidget::DownloadListWidget(QWidget *parent)
+ : QWidget(parent), ui(new Ui::DownloadListWidget)
+{
+ ui->setupUi(this);
+}
+
+
+DownloadListWidget::~DownloadListWidget()
+{
+ delete ui;
+}
+
+
+DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
+ : QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidget), m_ContextRow(0), m_View(view)
+{
+ m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
+ m_Progress = m_ItemWidget->findChild<QProgressBar*>("downloadProgress");
+ m_InstallLabel = m_ItemWidget->findChild<QLabel*>("installLabel");
+
+ m_InstallLabel->setVisible(false);
+}
+
+
+DownloadListWidgetDelegate::~DownloadListWidgetDelegate()
+{
+ delete m_ItemWidget;
+}
+
+
+void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ try {
+ m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height()));
+
+ int downloadIndex = index.data().toInt();
+
+ QString name = m_Manager->getFileName(downloadIndex);
+ if (name.length() > 53) {
+ name.truncate(50);
+ name.append("...");
+ }
+ m_NameLabel->setText(name);
+ DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
+ if (state >= DownloadManager::STATE_READY) {
+ QPalette labelPalette;
+ m_InstallLabel->setVisible(true);
+ m_Progress->setVisible(false);
+ if (state == DownloadManager::STATE_INSTALLED) {
+ // the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
+ // of DownloadListWidgetDelegate?
+#if QT_VERSION >= 0x050000
+ m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0));
+#else
+ m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8));
+#endif
+ labelPalette.setColor(QPalette::WindowText, Qt::darkGray);
+ } else {
+ // the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead
+ // of DownloadListWidgetDelegate?
+#if QT_VERSION >= 0x050000
+ m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
+#else
+ m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
+#endif
+ labelPalette.setColor(QPalette::WindowText, Qt::darkGreen);
+ }
+ m_InstallLabel->setPalette(labelPalette);
+ if (m_Manager->isInfoIncomplete(downloadIndex)) {
+ m_NameLabel->setText("<img src=\":/MO/gui/resources/dialog-warning_16.png\" /> " + m_NameLabel->text());
+ }
+ } else {
+ m_InstallLabel->setVisible(false);
+ m_Progress->setVisible(true);
+ m_Progress->setValue(m_Manager->getProgress(downloadIndex));
+ }
+
+ painter->save();
+ painter->translate(QPoint(0, option.rect.topLeft().y()));
+ m_ItemWidget->render(painter);
+ painter->restore();
+ } catch (const std::exception &e) {
+ qCritical("failed to paint download list: %s", e.what());
+ }
+}
+
+QSize DownloadListWidgetDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
+{
+ const int width = m_ItemWidget->minimumWidth();
+ const int height = m_ItemWidget->height();
+ return QSize(width, height);
+}
+
+
+void DownloadListWidgetDelegate::issueInstall()
+{
+ emit installDownload(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueQueryInfo()
+{
+ emit queryInfo(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueDelete()
+{
+ emit removeDownload(m_ContextRow, true);
+}
+
+void DownloadListWidgetDelegate::issueRemoveFromView()
+{
+ emit removeDownload(m_ContextRow, false);
+}
+
+void DownloadListWidgetDelegate::issueCancel()
+{
+ emit cancelDownload(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issuePause()
+{
+ emit pauseDownload(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueResume()
+{
+ emit resumeDownload(m_ContextRow);
+}
+
+void DownloadListWidgetDelegate::issueDeleteAll()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all finished downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-1, true);
+ }
+}
+
+void DownloadListWidgetDelegate::issueDeleteCompleted()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all installed downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-2, true);
+ }
+}
+
+void DownloadListWidgetDelegate::issueRemoveFromViewAll()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all finished downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-1, false);
+ }
+}
+
+void DownloadListWidgetDelegate::issueRemoveFromViewCompleted()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all installed downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-2, false);
+ }
+}
+
+bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option, const QModelIndex &index)
+{
+ try {
+ if (event->type() == QEvent::MouseButtonDblClick) {
+ QModelIndex sourceIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
+ if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) {
+ emit installDownload(sourceIndex.row());
+ }
+ return true;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ if (mouseEvent->button() == Qt::RightButton) {
+ QMenu menu(m_View);
+ m_ContextRow = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index).row();
+ DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
+ if (state >= DownloadManager::STATE_READY) {
+ menu.addAction(tr("Install"), this, SLOT(issueInstall()));
+ if (m_Manager->isInfoIncomplete(m_ContextRow)) {
+ menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
+ }
+ menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
+ menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
+ } else if (state == DownloadManager::STATE_DOWNLOADING){
+ menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
+ menu.addAction(tr("Pause"), this, SLOT(issuePause()));
+ } else if (state == DownloadManager::STATE_PAUSED) {
+ menu.addAction(tr("Remove"), this, SLOT(issueRemove()));
+ menu.addAction(tr("Resume"), this, SLOT(issueResume()));
+ }
+
+ menu.addSeparator();
+ menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
+ menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
+ menu.addSeparator();
+ menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
+ menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
+ menu.exec(mouseEvent->globalPos());
+
+ event->accept();
+ return true;
+ }
+ }
+ } catch (const std::exception &e) {
+ qCritical("failed to handle editor event: %s", e.what());
+ }
+ return QItemDelegate::editorEvent(event, model, option, index);
+}
diff --git a/src/downloadlistwidget.h b/src/downloadlistwidget.h new file mode 100644 index 00000000..6f9fa24b --- /dev/null +++ b/src/downloadlistwidget.h @@ -0,0 +1,102 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DOWNLOADLISTWIDGET_H
+#define DOWNLOADLISTWIDGET_H
+
+#include <QWidget>
+#include <QItemDelegate>
+#include <QLabel>
+#include <QProgressBar>
+#include <QTreeView>
+
+namespace Ui {
+ class DownloadListWidget;
+}
+
+class DownloadListWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit DownloadListWidget(QWidget *parent = 0);
+ ~DownloadListWidget();
+
+
+private:
+ Ui::DownloadListWidget *ui;
+};
+
+class DownloadManager;
+
+class DownloadListWidgetDelegate : public QItemDelegate
+{
+
+ Q_OBJECT
+
+public:
+
+ DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
+ ~DownloadListWidgetDelegate();
+
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+signals:
+
+ void installDownload(int index);
+ void queryInfo(int index);
+ void removeDownload(int index, bool deleteFile);
+ void cancelDownload(int index);
+ void pauseDownload(int index);
+ void resumeDownload(int index);
+
+protected:
+
+ bool editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option, const QModelIndex &index);
+
+private slots:
+
+ void issueInstall();
+ void issueDelete();
+ void issueRemoveFromView();
+ void issueCancel();
+ void issuePause();
+ void issueResume();
+ void issueDeleteAll();
+ void issueDeleteCompleted();
+ void issueRemoveFromViewAll();
+ void issueRemoveFromViewCompleted();
+ void issueQueryInfo();
+
+private:
+
+ DownloadListWidget *m_ItemWidget;
+ DownloadManager *m_Manager;
+
+ QLabel *m_NameLabel;
+ QProgressBar *m_Progress;
+ QLabel *m_InstallLabel;
+ int m_ContextRow;
+
+ QTreeView *m_View;
+};
+
+#endif // DOWNLOADLISTWIDGET_H
diff --git a/src/downloadlistwidget.ui b/src/downloadlistwidget.ui new file mode 100644 index 00000000..5f169215 --- /dev/null +++ b/src/downloadlistwidget.ui @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DownloadListWidget</class>
+ <widget class="QWidget" name="DownloadListWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>315</width>
+ <height>75</height>
+ </rect>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="windowTitle">
+ <string>Placeholder</string>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="nameLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>323</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Placeholder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="installLabel">
+ <property name="text">
+ <string>Done - Double Click to install</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="downloadProgress">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/downloadlistwidgetcompact.cpp b/src/downloadlistwidgetcompact.cpp new file mode 100644 index 00000000..c2ff8a08 --- /dev/null +++ b/src/downloadlistwidgetcompact.cpp @@ -0,0 +1,237 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "downloadlistwidgetcompact.h"
+#include "ui_downloadlistwidgetcompact.h"
+#include <QPainter>
+#include <QMouseEvent>
+#include <QMenu>
+#include <QMessageBox>
+#include <QSortFilterProxyModel>
+#include "downloadmanager.h"
+
+
+DownloadListWidgetCompact::DownloadListWidgetCompact(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::DownloadListWidgetCompact)
+{
+ ui->setupUi(this);
+}
+
+DownloadListWidgetCompact::~DownloadListWidgetCompact()
+{
+ delete ui;
+}
+
+
+DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent)
+ : QItemDelegate(parent), m_Manager(manager), m_ItemWidget(new DownloadListWidgetCompact), m_View(view)
+{
+ m_NameLabel = m_ItemWidget->findChild<QLabel*>("nameLabel");
+ m_Progress = m_ItemWidget->findChild<QProgressBar*>("downloadProgress");
+ m_DoneLabel = m_ItemWidget->findChild<QLabel*>("doneLabel");
+
+ m_DoneLabel->setVisible(false);
+}
+
+
+DownloadListWidgetCompactDelegate::~DownloadListWidgetCompactDelegate()
+{
+ delete m_ItemWidget;
+}
+
+
+void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ try {
+// m_ItemWidget->resize(option.rect.size());
+ m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height()));
+ if (index.row() % 2 == 1) {
+ m_ItemWidget->setBackgroundRole(QPalette::AlternateBase);
+ } else {
+ m_ItemWidget->setBackgroundRole(QPalette::Base);
+ }
+
+ int downloadIndex = index.data().toInt();
+
+ QString name = m_Manager->getFileName(downloadIndex);
+ if (name.length() > 53) {
+ name.truncate(50);
+ name.append("...");
+ }
+ m_NameLabel->setText(name);
+ DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
+ if (state >= DownloadManager::STATE_READY) {
+ m_DoneLabel->setVisible(true);
+ m_Progress->setVisible(false);
+ if (state == DownloadManager::STATE_INSTALLED) {
+ m_DoneLabel->setText(tr("Installed"));
+ m_DoneLabel->setForegroundRole(QPalette::Mid);
+ } else {
+ m_DoneLabel->setText(tr("Done"));
+ m_DoneLabel->setForegroundRole(QPalette::WindowText);
+ }
+ if (m_Manager->isInfoIncomplete(downloadIndex)) {
+ m_NameLabel->setText("<img src=\":/MO/gui/resources/dialog-warning_16.png\"/> " + m_NameLabel->text());
+ }
+ } else {
+ m_DoneLabel->setVisible(false);
+ m_Progress->setVisible(true);
+ m_Progress->setValue(m_Manager->getProgress(downloadIndex));
+ }
+
+ painter->save();
+ painter->translate(QPoint(0, option.rect.topLeft().y()));
+ m_ItemWidget->render(painter);
+ painter->restore();
+ } catch (const std::exception &e) {
+ qCritical("failed to paint download list item %d: %s", index.row(), e.what());
+ }
+}
+
+QSize DownloadListWidgetCompactDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
+{
+ const int width = m_ItemWidget->minimumWidth();
+ const int height = m_ItemWidget->height();
+ return QSize(width, height);
+}
+
+
+void DownloadListWidgetCompactDelegate::issueInstall()
+{
+ emit installDownload(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issueQueryInfo()
+{
+ emit queryInfo(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issueDelete()
+{
+ emit removeDownload(m_ContextIndex.row(), true);
+}
+
+void DownloadListWidgetCompactDelegate::issueRemoveFromView()
+{
+ emit removeDownload(m_ContextIndex.row(), false);
+}
+
+void DownloadListWidgetCompactDelegate::issueCancel()
+{
+ emit cancelDownload(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issuePause()
+{
+ emit pauseDownload(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issueResume()
+{
+ emit resumeDownload(m_ContextIndex.row());
+}
+
+void DownloadListWidgetCompactDelegate::issueDeleteAll()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all finished downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-1, true);
+ }
+}
+
+void DownloadListWidgetCompactDelegate::issueDeleteCompleted()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will remove all installed downloads from this list and from disk."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-2, true);
+ }
+}
+
+void DownloadListWidgetCompactDelegate::issueRemoveFromViewAll()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will permanently remove all finished downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-1, false);
+ }
+}
+
+void DownloadListWidgetCompactDelegate::issueRemoveFromViewCompleted()
+{
+ if (QMessageBox::question(NULL, tr("Are you sure?"),
+ tr("This will permanently remove all installed downloads from this list (but NOT from disk)."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit removeDownload(-2, false);
+ }
+}
+
+
+bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option, const QModelIndex &index)
+{
+ try {
+ if (event->type() == QEvent::MouseButtonDblClick) {
+ QModelIndex sourceIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
+ if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) {
+ emit installDownload(sourceIndex.row());
+ }
+ return true;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ if (mouseEvent->button() == Qt::RightButton) {
+ QMenu menu;
+ m_ContextIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
+ DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
+ if (state >= DownloadManager::STATE_READY) {
+ menu.addAction(tr("Install"), this, SLOT(issueInstall()));
+ if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
+ menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
+ }
+ menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
+ menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
+ } else if (state == DownloadManager::STATE_DOWNLOADING){
+ menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
+ menu.addAction(tr("Pause"), this, SLOT(issuePause()));
+ } else if (state == DownloadManager::STATE_PAUSED) {
+ menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
+ menu.addAction(tr("Resume"), this, SLOT(issueResume()));
+ }
+
+ menu.addSeparator();
+ menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
+ menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
+ menu.addSeparator();
+ menu.addAction(tr("Remove Installed..."), this, SLOT(issueRemoveFromViewCompleted()));
+ menu.addAction(tr("Remove All..."), this, SLOT(issueRemoveFromViewAll()));
+ menu.exec(mouseEvent->globalPos());
+
+ event->accept();
+ return false;
+ }
+ }
+ } catch (const std::exception &e) {
+ qCritical("failed to handle editor event: %s", e.what());
+ }
+
+ return QItemDelegate::editorEvent(event, model, option, index);
+}
+
diff --git a/src/downloadlistwidgetcompact.h b/src/downloadlistwidgetcompact.h new file mode 100644 index 00000000..65b110b6 --- /dev/null +++ b/src/downloadlistwidgetcompact.h @@ -0,0 +1,106 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DOWNLOADLISTWIDGETCOMPACT_H
+#define DOWNLOADLISTWIDGETCOMPACT_H
+
+#include <QWidget>
+#include <QItemDelegate>
+#include <QLabel>
+#include <QProgressBar>
+#include <QTreeView>
+
+
+namespace Ui {
+class DownloadListWidgetCompact;
+}
+
+class DownloadListWidgetCompact : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit DownloadListWidgetCompact(QWidget *parent = 0);
+ ~DownloadListWidgetCompact();
+
+private:
+ Ui::DownloadListWidgetCompact *ui;
+ int m_ContextRow;
+};
+
+class DownloadManager;
+
+class DownloadListWidgetCompactDelegate : public QItemDelegate
+{
+
+ Q_OBJECT
+
+public:
+
+ DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
+ ~DownloadListWidgetCompactDelegate();
+
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+
+signals:
+
+ void installDownload(int index);
+ void queryInfo(int index);
+ void removeDownload(int index, bool deleteFile);
+ void cancelDownload(int index);
+ void pauseDownload(int index);
+ void resumeDownload(int index);
+
+protected:
+
+ bool editorEvent(QEvent *event, QAbstractItemModel *model,
+ const QStyleOptionViewItem &option, const QModelIndex &index);
+
+private slots:
+
+ void issueInstall();
+ void issueDelete();
+ void issueRemoveFromView();
+ void issueCancel();
+ void issuePause();
+ void issueResume();
+ void issueDeleteAll();
+ void issueDeleteCompleted();
+ void issueRemoveFromViewAll();
+ void issueRemoveFromViewCompleted();
+ void issueQueryInfo();
+
+private:
+
+ DownloadListWidgetCompact *m_ItemWidget;
+ DownloadManager *m_Manager;
+
+ QLabel *m_NameLabel;
+ QProgressBar *m_Progress;
+ QLabel *m_DoneLabel;
+
+ QModelIndex m_ContextIndex;
+
+ QTreeView *m_View;
+
+};
+
+#endif // DOWNLOADLISTWIDGETCOMPACT_H
+
diff --git a/src/downloadlistwidgetcompact.ui b/src/downloadlistwidgetcompact.ui new file mode 100644 index 00000000..b905706c --- /dev/null +++ b/src/downloadlistwidgetcompact.ui @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DownloadListWidgetCompact</class>
+ <widget class="QWidget" name="DownloadListWidgetCompact">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>315</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="windowTitle">
+ <string>Placeholder</string>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="nameLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="text">
+ <string>Placeholder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="doneLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>0</red> + <green>118</green> + <blue>0</blue> + </color> + </brush> + </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>0</red> + <green>118</green> + <blue>0</blue> + </color> + </brush> + </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="text">
+ <string>Done</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="downloadProgress">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp new file mode 100644 index 00000000..a08490e6 --- /dev/null +++ b/src/downloadmanager.cpp @@ -0,0 +1,928 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "downloadmanager.h"
+#include "report.h"
+#include "nxmurl.h"
+#include <gameinfo.h>
+#include "utility.h"
+#include "json.h"
+#include "selectiondialog.h"
+#include <QTimer>
+#include <QFileInfo>
+#include <QRegExp>
+#include <QDirIterator>
+#include <QSettings>
+#include <QInputDialog>
+#include <regex>
+#include <QMessageBox>
+
+
+using QtJson::Json;
+
+
+// TODO limit number of downloads, also display download during nxm requests, store modid/fileid with downloads
+
+
+static const char UNFINISHED[] = ".unfinished";
+
+
+void DownloadManager::DownloadInfo::setName(QString newName, bool renameFile)
+{
+ QString oldMetaFileName = QString("%1.meta").arg(m_FileName);
+ m_FileName = QFileInfo(newName).fileName();
+ if ((m_State == DownloadManager::STATE_STARTED) ||
+ (m_State == DownloadManager::STATE_DOWNLOADING)) {
+ newName.append(UNFINISHED);
+ }
+ if (renameFile) {
+ if ((newName != m_Output.fileName()) && !m_Output.rename(newName)) {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(m_Output.fileName()).arg(newName));
+ return;
+ }
+
+ QFile metaFile(oldMetaFileName);
+ if (metaFile.exists()) {
+ metaFile.rename(newName.mid(0).append(".meta"));
+ }
+ }
+ m_Output.setFileName(newName);
+}
+
+
+DownloadManager::DownloadManager(NexusInterface *nexusInterface, QObject *parent)
+ : QObject(parent), m_NexusInterface(nexusInterface), m_DirWatcher()
+{
+ connect(&m_DirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
+}
+
+
+DownloadManager::~DownloadManager()
+{
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
+ delete *iter;
+ }
+}
+
+
+bool DownloadManager::downloadsInProgress()
+{
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter) {
+ if ((*iter)->m_State < STATE_READY) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void DownloadManager::setOutputDirectory(const QString &outputDirectory)
+{
+ QStringList directories = m_DirWatcher.directories();
+ if (directories.length() != 0) {
+ m_DirWatcher.removePaths(directories);
+ }
+ m_OutputDirectory = QDir::fromNativeSeparators(outputDirectory);
+ m_DirWatcher.addPath(m_OutputDirectory);
+ refreshList();
+}
+
+void DownloadManager::refreshList()
+{
+ // remove finished downloads
+ for (QVector<DownloadInfo*>::iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end();) {
+ if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED)) {
+ delete *Iter;
+ Iter = m_ActiveDownloads.erase(Iter);
+ } else {
+//qDebug("leaving %s / %s in the download list since it's still being processed",
+// qPrintable((*Iter)->m_FileName), qPrintable((*Iter)->m_Output.fileName()));
+ ++Iter;
+ }
+ }
+
+ QStringList nameFilters;
+ nameFilters.append("*.rar");
+ nameFilters.append("*.zip");
+ nameFilters.append("*.7z");
+ nameFilters.append("*.fomod");
+ nameFilters.append(QString("*").append(UNFINISHED));
+
+ QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
+
+ // add existing downloads to list
+ foreach (QString file, dir.entryList(nameFilters, QDir::Files, QDir::Time)) {
+ bool Exists = false;
+ for (QVector<DownloadInfo*>::const_iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end() && !Exists; ++Iter) {
+ if (QString::compare((*Iter)->m_FileName, file, Qt::CaseInsensitive) == 0) {
+ Exists = true;
+ } else if (QString::compare(QFileInfo((*Iter)->m_Output.fileName()).fileName(), file, Qt::CaseInsensitive) == 0) {
+//qDebug("%s found in m_Output: %s", qPrintable(file), qPrintable((*Iter)->m_Output.fileName()));
+ Exists = true;
+ }
+ }
+ if (Exists) {
+ continue;
+ }
+ DownloadInfo *info = new DownloadInfo;
+ info->m_State = STATE_READY;
+ if (file.endsWith(UNFINISHED)) {
+ info->m_FileName = file.mid(0, file.length() - strlen(UNFINISHED));
+ info->m_State = STATE_PAUSED;
+ } else {
+ info->m_FileName = file;
+ }
+ info->m_Output.setFileName(QString("%1/%2").arg(QDir::fromNativeSeparators(m_OutputDirectory)).arg(file));
+
+ QString metaFileName = QString("%1.meta").arg(info->m_Output.fileName());
+ QSettings metaFile(metaFileName, QSettings::IniFormat);
+ if (metaFile.value("removed", false).toBool()) {
+ continue;
+ }
+ info->m_ModID = metaFile.value("modID", 0).toInt();
+ info->m_FileID = metaFile.value("fileID", 0).toInt();
+ info->m_Url = metaFile.value("url", "").toString();
+ info->m_NexusInfo.m_Name = metaFile.value("name", 0).toString();
+ info->m_NexusInfo.m_ModName = metaFile.value("modName", "").toString();
+ info->m_NexusInfo.m_Version = metaFile.value("version", 0).toString();
+ info->m_NexusInfo.m_NewestVersion = metaFile.value("newestVersion", "").toString();
+ info->m_NexusInfo.m_Category = metaFile.value("category", 0).toInt();
+ if (metaFile.value("installed", false).toBool()) {
+ info->m_State = STATE_INSTALLED;
+ }
+ if (metaFile.value("paused", false).toBool()) {
+ info->m_State = STATE_PAUSED;
+ }
+ m_ActiveDownloads.push_front(info);
+ }
+ qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
+ emit update(-1);
+}
+
+
+bool DownloadManager::addDownload(const QUrl &url, int modID, int fileID, const NexusInfo &nexusInfo)
+{
+ QString fileName = QFileInfo(url.path()).fileName();
+ if (fileName.isEmpty()) {
+ fileName = "unknown";
+ }
+
+ QNetworkRequest request(url);
+ return addDownload(m_NexusInterface->getAccessManager()->get(request), fileName, modID, fileID, nexusInfo);
+}
+
+bool DownloadManager::addDownload(QNetworkReply *reply, const QString &fileName, int modID,
+ int fileID, const NexusInfo &nexusInfo)
+{
+ // download invoked from an already open network reply (i.e. download link in the browser)
+ DownloadInfo *newDownload = new DownloadInfo;
+ newDownload->m_StartTime.start();
+ newDownload->m_Progress = 0;
+ newDownload->m_ResumePos = 0;
+ newDownload->m_ModID = modID;
+ newDownload->m_FileID = fileID;
+ newDownload->m_NexusInfo = nexusInfo;
+
+ QString baseName = fileName;
+
+ if (!nexusInfo.m_FileName.isEmpty()) {
+ baseName = nexusInfo.m_FileName;
+ } else {
+ QString dispoName = getFileNameFromNetworkReply(reply);
+
+ if (!dispoName.isEmpty()) {
+ baseName = dispoName;
+ }
+ }
+
+ if (QFile::exists(m_OutputDirectory + "/" + baseName) &&
+ (QMessageBox::question(NULL, tr("Download again?"), tr("A file with the same name has already been downloaded. "
+ "Do you want to download it again? The new file will receive a different name."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) {
+ delete newDownload;
+ return false;
+ }
+
+ newDownload->setName(getDownloadFileName(baseName), false);
+
+ addDownload(reply, newDownload, false);
+
+ emit update(-1);
+ return true;
+}
+
+
+void DownloadManager::addDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume)
+{
+ newDownload->m_Reply = reply;
+ newDownload->m_State = STATE_DOWNLOADING;
+ newDownload->m_Url = reply->url().toString();
+
+ QIODevice::OpenMode mode = QIODevice::WriteOnly;
+ if (resume) {
+ mode |= QIODevice::Append;
+ }
+
+ if (!newDownload->m_Output.open(mode)) {
+ reportError(tr("failed to download %1: could not open output file: %2")
+ .arg(reply->url().toString()).arg(newDownload->m_Output.fileName()));
+ return;
+ }
+
+ connect(newDownload->m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)));
+ connect(newDownload->m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ connect(newDownload->m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
+ connect(newDownload->m_Reply, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
+
+ if (!resume) {
+ emit aboutToUpdate();
+
+ m_ActiveDownloads.append(newDownload);
+// qDebug("downloads after add: %d", m_ActiveDownloads.size());
+
+ emit update(-1);
+ }
+}
+
+
+void DownloadManager::addNXMDownload(const QString &url)
+{
+ NXMUrl nxmInfo(url);
+ m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.getModId(), nxmInfo.getFileId(), this, QVariant()));
+}
+
+
+void DownloadManager::removeFile(int index, bool deleteFile)
+{
+ if (index >= m_ActiveDownloads.size()) {
+ throw MyException(tr("invalid index"));
+ }
+
+ DownloadInfo *download = m_ActiveDownloads.at(index);
+ QString filePath = m_OutputDirectory + "/" + download->m_FileName;
+ if ((download->m_State == STATE_STARTED) ||
+ (download->m_State == STATE_DOWNLOADING)) {
+ // shouldn't have been possible
+ qCritical("tried to remove active download");
+ return;
+ }
+
+ if (download->m_State == STATE_PAUSED) {
+ filePath.append(UNFINISHED);
+ }
+
+ if (deleteFile) {
+ if (!QFile(filePath).remove()) {
+ reportError(tr("failed to delete %1").arg(filePath));
+ return;
+ }
+
+ QFile metaFile(filePath.append(".meta"));
+ if (metaFile.exists() && !metaFile.remove()) {
+ reportError(tr("failed to delete meta file for %1").arg(filePath));
+ }
+ } else {
+ QSettings metaSettings(filePath.append(".meta"), QSettings::IniFormat);
+ metaSettings.setValue("removed", true);
+ }
+}
+
+class LessThanWrapper
+{
+public:
+ LessThanWrapper(DownloadManager *manager) : m_Manager(manager) {}
+ bool operator()(int LHS, int RHS) {
+ return m_Manager->getFileName(LHS).compare(m_Manager->getFileName(RHS), Qt::CaseInsensitive) < 0;
+
+ }
+
+private:
+ DownloadManager *m_Manager;
+};
+
+bool DownloadManager::ByName(int LHS, int RHS)
+{
+ return m_ActiveDownloads[LHS]->m_FileName < m_ActiveDownloads[RHS]->m_FileName;
+}
+
+
+void DownloadManager::refreshAlphabeticalTranslation()
+{
+ m_AlphabeticalTranslation.clear();
+ int pos = 0;
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter, ++pos) {
+ m_AlphabeticalTranslation.push_back(pos);
+ }
+
+ qSort(m_AlphabeticalTranslation.begin(), m_AlphabeticalTranslation.end(), LessThanWrapper(this));
+}
+
+
+void DownloadManager::removeDownload(int index, bool deleteFile)
+{
+ try {
+ emit aboutToUpdate();
+
+ if (index < 0) {
+ DownloadState minState = index < -1 ? STATE_INSTALLED : STATE_READY;
+ index = 0;
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) {
+ if ((*iter)->m_State >= minState) {
+ removeFile(index, deleteFile);
+ delete *iter;
+ iter = m_ActiveDownloads.erase(iter);
+ } else {
+ ++iter;
+ ++index;
+ }
+ }
+ } else {
+ if (index >= m_ActiveDownloads.size()) {
+ reportError(tr("invalid index %1").arg(index));
+ return;
+ }
+
+ removeFile(index, deleteFile);
+ delete m_ActiveDownloads[index];
+ m_ActiveDownloads.erase(m_ActiveDownloads.begin() + index);
+ }
+ emit update(-1);
+ } catch (const std::exception &e) {
+ qCritical("failed to remove download: %s", e.what());
+ }
+}
+
+
+void DownloadManager::cancelDownload(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("invalid index %1").arg(index));
+ return;
+ }
+
+ if (m_ActiveDownloads[index]->m_State == STATE_DOWNLOADING) {
+ m_ActiveDownloads[index]->m_State = STATE_CANCELING;
+ qDebug("canceled %d - %s", index, m_ActiveDownloads[index]->m_FileName.toUtf8().constData());
+ }
+}
+
+
+void DownloadManager::pauseDownload(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("invalid index %1").arg(index));
+ return;
+ }
+
+ if (m_ActiveDownloads[index]->m_State == STATE_DOWNLOADING) {
+ m_ActiveDownloads[index]->m_State = STATE_PAUSING;
+ qDebug("pausing %d - %s", index, m_ActiveDownloads[index]->m_FileName.toUtf8().constData());
+ }
+}
+
+
+void DownloadManager::resumeDownload(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("invalid index %1").arg(index));
+ return;
+ }
+ if (m_ActiveDownloads[index]->m_State == STATE_PAUSED) {
+ DownloadInfo *info = m_ActiveDownloads[index];
+ qDebug("request resume from url %s", info->m_Url.toUtf8().constData());
+ QNetworkRequest request(info->m_Url);
+ info->m_ResumePos = info->m_Output.size();
+ QByteArray rangeHeader = "bytes=" + QByteArray::number(info->m_ResumePos) + "-";
+ request.setRawHeader("Range", rangeHeader);
+ addDownload(m_NexusInterface->getAccessManager()->get(request), info, true);
+ }
+ emit update(index);
+}
+
+
+void DownloadManager::queryInfo(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ reportError(tr("invalid index %1").arg(index));
+ return;
+ }
+ DownloadInfo *info = m_ActiveDownloads[index];
+
+ if (info->m_ModID == 0UL) {
+ QString fileName = getFileName(index);
+ QString ignore;
+ NexusInterface::interpretNexusFileName(fileName, ignore, info->m_ModID, true);
+ if (info->m_ModID < 0) {
+ QString modIDString;
+ while (modIDString.isEmpty()) {
+ modIDString = QInputDialog::getText(NULL, tr("Please enter the nexus mod id"), tr("Mod ID:"), QLineEdit::Normal,
+ QString(), NULL, 0, Qt::ImhFormattedNumbersOnly);
+ if (modIDString.isNull()) {
+ // canceled
+ return;
+ } else if (modIDString.contains(QRegExp("[^0-9]"))) {
+ qDebug("illegal character in mod-id");
+ modIDString.clear();
+ }
+ }
+ info->m_ModID = modIDString.toInt(NULL, 10);
+ }
+ }
+ m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_ModID, this, qVariantFromValue(static_cast<void*>(info))));
+}
+
+
+int DownloadManager::numTotalDownloads() const
+{
+ return m_ActiveDownloads.size();
+}
+
+
+QString DownloadManager::getFilePath(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_OutputDirectory + "/" + m_ActiveDownloads.at(index)->m_FileName;
+}
+
+
+QString DownloadManager::getFileName(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_ActiveDownloads.at(index)->m_FileName;
+}
+
+
+int DownloadManager::getProgress(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_ActiveDownloads.at(index)->m_Progress;
+}
+
+
+DownloadManager::DownloadState DownloadManager::getState(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_ActiveDownloads.at(index)->m_State;
+}
+
+
+bool DownloadManager::isInfoIncomplete(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ DownloadInfo *info = m_ActiveDownloads.at(index);
+ return (info->m_FileID == 0) || (info->m_ModID == 0) || info->m_NexusInfo.m_Version.isEmpty();
+}
+
+
+int DownloadManager::getModID(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_ActiveDownloads.at(index)->m_ModID;
+}
+
+
+NexusInfo DownloadManager::getNexusInfo(int index) const
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+
+ return m_ActiveDownloads.at(index)->m_NexusInfo;
+}
+
+
+void DownloadManager::markInstalled(int index)
+{
+ if ((index < 0) || (index >= m_ActiveDownloads.size())) {
+ throw MyException(tr("invalid index"));
+ }
+ QSettings metaFile(QString("%1.meta").arg(m_ActiveDownloads.at(index)->m_Output.fileName()), QSettings::IniFormat);
+ metaFile.setValue("installed", true);
+
+ m_ActiveDownloads.at(index)->m_State = STATE_INSTALLED;
+}
+
+
+QString DownloadManager::getDownloadFileName(const QString &baseName) const
+{
+ QString fullPath = m_OutputDirectory + "/" + baseName;
+ if (QFile::exists(fullPath)) {
+ int i = 1;
+ while (QFile::exists(QString("%1/%2_%3").arg(m_OutputDirectory).arg(i).arg(baseName))) {
+ ++i;
+ }
+
+ fullPath = QString("%1/%2_%3").arg(m_OutputDirectory).arg(i).arg(baseName);
+ }
+ return fullPath;
+}
+
+
+QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply)
+{
+ if (reply->hasRawHeader("Content-Disposition")) {
+ std::tr1::regex exp("filename=\"(.*)\"");
+
+ std::tr1::cmatch result;
+ if (std::tr1::regex_search(reply->rawHeader("Content-Disposition").constData(), result, exp)) {
+ return QString::fromUtf8(result.str(1).c_str());
+ }
+ }
+
+ return QString();
+}
+
+
+DownloadManager::DownloadInfo *DownloadManager::findDownload(QObject *reply, int *index) const
+{
+ for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
+ if (m_ActiveDownloads[i]->m_Reply == reply) {
+ if (index != NULL) {
+ *index = i;
+ }
+ return m_ActiveDownloads[i];
+ }
+ }
+ return NULL;
+}
+
+
+void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ if (bytesTotal == 0) {
+ return;
+ }
+ int index = 0;
+
+ DownloadInfo *info = findDownload(this->sender(), &index);
+ if (info != NULL) {
+ if (info->m_State == STATE_CANCELING) {
+ info->m_Reply->abort();
+ info->m_State = STATE_CANCELED;
+ } else if (info->m_State == STATE_PAUSING) {
+ info->m_Reply->abort();
+ info->m_State = STATE_PAUSED;
+ } else {
+ info->m_Progress = ((info->m_ResumePos + bytesReceived) * 100) / (info->m_ResumePos + bytesTotal);
+ emit update(index);
+ }
+ }
+}
+
+
+void DownloadManager::downloadReadyRead()
+{
+ DownloadInfo *info = findDownload(this->sender());
+ if (info != NULL) {
+ info->m_Output.write(info->m_Reply->readAll());
+ }
+}
+
+
+void DownloadManager::createMetaFile(DownloadInfo *info)
+{
+ QSettings metaFile(QString("%1.meta").arg(info->m_Output.fileName()), QSettings::IniFormat);
+ metaFile.setValue("modID", info->m_ModID);
+ metaFile.setValue("fileID", info->m_FileID);
+ metaFile.setValue("url", info->m_Url);
+ metaFile.setValue("name", info->m_NexusInfo.m_Name);
+ metaFile.setValue("modName", info->m_NexusInfo.m_ModName);
+ metaFile.setValue("version", info->m_NexusInfo.m_Version);
+ metaFile.setValue("newestVersion", info->m_NexusInfo.m_NewestVersion);
+ metaFile.setValue("category", info->m_NexusInfo.m_Category);
+ metaFile.setValue("installed", info->m_State == DownloadManager::STATE_INSTALLED);
+ metaFile.setValue("paused", info->m_State == DownloadManager::STATE_PAUSED);
+
+ // slightly hackish...
+ for (int i = 0; i < m_ActiveDownloads.size(); ++i) {
+ if (m_ActiveDownloads[i] == info) {
+ emit update(i);
+ }
+ }
+}
+
+
+void DownloadManager::nxmDescriptionAvailable(int, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ QVariantMap result = resultData.toMap();
+
+ DownloadInfo *info = static_cast<DownloadInfo*>(userData.value<void*>());
+ info->m_NexusInfo.m_Category = result["category_id"].toInt();
+ info->m_NexusInfo.m_ModName = result["name"].toString().trimmed();
+ info->m_NexusInfo.m_NewestVersion = result["version"].toString();
+
+ if (info->m_FileID != 0) {
+ createMetaFile(info);
+ info->m_State = STATE_READY;
+ } else {
+ info->m_State = STATE_FETCHINGFILEINFO;
+ m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_ModID, this, qVariantFromValue(static_cast<void*>(info))));
+ }
+}
+
+
+void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ DownloadInfo *info = static_cast<DownloadInfo*>(userData.value<void*>());
+
+ QVariantList result = resultData.toList();
+
+ // MO sometimes prepends <digit>_ to the filename in case of duplicate downloads.
+ // this may muck up the file name comparison
+ QString alternativeLocalName = info->m_FileName;
+
+ QRegExp expression("^\\d_(.*)$");
+ if (expression.indexIn(alternativeLocalName) == 0) {
+ alternativeLocalName = expression.cap(1);
+ }
+
+ bool found = false;
+
+ foreach(QVariant file, result) {
+ QVariantMap fileInfo = file.toMap();
+ QString fileName = fileInfo["uri"].toString();
+ QString fileNameVariant = fileName.mid(0).replace(' ', '_');
+ if ((fileName == info->m_FileName) || (fileName == alternativeLocalName) ||
+ (fileNameVariant == info->m_FileName) || (fileNameVariant == alternativeLocalName)) {
+ info->m_NexusInfo.m_Name = fileInfo["name"].toString();
+ info->m_NexusInfo.m_Version = fileInfo["version"].toString();
+ info->m_NexusInfo.m_FileCategory = fileInfo["category_id"].toInt();
+ info->m_FileID = fileInfo["id"].toInt();
+ found = true;
+ break;
+ }
+ }
+
+ if ((info->m_State == STATE_READY) ||
+ (info->m_State == STATE_INSTALLED)) {
+ if (found) {
+ emit showMessage(tr("Information updated"));
+ } else if (result.count() == 0) {
+ emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?"));
+ } else {
+ SelectionDialog selection(tr("No file on Nexus matches the selected file by name. Please manually choose the correct one."));
+ foreach(QVariant file, result) {
+ QVariantMap fileInfo = file.toMap();
+ selection.addChoice(fileInfo["uri"].toString(), "", file);
+ }
+ if (selection.exec() == QDialog::Accepted) {
+ QVariantMap fileInfo = selection.getChoiceData().toMap();
+ info->m_NexusInfo.m_Name = fileInfo["name"].toString();
+ info->m_NexusInfo.m_Version = fileInfo["version"].toString();
+ info->m_NexusInfo.m_FileCategory = fileInfo["category_id"].toInt();
+ info->m_FileID = fileInfo["id"].toInt();
+ } else {
+ emit showMessage(tr("No matching file found on Nexus! Maybe this file is no longer available or it was renamed?"));
+ }
+ }
+ } else {
+ if (info->m_FileID == 0) {
+ qWarning("could not determine file id for %s", info->m_FileName.toUtf8().constData());
+ }
+
+ info->m_State = STATE_READY;
+ }
+ createMetaFile(info);
+}
+
+
+void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ NexusInfo info;
+
+ QVariantMap result = resultData.toMap();
+
+ info.m_Name = result["name"].toString();
+ info.m_Version = result["version"].toString();
+ info.m_FileName = result["uri"].toString();
+
+ m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info)));
+}
+
+
+// sort function to sort by best download server
+bool DownloadManager::ServerByPreference(const QVariant &LHS, const QVariant &RHS)
+{
+ QVariantMap LHSMap = LHS.toMap();
+ QVariantMap RHSMap = RHS.toMap();
+ int LHSUsers = LHSMap["ConnectedUsers"].toInt();
+ int RHSUsers = RHSMap["ConnectedUsers"].toInt();
+ bool LHSPremium = LHSMap["IsPremium"].toBool();
+ bool RHSPremium = RHSMap["IsPremium"].toBool();
+
+ // 0 users is probably a sign that the server is offline. Since there is currently no
+ // mechanism to try a different server, we avoid those without users
+ if ((LHSUsers == 0) && (RHSUsers != 0)) return false;
+ if ((LHSUsers != 0) && (RHSUsers == 0)) return true;
+
+
+ if (LHSPremium && !RHSPremium) {
+ return true;
+ } else if (!LHSPremium && RHSPremium) {
+ return false;
+ }
+
+ // TODO implement country preference
+
+ return LHSUsers < RHSUsers;
+}
+
+
+void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ NexusInfo info = userData.value<NexusInfo>();
+ QVariantList resultList = resultData.toList();
+ if (resultList.length() == 0) {
+ emit showMessage(tr("No download server available. Please try again later."));
+ return;
+ }
+ qSort(resultList.begin(), resultList.end(), ServerByPreference);
+
+ QVariantMap dlServer = resultList.first().toMap();
+ qDebug("picked url: %s", dlServer["URI"].toString().toUtf8().constData());
+
+
+ addDownload(dlServer["URI"].toString(), modID, fileID, info);
+}
+
+
+void DownloadManager::nxmRequestFailed(int modID, QVariant, int requestID, const QString &errorString)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ int index = 0;
+
+ for (QVector<DownloadInfo*>::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end(); ++iter, ++index) {
+ DownloadInfo *info = *iter;
+ if (info->m_ModID == modID) {
+ if (info->m_State == STATE_STARTED) {
+ m_ActiveDownloads.erase(iter);
+ delete info;
+ } else if ((info->m_State == STATE_FETCHINGFILEINFO) ||
+ (info->m_State == STATE_FETCHINGMODINFO)) {
+ info->m_State = STATE_READY;
+ }
+ emit update(index);
+ break;
+ }
+ }
+ emit showMessage(tr("Failed to request file info from nexus: %1").arg(errorString));
+}
+
+
+void DownloadManager::downloadFinished()
+{
+ int index = 0;
+
+ DownloadInfo *info = findDownload(this->sender(), &index);
+ if (info != NULL) {
+ QNetworkReply *reply = info->m_Reply;
+ QByteArray data = info->m_Reply->readAll();
+ qDebug("finished %s (%d) (%d)", info->m_FileName.toUtf8().constData(), reply->error(), info->m_State);
+ info->m_Output.write(data);
+ info->m_Output.close();
+
+ if ((info->m_State != STATE_CANCELING) &&
+ (info->m_State != STATE_PAUSING)) {
+ if ((info->m_Output.size() == 0) ||
+ (reply->error() != QNetworkReply::NoError) ||
+ reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) {
+ emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
+ info->m_State = STATE_CANCELING;
+ }
+ }
+
+ if (info->m_State == STATE_CANCELING) {
+ info->m_Reply->abort();
+ info->m_State = STATE_CANCELED;
+ } else if (info->m_State == STATE_PAUSING) {
+ info->m_Output.write(info->m_Reply->readAll());
+ info->m_Reply->abort();
+
+ info->m_State = STATE_PAUSED;
+ }
+
+ if (info->m_State == STATE_CANCELED) {
+ emit aboutToUpdate();
+ info->m_Output.remove();
+ delete info;
+ m_ActiveDownloads.erase(m_ActiveDownloads.begin() + index);
+ emit update(-1);
+ } else if (info->m_State == STATE_PAUSED) {
+ info->m_Output.close();
+ createMetaFile(info);
+ emit update(index);
+ } else {
+ info->m_State = STATE_FETCHINGMODINFO;
+ QString newName = getFileNameFromNetworkReply(reply);
+ QString oldName = QFileInfo(info->m_Output).fileName();
+ if (!newName.isEmpty() && (newName != oldName)) {
+ info->setName(getDownloadFileName(newName), true);
+ } else {
+ info->setName(m_OutputDirectory + "/" + info->m_FileName, true); // don't rename but remove the ".unfinished" extension
+ }
+
+ m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_ModID, this, qVariantFromValue(static_cast<void*>(info))));
+
+ emit update(index);
+ }
+ reply->close();
+ reply->deleteLater();
+ } else {
+ qWarning("no download index %d", index);
+ }
+}
+
+
+void DownloadManager::metaDataChanged()
+{
+ int index = 0;
+
+ DownloadInfo *info = findDownload(this->sender(), &index);
+ if (info != NULL) {
+ QString newName = getFileNameFromNetworkReply(info->m_Reply);
+ if (!newName.isEmpty() && (newName != info->m_FileName)) {
+ info->setName(getDownloadFileName(newName), true);
+ refreshAlphabeticalTranslation();
+ if (!info->m_Output.open(QIODevice::WriteOnly | QIODevice::Append)) {
+ reportError(tr("failed to re-open %1").arg(info->m_FileName));
+ info->m_State = STATE_CANCELING;
+ info->m_Reply->abort();
+ }
+ }
+ } else {
+ qWarning("meta data event for unknown download");
+ }
+}
+
+void DownloadManager::directoryChanged(const QString&)
+{
+ refreshList();
+}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h new file mode 100644 index 00000000..5376666a --- /dev/null +++ b/src/downloadmanager.h @@ -0,0 +1,339 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DOWNLOADMANAGER_H
+#define DOWNLOADMANAGER_H
+
+#include "nexusinterface.h"
+#include <set>
+#include <QObject>
+#include <QUrl>
+#include <QQueue>
+#include <QFile>
+#include <QNetworkReply>
+#include <QTime>
+#include <QVector>
+#include <QMap>
+#include <QFileSystemWatcher>
+
+
+struct NexusInfo {
+ NexusInfo() : m_Category(0), m_FileCategory(0), m_Set(false) {}
+ int m_Category;
+ int m_FileCategory;
+ QString m_Name;
+ QString m_ModName;
+ QString m_Version;
+ QString m_NewestVersion;
+ QString m_FileName;
+ bool m_Set;
+};
+Q_DECLARE_METATYPE(NexusInfo)
+
+
+/*!
+ * \brief manages downloading of files and provides progress information for gui elements
+ **/
+class DownloadManager : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ enum DownloadState {
+ STATE_STARTED = 0,
+ STATE_DOWNLOADING,
+ STATE_CANCELING,
+ STATE_PAUSING,
+ STATE_CANCELED,
+ STATE_PAUSED,
+ STATE_FETCHINGMODINFO,
+ STATE_FETCHINGFILEINFO,
+ STATE_READY,
+ STATE_INSTALLED
+ };
+
+private:
+
+ struct DownloadInfo {
+ QString m_FileName;
+ QFile m_Output;
+ QNetworkReply *m_Reply;
+ QTime m_StartTime;
+ int m_Progress;
+ int m_ModID;
+ int m_FileID;
+ NexusInfo m_NexusInfo;
+ DownloadState m_State;
+ QString m_Url;
+ qint64 m_ResumePos;
+
+ /**
+ * @brief rename the file
+ * this will change the file name as well as the display name. It will automatically
+ * append .unfinished to the name if this file is still being downloaded
+ * @param newName the new name to setName
+ * @param renameFile if true, the file is assumed to exist and renamed. If the file does not
+ * yet exist, set this to false
+ **/
+ void setName(QString newName, bool renameFile);
+ };
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param nexusInterface interface to use to retrieve information from the relevant nexus page
+ * @param parent parent object
+ **/
+ explicit DownloadManager(NexusInterface *nexusInterface, QObject *parent);
+
+ ~DownloadManager();
+
+ /**
+ * @brief determine if a download is currently in progress
+ *
+ * @return true if there is currently a download in progress
+ **/
+ bool downloadsInProgress();
+
+ /**
+ * @brief set the output directory to write to
+ *
+ * @param outputDirectory the new output directory
+ **/
+ void setOutputDirectory(const QString &outputDirectory);
+
+ /**
+ * @return current download directory
+ **/
+ QString getOutputDirectory() const { return m_OutputDirectory; }
+
+ /**
+ * @brief start a download from a url
+ *
+ * @param url the url to download from
+ * @param modID the nexus mod id this download belongs to
+ * @param fileID the nexus file id this download belongs to, if known. Defaults to 0.
+ * @param nexusInfo information previously retrieved from the nexus network
+ * @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again
+ **/
+ bool addDownload(const QUrl &url, int modID, int fileID = 0, const NexusInfo &nexusInfo = NexusInfo());
+
+ /**
+ * @brief download from an already open network connection
+ *
+ * @param reply the network reply to download from
+ * @param fileName the name to use for the file. This may be overridden by the name in the nexusInfo-structure or if the http stream specifies a name
+ * @param modID the nexus mod id this download belongs to
+ * @param fileID the nexus file id this download belongs to, if known. Defaults to 0.
+ * @param nexusInfo information previously retrieved from the nexus network
+ * @return true if the download was started, false if it wasn't. The latter currently only happens if there is a duplicate and the user decides not to download again
+ **/
+ bool addDownload(QNetworkReply *reply, const QString &fileName, int modID, int fileID = 0, const NexusInfo &nexusInfo = NexusInfo());
+
+ /**
+ * @brief start a download using a nxm-link
+ *
+ * starts a download using a nxm-link. The download manager will first query the nexus
+ * page for file information.
+ * @param url a nxm link looking like this: nxm://skyrim/mods/1234/files/4711
+ * @todo the game name encoded into the link is currently ignored, all downloads are incorrectly assumed to be for the identified game
+ **/
+ void addNXMDownload(const QString &url);
+
+ /**
+ * @brief retrieve the total number of downloads, both finished and unfinished including downloads from previous sessions
+ *
+ * @return total number of downloads
+ **/
+ int numTotalDownloads() const;
+
+ /**
+ * @brief retrieve the full path to the download specified by index
+ *
+ * @param index the index to look up
+ * @return absolute path of the file
+ **/
+ QString getFilePath(int index) const;
+
+ /**
+ * @brief retrieve the filename of the download specified by index
+ *
+ * @param index index of the file to look up
+ * @return name of the file
+ **/
+ QString getFileName(int index) const;
+
+ /**
+ * @brief retrieve the current progress of the download specified by index
+ *
+ * @param index index of the file to look up
+ * @return progress of the download in percent (integer)
+ **/
+ int getProgress(int index) const;
+
+ /**
+ * @brief retrieve the current state of the download
+ *
+ * retrieve the current state of the download. A download usually goes through
+ * the following states:
+ * started -> downloading -> fetching mod info -> fetching file info -> done
+ * in case of downloads started via nxm-link, file information is fetched first
+ *
+ * @param index index of the file to look up
+ * @return the download state
+ **/
+ DownloadState getState(int index) const;
+
+ /**
+ * @param index index of the file to look up
+ * @return true if the nexus information for this download is not complete
+ **/
+ bool isInfoIncomplete(int index) const;
+
+ /**
+ * @brief retrieve the nexus mod id of the download specified by index
+ *
+ * @param index index of the file to look up
+ * @return the nexus mod id
+ **/
+ int getModID(int index) const;
+
+ /**
+ * @brief retrieve all nexus info of the download specified by index
+ *
+ * @param index index of the file to look up
+ * @return the nexus mod information
+ **/
+ NexusInfo getNexusInfo(int index) const;
+
+ /**
+ * @brief mark a download as installed
+ *
+ * @param index index of the file to mark installed
+ */
+ void markInstalled(int index);
+
+ /**
+ * @brief refreshes the list of downloads
+ */
+ void refreshList();
+
+ /**
+ * @brief Sort function for download servers
+ * @param LHS
+ * @param RHS
+ * @return
+ */
+ static bool ServerByPreference(const QVariant &LHS, const QVariant &RHS);
+
+signals:
+
+ void aboutToUpdate();
+
+ /**
+ * @brief signals that the specified download has changed
+ *
+ * @param row the row that changed. This corresponds to the download index
+ **/
+ void update(int row);
+
+ /**
+ * @brief signals the ui that a message should be displayed
+ *
+ * @param message the message to display
+ **/
+ void showMessage(const QString &message);
+
+public slots:
+
+ /**
+ * @brief removes the specified download
+ *
+ * @param index index of the download to remove
+ * @param deleteFile if true, the file will also be deleted from disc, otherwise it is only marked as hidden.
+ **/
+ void removeDownload(int index, bool deleteFile);
+
+ /**
+ * @brief cancel the specified download. This will lead to the corresponding file to be deleted
+ *
+ * @param index index of the download to cancel
+ **/
+ void cancelDownload(int index);
+
+ void pauseDownload(int index);
+
+ void resumeDownload(int index);
+
+ void queryInfo(int index);
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+
+ void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+
+ void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+
+ void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+
+ void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorString);
+
+private slots:
+
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void downloadReadyRead();
+ void downloadFinished();
+ void metaDataChanged();
+ void directoryChanged(const QString &dirctory);
+
+private:
+
+ void createMetaFile(DownloadInfo *info);
+// QString getOutputPath(const QUrl &url, const QString &fileName) const;
+ QString getDownloadFileName(const QString &baseName) const;
+
+ void addDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume);
+
+ // important: the caller has to lock the list-mutex, otherwise the DownloadInfo-pointer might get invalidated at any time
+ DownloadInfo *findDownload(QObject *reply, int *index = NULL) const;
+
+ void removeFile(int index, bool deleteFile);
+
+ void refreshAlphabeticalTranslation();
+
+ bool ByName(int LHS, int RHS);
+
+ QString getFileNameFromNetworkReply(QNetworkReply *reply);
+
+private:
+
+ NexusInterface *m_NexusInterface;
+ QVector<DownloadInfo*> m_ActiveDownloads;
+
+ QString m_OutputDirectory;
+ std::set<int> m_RequestIDs;
+ QVector<int> m_AlphabeticalTranslation;
+
+ QFileSystemWatcher m_DirWatcher;
+
+};
+
+#endif // DOWNLOADMANAGER_H
diff --git a/src/dummybsa.cpp b/src/dummybsa.cpp new file mode 100644 index 00000000..8383a6ad --- /dev/null +++ b/src/dummybsa.cpp @@ -0,0 +1,244 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "dummybsa.h"
+#include <QFile>
+#include <gameinfo.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+
+static void writeUlong(unsigned char* buffer, int offset, unsigned long value)
+{
+ union {
+ unsigned long ulValue;
+ unsigned char cValue[4];
+ };
+ ulValue = value;
+ memcpy(buffer + offset, cValue, 4);
+}
+
+static void writeUlonglong(unsigned char* buffer, int offset, unsigned long long value)
+{
+ union {
+ unsigned long long ullValue;
+ unsigned char cValue[8];
+ };
+ ullValue = value;
+ memcpy(buffer + offset, cValue, 8);
+}
+/*
+static unsigned long long genHashInt(const char* pos, const char* end)
+{
+ unsigned long long hash2 = 0;
+ for (; pos < end; ++pos) {
+ hash2 *= 0x1003f;
+ hash2 += *pos;
+ }
+ return hash2;
+}
+
+
+static unsigned long long genHash(const char* fileName)
+{
+ char fileNameLower[MAX_PATH + 1];
+ int i = 0;
+ for (; i < MAX_PATH && fileName[i] != '\0'; ++i) {
+ fileNameLower[i] = tolower(fileName[i]);
+ }
+ fileNameLower[i] = '\0';
+
+ char* ext = strrchr(fileNameLower, '.');
+ if (ext == NULL) {
+ ext = fileNameLower + strlen(fileNameLower);
+ }
+
+ int length = ext - fileNameLower;
+
+ unsigned long long hash = 0ULL;
+
+ if (length > 0) {
+ hash = *(ext - 1) |
+ ((length > 2 ? *(ext - 2) : 0) << 8) |
+ (length << 16) |
+ (fileNameLower[0] << 24);
+ }
+
+ if (strcmp(ext + 1, "dds") == 0) {
+ hash |= 0x8080;
+ } // the rest is not supported currently
+
+ hash |= genHashInt(fileNameLower + 1, ext - 2) << 0x32;
+ hash |= genHashInt(ext, ext + strlen(ext)) << 0x32;
+
+ return hash;
+}*/
+
+
+static unsigned long genHashInt(const unsigned char *pos, const unsigned char *end)
+{
+ unsigned long hash = 0;
+ for (; pos < end; ++pos) {
+ hash *= 0x1003f;
+ hash += *pos;
+ }
+ return hash;
+}
+
+
+static unsigned long long genHash(const char* fileName)
+{
+ char fileNameLower[MAX_PATH + 1];
+ int i = 0;
+ for (; i < MAX_PATH && fileName[i] != '\0'; ++i) {
+ fileNameLower[i] = static_cast<char>(tolower(fileName[i]));
+ if (fileNameLower[i] == '\\') {
+ fileNameLower[i] = '/';
+ }
+ }
+ fileNameLower[i] = '\0';
+
+ unsigned char *fileNameLowerU = reinterpret_cast<unsigned char*>(fileNameLower);
+
+ char* ext = strrchr(fileNameLower, '.');
+ if (ext == NULL) {
+ ext = fileNameLower + strlen(fileNameLower);
+ }
+ unsigned char *extU = reinterpret_cast<unsigned char*>(ext);
+
+ int length = ext - fileNameLower;
+
+ unsigned long long hash = 0ULL;
+
+ if (length > 0) {
+ hash = *(extU - 1) |
+ ((length > 2 ? *(ext - 2) : 0) << 8) |
+ (length << 16) |
+ (fileNameLowerU[0] << 24);
+ }
+
+ if (strlen(ext) > 0) {
+ if (strcmp(ext + 1, "kf") == 0) {
+ hash |= 0x80;
+ } else if (strcmp(ext + 1, "nif") == 0) {
+ hash |= 0x8000;
+ } else if (strcmp(ext + 1, "dds") == 0) {
+ hash |= 0x8080;
+ } else if (strcmp(ext + 1, "wav") == 0) {
+ hash |= 0x80000000;
+ }
+
+ unsigned long long temp = static_cast<unsigned long long>(genHashInt(
+ fileNameLowerU + 1, extU - 2));
+ temp += static_cast<unsigned long long>(genHashInt(
+ extU, extU + strlen(ext)));
+
+ hash |= (temp & 0xFFFFFFFF) << 32;
+ }
+ return hash;
+}
+
+
+DummyBSA::DummyBSA()
+ : m_Version(GameInfo::instance().getBSAVersion()), m_FolderName(""), m_FileName("dummy.dds"),
+ m_TotalFileNameLength(0)
+{
+}
+
+
+void DummyBSA::writeHeader(QFile& file)
+{
+ unsigned char header[] = {
+ 'B', 'S', 'A', '\0', // magic string
+ 0xDE, 0xAD, 0xBE, 0xEF, // version - insert later
+ 0x24, 0x00, 0x00, 0x00, // offset to folder recors. header size is static
+ 0xDE, 0xAD, 0xBE, 0xEF, // archive flags - insert later
+ 0x01, 0x00, 0x00, 0x00, // folder count
+ 0x01, 0x00, 0x00, 0x00, // file count
+ 0xDE, 0xAD, 0xBE, 0xEF, // total folder names length - insert later
+ 0xDE, 0xAD, 0xBE, 0xEF, // total file names length - insert later
+ 0xDE, 0xAD, 0xBE, 0xEF // file flags - insert later
+ };
+
+ writeUlong(header, 4, GameInfo::instance().getBSAVersion());
+ writeUlong(header, 12, 0x01 | 0x02); // has directories and has files.
+ writeUlong(header, 24, m_FolderName.length() + 1); // empty folder name
+ writeUlong(header, 28, m_TotalFileNameLength); // single character file name
+
+ writeUlong(header, 32, 2); // has dds
+
+ file.write(reinterpret_cast<char*>(header), sizeof(header));
+}
+
+
+void DummyBSA::writeFolderRecord(QFile& file, const std::string& folderName)
+{
+ unsigned char folderRecord[] = {
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // folder hash
+ 0x01, 0x00, 0x00, 0x00, // file count
+ 0xDE, 0xAD, 0xBE, 0xEF, // offset to folder name
+ };
+ // we'd usually have to sort folders be the hash value generated here
+ writeUlonglong(folderRecord, 0, genHash(folderName.c_str()));
+ writeUlong( folderRecord, 12, 0x34 + m_TotalFileNameLength); // TODO: this should be calculated properly
+
+ file.write(reinterpret_cast<char*>(folderRecord), sizeof(folderRecord));
+}
+
+
+void DummyBSA::writeFileRecord(QFile& file, const std::string& fileName)
+{
+ unsigned char fileRecord[] = {
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // file name hash
+ 0xDE, 0xAD, 0xBE, 0xEF, // size
+ 0xDE, 0xAD, 0xBE, 0xEF, // offset to file data
+ };
+
+ // we'd usually have to sort files by the value generated here
+ writeUlonglong(fileRecord, 0, genHash(fileName.c_str()));
+ writeUlong( fileRecord, 8, 0);
+ writeUlong( fileRecord, 12, 0x44 + (fileName.length() + 1) + 4); // after this record we expect the filename and 4 bytes of file size
+
+ file.write(reinterpret_cast<char*>(fileRecord), sizeof(fileRecord));
+}
+
+
+void DummyBSA::writeFileRecordBlocks(QFile& file, const std::string& folderName)
+{
+ file.write(folderName.c_str(), folderName.length() + 1);
+
+ writeFileRecord(file, m_FileName);
+}
+
+
+void DummyBSA::write(const QString& fileName)
+{
+ QFile file(fileName);
+ file.open(QIODevice::WriteOnly);
+
+ m_TotalFileNameLength = m_FileName.length() + 1;
+
+ writeHeader(file);
+ writeFolderRecord(file, m_FolderName);
+ writeFileRecordBlocks(file, m_FolderName);
+ file.write(m_FileName.c_str() , m_FileName.length() + 1);
+ char fileSize[] = { 0x00, 0x00, 0x00, 0x00 };
+ file.write(fileSize, sizeof(fileSize));
+ file.close();
+}
diff --git a/src/dummybsa.h b/src/dummybsa.h new file mode 100644 index 00000000..6fcea82b --- /dev/null +++ b/src/dummybsa.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DUMMYBSA_H
+#define DUMMYBSA_H
+
+#include <QString>
+#include <QFile>
+
+/**
+ * @brief Class for creating a dummy bsa used for archive invalidation
+ **/
+class DummyBSA
+{
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ **/
+ DummyBSA();
+
+ /**
+ * @brief write to the specified file
+ *
+ * @param fileName name of the file to write to
+ **/
+ void write(const QString& fileName);
+
+private:
+
+ void writeHeader(QFile& file);
+ void writeFolderRecord(QFile& file, const std::string& folderName);
+ void writeFileRecord(QFile& file, const std::string& fileName);
+ void writeFileRecordBlocks(QFile& file, const std::string& folderName);
+
+private:
+
+ unsigned long m_Version;
+ std::string m_FolderName;
+ std::string m_FileName;
+ unsigned long m_TotalFileNameLength;
+
+};
+
+
+#endif // DUMMYBSA_H
diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp new file mode 100644 index 00000000..a364c65d --- /dev/null +++ b/src/editexecutablesdialog.cpp @@ -0,0 +1,194 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "editexecutablesdialog.h" +#include "ui_editexecutablesdialog.h" +#include "filedialogmemory.h" +#include <QMessageBox> + + +EditExecutablesDialog::EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent) + : TutorableDialog("EditExecutables", parent), + ui(new Ui::EditExecutablesDialog), m_ExecutablesList(executablesList) +{ + ui->setupUi(this); + + refreshExecutablesWidget(); +} + +EditExecutablesDialog::~EditExecutablesDialog() +{ + delete ui; +} + +ExecutablesList EditExecutablesDialog::getExecutablesList() const +{ + ExecutablesList newList; + for (int i = 0; i < ui->executablesListBox->count(); ++i) { + newList.addExecutable(ui->executablesListBox->item(i)->data(Qt::UserRole).value<Executable>()); + } + return newList; +} + +void EditExecutablesDialog::refreshExecutablesWidget() +{ + QListWidget *executablesWidget = findChild<QListWidget*>("executablesListBox"); + + executablesWidget->clear(); + std::vector<Executable>::const_iterator current, end; + m_ExecutablesList.getExecutables(current, end); + + for(; current != end; ++current) { + QListWidgetItem *newItem = new QListWidgetItem(current->m_Title); + QVariant temp; + temp.setValue(*current); + newItem->setData(Qt::UserRole, temp); + newItem->setTextColor(current->m_Custom ? QColor(Qt::black) : QColor(Qt::darkGray)); + executablesWidget->addItem(newItem); + } + + QPushButton *addButton = findChild<QPushButton*>("addButton"); + QPushButton *removeButton = findChild<QPushButton*>("removeButton"); + + addButton->setEnabled(false); + removeButton->setEnabled(false); +} + + +void EditExecutablesDialog::on_binaryEdit_textChanged(const QString &arg1) +{ + QPushButton *addButton = findChild<QPushButton*>("addButton"); +// QPushButton *removeButton = findChild<QPushButton*>("removeButton"); + + QFileInfo fileInfo(arg1); + addButton->setEnabled(fileInfo.exists() && fileInfo.isFile()); +} + +void EditExecutablesDialog::resetInput() +{ + ui->binaryEdit->setText(""); + ui->titleEdit->setText(""); + ui->argumentsEdit->setText(""); + ui->closeCheckBox->setChecked(false); +} + + +void EditExecutablesDialog::on_addButton_clicked() +{ + QLineEdit *titleEdit = findChild<QLineEdit*>("titleEdit"); + QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit"); + QLineEdit *argumentsEdit = findChild<QLineEdit*>("argumentsEdit"); + QLineEdit *workingDirEdit = findChild<QLineEdit*>("workingDirEdit"); + QCheckBox *closeCheckBox = findChild<QCheckBox*>("closeCheckBox"); + + m_ExecutablesList.addExecutable(titleEdit->text(), QDir::fromNativeSeparators(binaryEdit->text()), + argumentsEdit->text(), QDir::fromNativeSeparators(workingDirEdit->text()), + (closeCheckBox->checkState() == Qt::Checked) ? DEFAULT_CLOSE : DEFAULT_STAY, + ui->overwriteAppIDBox->isChecked() ? ui->appIDOverwriteEdit->text() : ""); + + resetInput(); + refreshExecutablesWidget(); +} + +void EditExecutablesDialog::on_browseButton_clicked() +{ + QString binaryName = FileDialogMemory::getOpenFileName("editExecutableBinary", this, + tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat")); + + QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit"); + + binaryEdit->setText(QDir::toNativeSeparators(binaryName)); +} + +void EditExecutablesDialog::on_browseDirButton_clicked() +{ + QString dirName = FileDialogMemory::getExistingDirectory("editExecutableDirectory", this, + tr("Select a directory")); + + ui->workingDirEdit->setText(dirName); +} + +void EditExecutablesDialog::on_removeButton_clicked() +{ +// QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit"); + + if (QMessageBox::question(this, tr("Confirm"), tr("Really remove \"%1\" from executables?").arg(ui->titleEdit->text()), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + m_ExecutablesList.remove(ui->titleEdit->text()); + } + + resetInput(); + refreshExecutablesWidget(); +} + +void EditExecutablesDialog::on_titleEdit_textChanged(const QString &arg1) +{ + QPushButton *addButton = findChild<QPushButton*>("addButton"); + QPushButton *removeButton = findChild<QPushButton*>("removeButton"); + + QListWidget *executablesWidget = findChild<QListWidget*>("executablesListBox"); + + QList<QListWidgetItem*> existingItems = executablesWidget->findItems(arg1, Qt::MatchFixedString); + + addButton->setEnabled(arg1.length() != 0); + + if (existingItems.count() == 0) { + addButton->setText(tr("Add")); + removeButton->setEnabled(false); + } else { + // existing item. is it a custom one? + addButton->setText(tr("Modify")); + removeButton->setEnabled(true); + } +} + +void EditExecutablesDialog::on_executablesListBox_itemClicked(QListWidgetItem *item) +{ + QLineEdit *titleEdit = findChild<QLineEdit*>("titleEdit"); + QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit"); + QLineEdit *argumentsEdit = findChild<QLineEdit*>("argumentsEdit"); + QLineEdit *workingDirEdit = findChild<QLineEdit*>("workingDirEdit"); + QPushButton *removeButton = findChild<QPushButton*>("removeButton"); + QCheckBox *closeCheckBox = findChild<QCheckBox*>("closeCheckBox"); + + const Executable &selectedExecutable = item->data(Qt::UserRole).value<Executable>(); + + titleEdit->setText(selectedExecutable.m_Title); + binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath())); + argumentsEdit->setText(selectedExecutable.m_Arguments); + workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_WorkingDirectory)); + closeCheckBox->setChecked(selectedExecutable.m_CloseMO == DEFAULT_CLOSE); + if (selectedExecutable.m_CloseMO == NEVER_CLOSE) { + closeCheckBox->setEnabled(false); + closeCheckBox->setToolTip(tr("MO must be kept running or this application will not work correctly.")); + } else { + closeCheckBox->setEnabled(true); + closeCheckBox->setToolTip(tr("If checked, MO will be closed once the specified executable is run.")); + } + removeButton->setEnabled(selectedExecutable.m_Custom); + ui->overwriteAppIDBox->setChecked(selectedExecutable.m_SteamAppID != 0); + if (selectedExecutable.m_SteamAppID != 0) { + ui->appIDOverwriteEdit->setText(selectedExecutable.m_SteamAppID); + } +} + +void EditExecutablesDialog::on_overwriteAppIDBox_toggled(bool checked) +{ + ui->appIDOverwriteEdit->setEnabled(checked); +} diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h new file mode 100644 index 00000000..fad72dfd --- /dev/null +++ b/src/editexecutablesdialog.h @@ -0,0 +1,86 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef EDITEXECUTABLESDIALOG_H
+#define EDITEXECUTABLESDIALOG_H
+
+#include "tutorabledialog.h"
+#include <QListWidgetItem>
+#include "executableslist.h"
+
+namespace Ui {
+ class EditExecutablesDialog;
+}
+
+/**
+ * @brief Dialog to manage the list of executables
+ **/
+class EditExecutablesDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param executablesList current list of executables
+ * @param parent parent widget
+ **/
+ explicit EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent = 0);
+
+ ~EditExecutablesDialog();
+
+ /**
+ * @brief retrieve the updated list of executables
+ *
+ * @return updated list of executables
+ **/
+ ExecutablesList getExecutablesList() const;
+
+private slots:
+
+ void on_binaryEdit_textChanged(const QString &arg1);
+
+ void on_addButton_clicked();
+
+ void on_browseButton_clicked();
+
+ void on_removeButton_clicked();
+
+ void on_titleEdit_textChanged(const QString &arg1);
+
+ void on_executablesListBox_itemClicked(QListWidgetItem *item);
+
+ void on_overwriteAppIDBox_toggled(bool checked);
+
+ void on_browseDirButton_clicked();
+
+private:
+
+ void resetInput();
+
+ void refreshExecutablesWidget();
+
+private:
+ Ui::EditExecutablesDialog *ui;
+ ExecutablesList m_ExecutablesList;
+};
+
+#endif // EDITEXECUTABLESDIALOG_H
diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui new file mode 100644 index 00000000..b417452a --- /dev/null +++ b/src/editexecutablesdialog.ui @@ -0,0 +1,262 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditExecutablesDialog</class>
+ <widget class="QDialog" name="EditExecutablesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>384</width>
+ <height>362</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Modify Executables</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QListWidget" name="executablesListBox">
+ <property name="toolTip">
+ <string>List of configured executables</string>
+ </property>
+ <property name="whatsThis">
+ <string>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</string>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Title</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="titleEdit">
+ <property name="toolTip">
+ <string>Name of the executable. This is only for display purposes.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Name of the executable. This is only for display purposes.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Binary</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="binaryEdit">
+ <property name="toolTip">
+ <string>Binary to run</string>
+ </property>
+ <property name="whatsThis">
+ <string>Binary to run</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="browseButton">
+ <property name="toolTip">
+ <string>Browse filesystem</string>
+ </property>
+ <property name="whatsThis">
+ <string>Browse filesystem for the executable to run.</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Start in</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="workingDirEdit"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="browseDirButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Arguments</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="argumentsEdit">
+ <property name="toolTip">
+ <string>Arguments to pass to the application</string>
+ </property>
+ <property name="whatsThis">
+ <string>Arguments to pass to the application</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QCheckBox" name="overwriteAppIDBox">
+ <property name="toolTip">
+ <string>Allow the Steam AppID to be used for this executable to be changed.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Allow the Steam AppID to be used for this executable to be changed.
+Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game.
+Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</string>
+ </property>
+ <property name="text">
+ <string>Overwrite Steam AppID</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="appIDOverwriteEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Steam AppID to use for this executable that differs from the games AppID.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Steam AppID to use for this executable that differs from the games AppID.
+Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850).
+Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="closeCheckBox">
+ <property name="toolTip">
+ <string>If checked, MO will be closed once the specified executable is run.</string>
+ </property>
+ <property name="whatsThis">
+ <string>If checked, MO will be closed once the specified executable is run.</string>
+ </property>
+ <property name="text">
+ <string>Close MO when started</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="toolTip">
+ <string>Add an executable</string>
+ </property>
+ <property name="whatsThis">
+ <string>Add an executable</string>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/new/guiresources/resources/list-add.png</normaloff>:/new/guiresources/resources/list-add.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="toolTip">
+ <string>Remove the selected executable</string>
+ </property>
+ <property name="whatsThis">
+ <string>Remove the selected executable</string>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/new/guiresources/resources/list-remove.png</normaloff>:/new/guiresources/resources/list-remove.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>EditExecutablesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>EditExecutablesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/executableslist.cpp b/src/executableslist.cpp new file mode 100644 index 00000000..ed66d8f4 --- /dev/null +++ b/src/executableslist.cpp @@ -0,0 +1,194 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "executableslist.h"
+#include <gameinfo.h>
+#include <QFileInfo>
+#include <QDir>
+#include "utility.h"
+#include <algorithm>
+
+
+QDataStream &operator<<(QDataStream &out, const Executable &obj)
+{
+ out << obj.m_Title << obj.m_BinaryInfo.absoluteFilePath() << obj.m_Arguments << obj.m_CloseMO
+ << obj.m_SteamAppID << obj.m_WorkingDirectory << obj.m_Custom;
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, Executable &obj)
+{
+ QString binaryTemp;
+ int closeStyleTemp;
+ in >> obj.m_Title >> binaryTemp >> obj.m_Arguments >> closeStyleTemp
+ >> obj.m_SteamAppID >> obj.m_WorkingDirectory >> obj.m_Custom;
+ obj.m_CloseMO = (CloseMOStyle)closeStyleTemp;
+ obj.m_BinaryInfo.setFile(binaryTemp);
+ return in;
+}
+
+
+void registerExecutable()
+{
+ qRegisterMetaType<Executable>("Executable");
+ qRegisterMetaTypeStreamOperators<Executable>("Executable");
+}
+
+
+ExecutablesList::ExecutablesList()
+{
+}
+
+ExecutablesList::~ExecutablesList()
+{
+}
+
+void ExecutablesList::init()
+{
+ std::vector<ExecutableInfo> executables = GameInfo::instance().getExecutables();
+ for (std::vector<ExecutableInfo>::const_iterator iter = executables.begin(); iter != executables.end(); ++iter) {
+ ExecutableInfo test = *iter;
+ addExecutableInternal(ToQString(iter->title),
+ QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())).append("/").append(ToQString(iter->binary)),
+ ToQString(iter->arguments), ToQString(iter->workingDirectory),
+ iter->closeMO, ToQString(iter->steamAppID));
+ }
+}
+
+
+void ExecutablesList::getExecutables(std::vector<Executable>::iterator &begin, std::vector<Executable>::iterator &end)
+{
+ begin = m_Executables.begin();
+ end = m_Executables.end();
+}
+
+
+void ExecutablesList::getExecutables(std::vector<Executable>::const_iterator &begin,
+ std::vector<Executable>::const_iterator &end) const
+{
+ begin = m_Executables.begin();
+ end = m_Executables.end();
+}
+
+
+const Executable &ExecutablesList::find(const QString &title) const
+{
+ for (std::vector<Executable>::const_iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
+ if (iter->m_Title == title) {
+ return *iter;
+ }
+ }
+ throw std::runtime_error("invalid name");
+}
+
+
+Executable *ExecutablesList::findExe(const QString &title)
+{
+ for (std::vector<Executable>::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
+ if (iter->m_Title == title) {
+ return &*iter;
+ }
+ }
+ return NULL;
+}
+
+
+bool ExecutablesList::titleExists(const QString &title) const
+{
+ auto test = [&] (const Executable &exe) { return exe.m_Title == title; };
+ return std::find_if(m_Executables.begin(), m_Executables.end(), test) != m_Executables.end();
+}
+
+
+void ExecutablesList::addExecutable(const Executable &executable)
+{
+ Executable *existingExe = findExe(executable.m_Title);
+ if (existingExe != NULL) {
+ *existingExe = executable;
+ } else {
+ m_Executables.push_back(executable);
+ }
+}
+
+
+void ExecutablesList::addExecutable(const QString &title, const QString &executableName, const QString &arguments,
+ const QString &workingDirectory, CloseMOStyle closeMO, const QString &steamAppID)
+{
+ QFileInfo file(executableName);
+ Executable *existingExe = findExe(title);
+ if (existingExe != NULL) {
+ existingExe->m_Title = title;
+ existingExe->m_CloseMO = closeMO;
+ existingExe->m_BinaryInfo = file;
+ existingExe->m_Arguments = arguments;
+ existingExe->m_WorkingDirectory = workingDirectory;
+ existingExe->m_SteamAppID = steamAppID;
+ existingExe->m_Custom = true;
+ } else {
+ Executable newExe;
+ newExe.m_Title = title;
+ newExe.m_CloseMO = closeMO;
+ newExe.m_BinaryInfo = file;
+ newExe.m_Arguments = arguments;
+ newExe.m_WorkingDirectory = workingDirectory;
+ newExe.m_SteamAppID = steamAppID;
+ newExe.m_Custom = true;
+ m_Executables.push_back(newExe);
+ }
+}
+
+/*void ExecutablesList::remove(const QString &executableName)
+{
+ for (std::vector<Executable>::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
+ if (iter->m_Custom && (iter->m_BinaryInfo.absoluteFilePath() == executableName)) {
+ m_Executables.erase(iter);
+ break;
+ }
+ }
+}*/
+
+
+void ExecutablesList::remove(const QString &title)
+{
+ for (std::vector<Executable>::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
+ if (iter->m_Custom && (iter->m_Title == title)) {
+ m_Executables.erase(iter);
+ break;
+ }
+ }
+}
+
+
+void ExecutablesList::addExecutableInternal(const QString &title, const QString &executableName,
+ const QString &arguments, const QString &workingDirectory,
+ CloseMOStyle closeMO, const QString &steamAppID)
+{
+ QFileInfo file(executableName);
+ if (file.exists()) {
+ Executable newExe;
+ newExe.m_CloseMO = closeMO;
+ newExe.m_BinaryInfo = file;
+ newExe.m_Title = title;
+ newExe.m_Arguments = arguments;
+ newExe.m_WorkingDirectory = workingDirectory;
+ newExe.m_SteamAppID = steamAppID;
+ newExe.m_Custom = false;
+ m_Executables.push_back(newExe);
+ }
+}
diff --git a/src/executableslist.h b/src/executableslist.h new file mode 100644 index 00000000..6a7d36eb --- /dev/null +++ b/src/executableslist.h @@ -0,0 +1,145 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef EXECUTABLESLIST_H
+#define EXECUTABLESLIST_H
+
+
+#include <vector>
+#include <QFileInfo>
+#include <QMetaType>
+#include <gameinfo.h>
+
+
+/*!
+ * @brief Information about an executable
+ **/
+struct Executable {
+ QString m_Title;
+ QFileInfo m_BinaryInfo;
+ QString m_Arguments;
+ CloseMOStyle m_CloseMO;
+ QString m_SteamAppID;
+ QString m_WorkingDirectory;
+
+ bool m_Custom;
+};
+Q_DECLARE_METATYPE(Executable)
+
+
+void registerExecutable();
+
+
+/*!
+ * @brief List of executables configured to by started from MO
+ **/
+class ExecutablesList {
+public:
+
+ /**
+ * @brief constructor
+ *
+ **/
+ ExecutablesList();
+
+ ~ExecutablesList();
+
+ /**
+ * @brief initialise the list with the executables preconfigured for this game
+ **/
+ void init();
+
+ /**
+ * @brief retrieve an executable by index
+ *
+ * @param index index of the executable to look up
+ * @return reference to the executable
+ * @exception out_of_range will throw an exception if the index is invalid
+ **/
+ const Executable &get(int index) const { return m_Executables.at(index); }
+
+ /**
+ * @brief find an executable by its name
+ *
+ * @param title the title of the executable to look up
+ * @return the executable
+ * @exception runtime_error will throw an exception if the name is not correct
+ **/
+ const Executable &find(const QString &tilte) const;
+
+ /**
+ * @brief determine if an executable exists
+ * @param title the title of the executable to look up
+ * @return true if the executable exists, false otherwise
+ **/
+ bool titleExists(const QString &title) const;
+
+ /**
+ * @brief add a new executable to the list
+ * @param executable
+ */
+ void addExecutable(const Executable &executable);
+
+ /**
+ * @brief add a new executable to the list
+ *
+ * @param title name displayed in the UI
+ * @param executableName the actual filename to execute
+ * @param arguments arguments to pass to the executable
+ * @param closeMO if true, MO will be closed when the binary is started
+ **/
+ void addExecutable(const QString &title, const QString &executableName, const QString &arguments, const QString &workingDirectory, CloseMOStyle closeMO, const QString &steamAppID);
+
+ /**
+ * @brief remove the executable with the specified file name. This needs to be an absolute file path
+ *
+ * @param title title of the executable to remove
+ * @note if the executable name is invalid, nothing happens. There is no way to determine if this was successful
+ **/
+ void remove(const QString &title);
+
+ /**
+ * @brief retrieve begin and end iterators of the configured executables
+ *
+ * @param begin iterator to the first executable
+ * @param end iterator one past the last executable
+ **/
+ void getExecutables(std::vector<Executable>::const_iterator &begin, std::vector<Executable>::const_iterator &end) const;
+
+ /**
+ * @brief retrieve begin and end iterators of the configured executables
+ *
+ * @param begin iterator to the first executable
+ * @param end iterator one past the last executable
+ **/
+ void getExecutables(std::vector<Executable>::iterator &begin, std::vector<Executable>::iterator &end);
+
+private:
+
+ Executable *findExe(const QString &title);
+
+ void addExecutableInternal(const QString &title, const QString &executableName, const QString &arguments, const QString &workingDirectory, CloseMOStyle closeMO, const QString &steamAppID);
+
+private:
+
+ std::vector<Executable> m_Executables;
+
+};
+
+#endif // EXECUTABLESLIST_H
diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp new file mode 100644 index 00000000..86bf22c3 --- /dev/null +++ b/src/filedialogmemory.cpp @@ -0,0 +1,94 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "filedialogmemory.h"
+#include <QFileDialog>
+
+
+FileDialogMemory::FileDialogMemory()
+{
+}
+
+
+void FileDialogMemory::save(QSettings &settings)
+{
+ settings.remove("recentDirectories");
+ settings.beginWriteArray("recentDirectories");
+ int index = 0;
+ for (std::map<QString, QString>::const_iterator iter = instance().m_Cache.begin();
+ iter != instance().m_Cache.end(); ++iter) {
+ settings.setArrayIndex(index++);
+ settings.setValue("name", iter->first);
+ settings.setValue("directory", iter->second);
+ }
+ settings.endArray();
+}
+
+
+void FileDialogMemory::restore(QSettings &settings)
+{
+ int size = settings.beginReadArray("recentDirectories");
+ for (int i = 0; i < size; ++i) {
+ settings.setArrayIndex(i);
+ QVariant name = settings.value("name");
+ QVariant dir = settings.value("directory");
+ if (name.isValid() && dir.isValid()) {
+ instance().m_Cache.insert(std::make_pair(name.toString(), dir.toString()));
+ }
+ }
+ settings.endArray();
+}
+
+
+QString FileDialogMemory::getOpenFileName(const QString &dirID, QWidget *parent,
+ const QString &caption, const QString &dir,
+ const QString &filter, QString *selectedFilter,
+ QFileDialog::Options options)
+{
+ std::pair<std::map<QString, QString>::iterator, bool> currentDir =
+ instance().m_Cache.insert(std::make_pair(dirID, dir));
+
+ QString result = QFileDialog::getOpenFileName(parent, caption, currentDir.first->second,
+ filter, selectedFilter, options);
+ if (!result.isNull()) {
+ instance().m_Cache[dirID] = QFileInfo(result).path();
+ }
+ return result;
+}
+
+
+QString FileDialogMemory::getExistingDirectory(const QString &dirID, QWidget *parent,
+ const QString &caption, const QString &dir, QFileDialog::Options options)
+{
+ std::pair<std::map<QString, QString>::iterator, bool> currentDir =
+ instance().m_Cache.insert(std::make_pair(dirID, dir));
+
+ QString result = QFileDialog::getExistingDirectory(parent, caption, currentDir.first->second, options);
+ if (!result.isNull()) {
+ instance().m_Cache[dirID] = QFileInfo(result).path();
+ }
+ return result;
+}
+
+
+FileDialogMemory &FileDialogMemory::instance()
+{
+ static FileDialogMemory instance;
+ return instance;
+}
diff --git a/src/filedialogmemory.h b/src/filedialogmemory.h new file mode 100644 index 00000000..e17d83d6 --- /dev/null +++ b/src/filedialogmemory.h @@ -0,0 +1,58 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef FILEDIALOGMEMORY_H
+#define FILEDIALOGMEMORY_H
+
+
+#include <map>
+#include <QString>
+#include <QSettings>
+#include <QFileDialog>
+
+
+class FileDialogMemory
+{
+
+public:
+
+ static void save(QSettings &settings);
+ static void restore(QSettings &settings);
+
+ static QString getOpenFileName(const QString &dirID, QWidget *parent = 0, const QString &caption = QString(),
+ const QString &dir = QString(), const QString &filter = QString(),
+ QString *selectedFilter = 0, QFileDialog::Options options = 0);
+
+ static QString getExistingDirectory(const QString &dirID, QWidget *parent = 0, const QString &caption = QString(),
+ const QString &dir = QString(),
+ QFileDialog::Options options = QFileDialog::ShowDirsOnly);
+
+private:
+
+ FileDialogMemory();
+
+ static FileDialogMemory &instance();
+
+private:
+
+ std::map<QString, QString> m_Cache;
+
+};
+
+#endif // FILEDIALOGMEMORY_H
diff --git a/src/finddialog.cpp b/src/finddialog.cpp new file mode 100644 index 00000000..58b70ade --- /dev/null +++ b/src/finddialog.cpp @@ -0,0 +1,48 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "finddialog.h"
+#include "ui_finddialog.h"
+
+FindDialog::FindDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::FindDialog)
+{
+ ui->setupUi(this);
+}
+
+FindDialog::~FindDialog()
+{
+ delete ui;
+}
+
+void FindDialog::on_nextBtn_clicked()
+{
+ emit findNext();
+}
+
+void FindDialog::on_patternEdit_textChanged(const QString &pattern)
+{
+ emit patternChanged(pattern);
+}
+
+void FindDialog::on_closeBtn_clicked()
+{
+ this->close();
+}
diff --git a/src/finddialog.h b/src/finddialog.h new file mode 100644 index 00000000..70493654 --- /dev/null +++ b/src/finddialog.h @@ -0,0 +1,73 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef FINDDIALOG_H
+#define FINDDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class FindDialog;
+}
+
+/**
+ * @brief Find dialog used in the TextView dialog
+ **/
+class FindDialog : public QDialog
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param parent parent widget
+ **/
+ explicit FindDialog(QWidget *parent = 0);
+
+ ~FindDialog();
+
+signals:
+
+ /**
+ * @brief emitted when the user wants to jump to the next location matching the pattern
+ **/
+ void findNext();
+
+ /**
+ * @brief emitted when the user changes the pattern to search for
+ *
+ * @param pattern the new search pattern
+ **/
+ void patternChanged(const QString &pattern);
+
+private slots:
+ void on_nextBtn_clicked();
+
+ void on_patternEdit_textChanged(const QString &arg1);
+
+ void on_closeBtn_clicked();
+
+private:
+ Ui::FindDialog *ui;
+};
+
+#endif // FINDDIALOG_H
diff --git a/src/finddialog.ui b/src/finddialog.ui new file mode 100644 index 00000000..2c4c80b8 --- /dev/null +++ b/src/finddialog.ui @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FindDialog</class>
+ <widget class="QDialog" name="FindDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>72</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Find</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Find what:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="patternEdit">
+ <property name="toolTip">
+ <string>Search term</string>
+ </property>
+ <property name="whatsThis">
+ <string>Search term</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QPushButton" name="nextBtn">
+ <property name="toolTip">
+ <string>Find next occurence from current file position.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Find next occurence from current file position.</string>
+ </property>
+ <property name="text">
+ <string>&Find Next</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeBtn">
+ <property name="toolTip">
+ <string>Close</string>
+ </property>
+ <property name="whatsThis">
+ <string>Close</string>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/fomodinstallerdialog.cpp b/src/fomodinstallerdialog.cpp new file mode 100644 index 00000000..16f6db60 --- /dev/null +++ b/src/fomodinstallerdialog.cpp @@ -0,0 +1,939 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "fomodinstallerdialog.h"
+#include "report.h"
+#include "utility.h"
+#include "ui_fomodinstallerdialog.h"
+
+#include <QFile>
+#include <QDir>
+#include <QImage>
+#include <QCheckBox>
+#include <QRadioButton>
+#include <QScrollArea>
+#include <Shellapi.h>
+
+
+bool ControlsAscending(QAbstractButton *LHS, QAbstractButton *RHS)
+{
+ return LHS->text() < RHS->text();
+}
+
+
+bool ControlsDescending(QAbstractButton *LHS, QAbstractButton *RHS)
+{
+ return LHS->text() > RHS->text();
+}
+
+
+bool PagesAscending(QGroupBox *LHS, QGroupBox *RHS)
+{
+ return LHS->title() < RHS->title();
+}
+
+
+bool PagesDescending(QGroupBox *LHS, QGroupBox *RHS)
+{
+ return LHS->title() > RHS->title();
+}
+
+
+FomodInstallerDialog::FomodInstallerDialog(const QString &modName, const QString &fomodPath, QWidget *parent)
+ : QDialog(parent), ui(new Ui::FomodInstallerDialog), m_FomodPath(fomodPath), m_Manual(false)
+{
+ ui->setupUi(this);
+ ui->nameEdit->setText(modName);
+}
+
+FomodInstallerDialog::~FomodInstallerDialog()
+{
+ delete ui;
+}
+
+#pragma message("implement module dependencies->file dependencies")
+
+void FomodInstallerDialog::initData()
+{
+ { // parse provided package information
+ QFile file(QDir::tempPath().append("/info.xml"));
+ if (file.open(QIODevice::ReadOnly)) {
+ // nmm allows files with wrong encoding and of course there are now files with broken
+ // so, let's do as nmm does and ignore the standard. yay
+ QByteArray header = file.readLine();
+ if (strncmp(header.constData(), "<?", 2) != 0) {
+ // not a header, rewind
+ file.seek(0);
+ }
+ parseInfo(file.readAll());
+ }
+ file.close();
+ }
+
+ QImage screenshot(QDir::tempPath().append("/screenshot.png"));
+ if (!screenshot.isNull()) {
+ screenshot = screenshot.scaledToWidth(ui->screenshotLabel->width());
+ ui->screenshotLabel->setPixmap(QPixmap::fromImage(screenshot));
+ }
+
+ { // parse xml installer file
+ QFile file(QDir::tempPath().append("/ModuleConfig.xml"));
+ if (!file.open(QIODevice::ReadOnly)) {
+ throw MyException(tr("ModuleConfig.xml missing"));
+ }
+ // nmm allows files with wrong encoding and of course there are now files that are broken
+ QByteArray header = file.readLine();
+ if (strncmp(header.constData(), "<?", 2) != 0) {
+ // not a header, rewind
+ if (!file.seek(0)) {
+ qCritical("failed to rewind file");
+ }
+ }
+ parseModuleConfig(file.readAll());
+ file.close();
+ }
+}
+
+
+QString FomodInstallerDialog::getName() const
+{
+ return ui->nameEdit->text();
+}
+
+
+void FomodInstallerDialog::moveTree(DirectoryTree::Node *target, DirectoryTree::Node *source)
+{
+ for (DirectoryTree::const_node_iterator iter = source->nodesBegin(); iter != source->nodesEnd();) {
+ target->addNode(*iter, true);
+ iter = source->detach(iter);
+ }
+
+ for (DirectoryTree::const_leaf_reverse_iterator iter = source->leafsRBegin();
+ iter != source->leafsREnd(); ++iter) {
+ target->addLeaf(*iter);
+ }
+}
+
+
+DirectoryTree::Node *FomodInstallerDialog::findNode(DirectoryTree::Node *node, const QString &path, bool create)
+{
+ if (path.length() == 0) {
+ return node;
+ }
+
+// static QRegExp pathSeparator("[/\\]");
+ int pos = path.indexOf('\\');
+ if (pos == -1) {
+ pos = path.indexOf('/');
+ }
+ QString subPath = path;
+ if (pos > 0) {
+ subPath = path.mid(0, pos);
+ }
+ for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) {
+ if ((*iter)->getData().name.compare(subPath, Qt::CaseInsensitive) == 0) {
+ if (pos <= 0) {
+ return *iter;
+ } else {
+ return findNode(*iter, path.mid(pos + 1), create);
+ }
+ }
+ }
+ if (create) {
+ DirectoryTree::Node *newNode = new DirectoryTree::Node;
+ newNode->setData(subPath);
+ node->addNode(newNode, false);
+ if (pos <= 0) {
+ return newNode;
+ } else {
+ return findNode(newNode, path.mid(pos + 1), create);
+ }
+ } else {
+ throw MyException(QString("%1 not found in archive").arg(path));
+ }
+}
+
+void FomodInstallerDialog::copyLeaf(DirectoryTree::Node *sourceTree, const QString &sourcePath,
+ DirectoryTree::Node *destinationTree, const QString &destinationPath)
+{
+ int sourceFileIndex = sourcePath.lastIndexOf('\\');
+ if (sourceFileIndex == -1) {
+ sourceFileIndex = sourcePath.lastIndexOf('/');
+ if (sourceFileIndex == -1) {
+ sourceFileIndex = 0;
+ }
+ }
+ DirectoryTree::Node *sourceNode = sourceFileIndex == 0 ? sourceTree : findNode(sourceTree, sourcePath.mid(0, sourceFileIndex), false);
+
+ int destinationFileIndex = destinationPath.lastIndexOf('\\');
+ if (destinationFileIndex == -1) {
+ destinationFileIndex = destinationPath.lastIndexOf('/');
+ if (destinationFileIndex == -1) {
+ destinationFileIndex = 0;
+ }
+ }
+
+ DirectoryTree::Node *destinationNode =
+ destinationFileIndex == 0 ? destinationTree
+ : findNode(destinationTree, destinationPath.mid(0, destinationFileIndex), true);
+
+ QString sourceName = sourcePath.mid((sourceFileIndex != 0) ? sourceFileIndex + 1 : 0);
+ QString destinationName = (destinationFileIndex != 0) ? destinationPath.mid(destinationFileIndex + 1) : destinationPath;
+ if (destinationName.length() == 0) {
+ destinationName = sourceName;
+ }
+
+ bool found = false;
+ for (DirectoryTree::const_leaf_reverse_iterator iter = sourceNode->leafsRBegin();
+ iter != sourceNode->leafsREnd(); ++iter) {
+ if (iter->getName().compare(sourceName, Qt::CaseInsensitive) == 0) {
+ destinationNode->addLeaf(*iter);
+ found = true;
+ }
+ }
+ if (!found) {
+ qCritical("%s not found!", sourceName.toUtf8().constData());
+ }
+}
+
+
+void dumpTree(DirectoryTree::Node *node, int indent)
+{
+ for (DirectoryTree::const_leaf_reverse_iterator iter = node->leafsRBegin();
+ iter != node->leafsREnd(); ++iter) {
+ qDebug("%.*s%s", indent, " ", iter->getName().toUtf8().constData());
+ }
+
+ for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) {
+ qDebug("%.*s-- %s", indent, " ", (*iter)->getData().name.toUtf8().constData());
+ dumpTree(*iter, indent + 2);
+ }
+}
+
+
+bool FomodInstallerDialog::copyFileIterator(DirectoryTree *sourceTree, DirectoryTree *destinationTree, FileDescriptor *descriptor)
+{
+ QString source = (m_FomodPath.length() != 0) ? m_FomodPath.mid(0).append("\\").append(descriptor->m_Source)
+ : descriptor->m_Source;
+ QString destination = descriptor->m_Destination;
+ try {
+ if (descriptor->m_IsFolder) {
+ DirectoryTree::Node *sourceNode = findNode(sourceTree, source, false);
+ DirectoryTree::Node *targetNode = findNode(destinationTree, destination, true);
+ moveTree(targetNode, sourceNode);
+ } else {
+ copyLeaf(sourceTree, source, destinationTree, destination);
+ }
+ return true;
+ } catch (const MyException &e) {
+ qCritical("failed to extract %s to %s: %s",
+ source.toUtf8().constData(), destination.toUtf8().constData(), e.what());
+ return false;
+ }
+}
+
+
+DirectoryTree *FomodInstallerDialog::updateTree(DirectoryTree *tree)
+{
+ DirectoryTree *newTree = new DirectoryTree;
+
+ for (std::vector<FileDescriptor*>::iterator iter = m_RequiredFiles.begin(); iter != m_RequiredFiles.end(); ++iter) {
+ copyFileIterator(tree, newTree, *iter);
+ }
+
+ for (std::vector<ConditionalInstall>::iterator installIter = m_ConditionalInstalls.begin();
+ installIter != m_ConditionalInstalls.end(); ++installIter) {
+ bool match = installIter->m_Operator == ConditionalInstall::OP_AND;
+ for (std::vector<Condition>::iterator conditionIter = installIter->m_Conditions.begin();
+ conditionIter != installIter->m_Conditions.end(); ++conditionIter) {
+ bool conditionMatches = testCondition(ui->stepsStack->count(), conditionIter->m_Name, conditionIter->m_Value);
+ if (conditionMatches && (installIter->m_Operator == ConditionalInstall::OP_OR)) {
+ match = true;
+ break;
+ } else if (!conditionMatches && (installIter->m_Operator == ConditionalInstall::OP_AND)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ for (std::vector<FileDescriptor*>::iterator fileIter = installIter->m_Files.begin();
+ fileIter != installIter->m_Files.end(); ++fileIter) {
+ copyFileIterator(tree, newTree, *fileIter);
+ }
+ }
+ }
+
+ QList<QAbstractButton*> choices = ui->stepsStack->findChildren<QAbstractButton*>("choice");
+ foreach (QAbstractButton* choice, choices) {
+ if (choice->isChecked()) {
+ QVariantList fileList = choice->property("files").toList();
+ foreach (QVariant fileVariant, fileList) {
+ copyFileIterator(tree, newTree, fileVariant.value<FileDescriptor*>());
+ }
+ }
+ }
+
+// dumpTree(newTree, 0);
+
+ return newTree;
+}
+
+
+void FomodInstallerDialog::highlightControl(QAbstractButton *button)
+{
+ QVariant screenshotName = button->property("screenshot");
+ if (screenshotName.isValid()) {
+ QString screenshotFileName = screenshotName.toString();
+ if (!screenshotFileName.isEmpty()) {
+ QString temp = QFileInfo(screenshotFileName).fileName();
+ QImage screenshot(QDir::tempPath().append("/").append(temp));
+ if (screenshot.isNull()) {
+ qWarning(">%s< is a null image", screenshotName.toString().toUtf8().constData());
+ }
+ screenshot = screenshot.scaledToWidth(ui->screenshotLabel->width());
+ ui->screenshotLabel->setPixmap(QPixmap::fromImage(screenshot));
+ } else {
+ ui->screenshotLabel->setPixmap(QPixmap());
+ }
+ }
+ ui->descriptionText->setText(button->property("description").toString());
+}
+
+
+bool FomodInstallerDialog::eventFilter(QObject *object, QEvent *event)
+{
+ QAbstractButton *button = qobject_cast<QAbstractButton*>(object);
+ if ((button != NULL) && (event->type() == QEvent::HoverEnter)) {
+ highlightControl(button);
+
+ }
+ return QDialog::eventFilter(object, event);
+}
+
+
+QString FomodInstallerDialog::readContent(QXmlStreamReader &reader)
+{
+ if (reader.readNext() == QXmlStreamReader::Characters) {
+ return reader.text().toString();
+ } else {
+ return QString();
+ }
+}
+
+
+void FomodInstallerDialog::parseInfo(const QByteArray &data)
+{
+ QXmlStreamReader reader(data);
+/* while (reader.readNext() != QXmlStreamReader::StartDocument) {}
+ QTextDecoder *decoder = QTextCodec::codecForName(reader.documentEncoding().toLocal8Bit())->makeDecoder(QTextCodec::ConvertInvalidToNull);
+ QString test(decoder->toUnicode(data));
+ qDebug("test: %d, %s", test.isNull(), test.toUtf8().constData());
+
+ qDebug(">%s<", reader.documentEncoding().toUtf8().constData());*/
+ while (!reader.atEnd() && !reader.hasError()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::StartElement: {
+ if (reader.name() == "Name") {
+ ui->nameEdit->setText(readContent(reader));
+ } else if (reader.name() == "Author") {
+ ui->authorLabel->setText(readContent(reader));
+ } else if (reader.name() == "Version") {
+ ui->versionLabel->setText(readContent(reader));
+ } else if (reader.name() == "Website") {
+ QString url = readContent(reader);
+ ui->websiteLabel->setText(tr("<a href=\"%1\">Link</a>").arg(url));
+ ui->websiteLabel->setToolTip(url);
+ }
+ } break;
+ default: {} break;
+ }
+ }
+ if (reader.hasError()) {
+ throw MyException(tr("failed to parse info.xml: %1 (%2) (line %3, column %4)")
+ .arg(reader.errorString())
+ .arg(reader.error())
+ .arg(reader.lineNumber())
+ .arg(reader.columnNumber()));
+
+ }
+}
+
+
+FomodInstallerDialog::ItemOrder FomodInstallerDialog::getItemOrder(const QString &orderString)
+{
+ if (orderString == "Ascending") {
+ return ORDER_ASCENDING;
+ } else if (orderString == "Descending") {
+ return ORDER_DESCENDING;
+ } else if (orderString == "Explicit") {
+ return ORDER_EXPLICIT;
+ } else {
+ throw MyException(tr("unsupported order type %1").arg(orderString));
+ }
+}
+
+
+FomodInstallerDialog::GroupType FomodInstallerDialog::getGroupType(const QString &typeString)
+{
+ if (typeString == "SelectAtLeastOne") {
+ return TYPE_SELECTATLEASTONE;
+ } else if (typeString == "SelectAtMostOne") {
+ return TYPE_SELECTATMOSTONE;
+ } else if (typeString == "SelectExactlyOne") {
+ return TYPE_SELECTEXACTLYONE;
+ } else if (typeString == "SelectAny") {
+ return TYPE_SELECTANY;
+ } else if (typeString == "SelectAll") {
+ return TYPE_SELECTALL;
+ } else {
+ throw MyException(tr("unsupported group type %1").arg(typeString));
+ }
+}
+
+
+FomodInstallerDialog::PluginType FomodInstallerDialog::getPluginType(const QString &typeString)
+{
+ if (typeString == "Required") {
+ return FomodInstallerDialog::TYPE_REQUIRED;
+ } else if (typeString == "Optional") {
+ return FomodInstallerDialog::TYPE_OPTIONAL;
+ } else if (typeString == "Recommended") {
+ return FomodInstallerDialog::TYPE_RECOMMENDED;
+ } else if (typeString == "NotUsable") {
+ return FomodInstallerDialog::TYPE_NOTUSABLE;
+ } else if (typeString == "CouldBeUsable") {
+ return FomodInstallerDialog::TYPE_COULDBEUSABLE;
+ } else {
+ qCritical("invalid plugin type %s", typeString.toUtf8().constData());
+ return FomodInstallerDialog::TYPE_OPTIONAL;
+ }
+}
+
+
+void FomodInstallerDialog::readFileList(QXmlStreamReader &reader, std::vector<FileDescriptor*> &fileList)
+{
+ QStringRef openTag = reader.name();
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == openTag))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if ((reader.name() == "folder") ||
+ (reader.name() == "file")) {
+ QXmlStreamAttributes attributes = reader.attributes();
+ FileDescriptor *file = new FileDescriptor(this);
+ file->m_Source = attributes.value("source").toString();
+ file->m_Destination = attributes.hasAttribute("destination") ? attributes.value("destination").toString()
+ : file->m_Source;
+ file->m_Priority = attributes.hasAttribute("priority") ? attributes.value("priority").string()->toInt()
+ : 0;
+ file->m_IsFolder = reader.name() == "folder";
+ file->m_InstallIfUsable = attributes.hasAttribute("installIfUsable") ? (attributes.value("installIfUsable").compare("true") == 0)
+ : false;
+ file->m_AlwaysInstall = attributes.hasAttribute("alwaysInstall") ? (attributes.value("alwaysInstall").compare("true") == 0)
+ : false;
+
+ fileList.push_back(file);
+ }
+ }
+ }
+}
+
+
+void FomodInstallerDialog::readPluginType(QXmlStreamReader &reader, Plugin &plugin)
+{
+ plugin.m_Type = TYPE_OPTIONAL;
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "typeDescriptor"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "type") {
+ plugin.m_Type = getPluginType(reader.attributes().value("name").toString());
+ }
+ }
+ }
+}
+
+
+void FomodInstallerDialog::readConditionFlags(QXmlStreamReader &reader, Plugin &plugin)
+{
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "conditionFlags"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "flag") {
+ QString name = reader.attributes().value("name").toString();
+ plugin.m_Conditions.push_back(Condition(name, readContent(reader)));
+ }
+ }
+ }
+}
+
+
+bool FomodInstallerDialog::byPriority(const FileDescriptor *LHS, const FileDescriptor *RHS)
+{
+ return LHS->m_Priority < RHS->m_Priority;
+}
+
+
+FomodInstallerDialog::Plugin FomodInstallerDialog::readPlugin(QXmlStreamReader &reader)
+{
+ Plugin result;
+ result.m_Name = reader.attributes().value("name").toString();
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "plugin"))) {
+// QXmlStreamReader::TokenType type = reader.tokenType();
+// QString name = reader.name().toUtf8();
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "description") {
+ result.m_Description = readContent(reader).trimmed();
+ } else if (reader.name() == "image") {
+ result.m_ImagePath = reader.attributes().value("path").toString();
+ } else if (reader.name() == "typeDescriptor") {
+ readPluginType(reader, result);
+ } else if (reader.name() == "conditionFlags") {
+ readConditionFlags(reader, result);
+ } else if (reader.name() == "files") {
+ readFileList(reader, result.m_Files);
+ }
+ }
+ }
+
+ std::sort(result.m_Files.begin(), result.m_Files.end(), byPriority);
+
+ return result;
+}
+
+
+void FomodInstallerDialog::readPlugins(QXmlStreamReader &reader, GroupType groupType, QLayout *layout)
+{
+ ItemOrder pluginOrder = reader.attributes().hasAttribute("order") ? getItemOrder(reader.attributes().value("order").toString())
+ : ORDER_ASCENDING;
+ bool first = true;
+ bool maySelectMore = true;
+
+ std::vector<QAbstractButton*> controls;
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "plugins"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "plugin") {
+ Plugin plugin = readPlugin(reader);
+ QAbstractButton *newControl = NULL;
+ switch (groupType) {
+ case TYPE_SELECTATLEASTONE:
+ case TYPE_SELECTANY: {
+ newControl = new QCheckBox(plugin.m_Name);
+ } break;
+ case TYPE_SELECTATMOSTONE: {
+ newControl = new QRadioButton(plugin.m_Name);
+ } break;
+ case TYPE_SELECTEXACTLYONE: {
+ newControl = new QRadioButton(plugin.m_Name);
+ if (first) {
+ newControl->setChecked(true);
+ }
+ } break;
+ case TYPE_SELECTALL: {
+ newControl = new QCheckBox(plugin.m_Name);
+ newControl->setChecked(true);
+ newControl->setEnabled(false);
+ } break;
+ }
+ newControl->setObjectName("choice");
+ switch (plugin.m_Type) {
+ case TYPE_REQUIRED: {
+ newControl->setChecked(true);
+ newControl->setEnabled(false);
+ newControl->setToolTip(tr("This component is required"));
+ } break;
+ case TYPE_RECOMMENDED: {
+ if (maySelectMore) {
+ newControl->setChecked(true);
+ }
+ newControl->setToolTip(tr("It is recommended you enable this component"));
+ if ((groupType == TYPE_SELECTATMOSTONE) || (groupType == TYPE_SELECTEXACTLYONE)) {
+ maySelectMore = false;
+ }
+ } break;
+ case TYPE_OPTIONAL: {
+ newControl->setToolTip(tr("Optional component"));
+ } break;
+ case TYPE_NOTUSABLE: {
+ newControl->setChecked(false);
+ newControl->setEnabled(false);
+ newControl->setToolTip(tr("This component is not usable in combination with other installed plugins"));
+ } break;
+ case TYPE_COULDBEUSABLE: {
+ newControl->setCheckable(true);
+ newControl->setIcon(QIcon(":/new/guiresources/resources/dialog-warning_16.png"));
+ newControl->setToolTip(tr("You may be experiencing instability in combination with other installed plugins"));
+ } break;
+ }
+
+ newControl->setProperty("plugintype", plugin.m_Type);
+ newControl->setProperty("screenshot", plugin.m_ImagePath);
+ newControl->setProperty("description", plugin.m_Description);
+ QVariantList fileList;
+ for (std::vector<FileDescriptor*>::iterator iter = plugin.m_Files.begin(); iter != plugin.m_Files.end(); ++iter) {
+ fileList.append(qVariantFromValue(*iter));
+ }
+ newControl->setProperty("files", fileList);
+ QVariantList conditionFlags;
+ for (std::vector<Condition>::const_iterator iter = plugin.m_Conditions.begin(); iter != plugin.m_Conditions.end(); ++iter) {
+ if (iter->m_Name.length() != 0) {
+ conditionFlags.append(qVariantFromValue(Condition(iter->m_Name, iter->m_Value)));
+ }
+ }
+ newControl->setProperty("conditionFlags", conditionFlags);
+ newControl->installEventFilter(this);
+ controls.push_back(newControl);
+ first = false;
+ }
+ }
+ }
+
+ if (pluginOrder == ORDER_ASCENDING) {
+ std::sort(controls.begin(), controls.end(), ControlsAscending);
+ } else if (pluginOrder == ORDER_DESCENDING) {
+ std::sort(controls.begin(), controls.end(), ControlsDescending);
+ }
+
+ for (std::vector<QAbstractButton*>::const_iterator iter = controls.begin(); iter != controls.end(); ++iter) {
+ layout->addWidget(*iter);
+ }
+
+ if (groupType == TYPE_SELECTATMOSTONE) {
+ QRadioButton *newButton = new QRadioButton(tr("None"));
+ if (maySelectMore) {
+ newButton->setChecked(true);
+ }
+ layout->addWidget(newButton);
+ }
+}
+
+
+void FomodInstallerDialog::readGroup(QXmlStreamReader &reader, QLayout *layout)
+{
+ //FileGroup result;
+ QString name = reader.attributes().value("name").toString();
+ GroupType type = getGroupType(reader.attributes().value("type").toString());
+
+ if (type == TYPE_SELECTATLEASTONE) {
+ QLabel *label = new QLabel(tr("Select one or more of these options:"));
+ layout->addWidget(label);
+ }
+
+ QGroupBox *groupBox = new QGroupBox(name);
+
+ QVBoxLayout *groupLayout = new QVBoxLayout;
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "group"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "plugins") {
+ readPlugins(reader, type, groupLayout);
+ }
+ }
+ }
+
+ groupBox->setLayout(groupLayout);
+ layout->addWidget(groupBox);
+}
+
+
+void FomodInstallerDialog::readGroups(QXmlStreamReader &reader, QLayout *layout)
+{
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "optionalFileGroups"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "group") {
+ readGroup(reader, layout);
+ }
+ }
+ }
+}
+
+
+void FomodInstallerDialog::readVisible(QXmlStreamReader &reader, QVariantList &conditions)
+{
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "visible"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "flagDependency") {
+ Condition condition(reader.attributes().value("flag").toString(),
+ reader.attributes().value("value").toString());
+ conditions.append(qVariantFromValue(condition));
+ }
+ }
+ }
+}
+
+QGroupBox *FomodInstallerDialog::readInstallerStep(QXmlStreamReader &reader)
+{
+ QString name = reader.attributes().value("name").toString();
+ QGroupBox *page = new QGroupBox(name);
+ QVBoxLayout *pageLayout = new QVBoxLayout;
+ QScrollArea *scrollArea = new QScrollArea;
+ QFrame *scrolledArea = new QFrame;
+ QVBoxLayout *scrollLayout = new QVBoxLayout;
+
+ QVariantList conditions;
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "installStep"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "optionalFileGroups") {
+ readGroups(reader, scrollLayout);
+ } else if (reader.name() == "visible") {
+ readVisible(reader, conditions);
+ }
+ }
+ }
+ if (conditions.length() != 0) {
+ page->setProperty("conditions", conditions);
+ }
+
+ scrolledArea->setLayout(scrollLayout);
+ scrollArea->setWidget(scrolledArea);
+ scrollArea->setWidgetResizable(true);
+ pageLayout->addWidget(scrollArea);
+ page->setLayout(pageLayout);
+ return page;
+}
+
+
+void FomodInstallerDialog::readInstallerSteps(QXmlStreamReader &reader)
+{
+ ItemOrder stepOrder = reader.attributes().hasAttribute("order") ? getItemOrder(reader.attributes().value("order").toString())
+ : ORDER_ASCENDING;
+
+ std::vector<QGroupBox*> pages;
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "installSteps"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "installStep") {
+ pages.push_back(readInstallerStep(reader));
+ }
+ }
+ }
+
+ if (stepOrder == ORDER_ASCENDING) {
+ std::sort(pages.begin(), pages.end(), PagesAscending);
+ } else if (stepOrder == ORDER_DESCENDING) {
+ std::sort(pages.begin(), pages.end(), PagesDescending);
+ }
+
+ for (std::vector<QGroupBox*>::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) {
+ ui->stepsStack->addWidget(*iter);
+ }
+}
+
+
+FomodInstallerDialog::ConditionalInstall FomodInstallerDialog::readConditionalPattern(QXmlStreamReader &reader)
+{
+ ConditionalInstall result;
+ result.m_Operator = ConditionalInstall::OP_AND;
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "pattern"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "dependencies") {
+ QStringRef dependencyOperator = reader.attributes().value("operator");
+ if (dependencyOperator == "And") {
+ result.m_Operator = ConditionalInstall::OP_AND;
+ } else if (dependencyOperator == "Or") {
+ result.m_Operator = ConditionalInstall::OP_OR;
+ } // otherwise operator is not set (which we can ignore) or invalid (which we should report actually)
+
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "dependencies"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "flagDependency") {
+ result.m_Conditions.push_back(Condition(reader.attributes().value("flag").toString(),
+ reader.attributes().value("value").toString()));
+ }
+ }
+ }
+ } else if (reader.name() == "files") {
+ readFileList(reader, result.m_Files);
+ }
+ }
+ }
+ return result;
+}
+
+
+void FomodInstallerDialog::readConditionalFileInstalls(QXmlStreamReader &reader)
+{
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "conditionalFileInstalls"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "patterns") {
+ while (!((reader.readNext() == QXmlStreamReader::EndElement) &&
+ (reader.name() == "patterns"))) {
+ if (reader.tokenType() == QXmlStreamReader::StartElement) {
+ if (reader.name() == "pattern") {
+ m_ConditionalInstalls.push_back(readConditionalPattern(reader));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void FomodInstallerDialog::parseModuleConfig(const QByteArray &data)
+{
+ QXmlStreamReader reader(data);
+ while (!reader.atEnd() && !reader.hasError()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::StartElement: {
+ if (reader.name() == "installSteps") {
+ readInstallerSteps(reader);
+ } else if (reader.name() == "requiredInstallFiles") {
+ readFileList(reader, m_RequiredFiles);
+ } else if (reader.name() == "conditionalFileInstalls") {
+ readConditionalFileInstalls(reader);
+ }
+ } break;
+ default: {} break;
+ }
+ }
+ if (reader.hasError()) {
+ reportError(tr("failed to parse ModuleConfig.xml: %1 - %2").arg(reader.errorString()).arg(reader.lineNumber()));
+ }
+ activateCurrentPage();
+}
+
+
+void FomodInstallerDialog::on_manualBtn_clicked()
+{
+ m_Manual = true;
+ this->reject();
+}
+
+void FomodInstallerDialog::on_cancelBtn_clicked()
+{
+ this->reject();
+}
+
+
+void FomodInstallerDialog::on_websiteLabel_linkActivated(const QString &link)
+{
+ ::ShellExecuteW(NULL, L"open", ToWString(link).c_str(), NULL, NULL, SW_SHOWNORMAL);
+}
+
+
+void FomodInstallerDialog::activateCurrentPage()
+{
+ QList<QAbstractButton*> choices = ui->stepsStack->currentWidget()->findChildren<QAbstractButton*>("choice");
+ if (choices.count() > 0) {
+ highlightControl(choices.at(0));
+ }
+}
+
+
+bool FomodInstallerDialog::testCondition(int maxIndex, const QString &flag, const QString &value)
+{
+ // iterate through all set condition flags on all activated controls on all visible pages if one of them matches the condition
+ for (int i = 0; i < maxIndex; ++i) {
+ if (testVisible(i)) {
+ QWidget *page = ui->stepsStack->widget(i);
+ QList<QAbstractButton*> choices = page->findChildren<QAbstractButton*>("choice");
+ foreach (QAbstractButton* choice, choices) {
+ if (choice->isChecked()) {
+ QVariant temp = choice->property("conditionFlags");
+ if (temp.isValid()) {
+ QVariantList conditionFlags = temp.toList();
+ for (QVariantList::const_iterator iter = conditionFlags.begin(); iter != conditionFlags.end(); ++iter) {
+ Condition condition = iter->value<Condition>();
+ if ((condition.m_Name == flag) && (condition.m_Value == value)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool FomodInstallerDialog::testVisible(int pageIndex)
+{
+ QWidget *page = ui->stepsStack->widget(pageIndex);
+ QVariant temp = page->property("conditions");
+ if (temp.isValid()) {
+ QVariantList conditions = temp.toList();
+ for (QVariantList::const_iterator iter = conditions.begin(); iter != conditions.end(); ++iter) {
+ Condition condition = iter->value<Condition>();
+ if (!testCondition(pageIndex, condition.m_Name, condition.m_Value)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return true;
+ }
+}
+
+
+bool FomodInstallerDialog::nextPage()
+{
+ int index = ui->stepsStack->currentIndex() + 1;
+ while (index < ui->stepsStack->count()) {
+ if (testVisible(index)) {
+ ui->stepsStack->setCurrentIndex(index);
+ return true;
+ }
+ ++index;
+ }
+ // no more visible pages -> install
+ return false;
+}
+
+
+void FomodInstallerDialog::on_nextBtn_clicked()
+{
+ if (ui->stepsStack->currentIndex() == ui->stepsStack->count() - 1) {
+ this->accept();
+ } else {
+ if (nextPage()) {
+ if (ui->stepsStack->currentIndex() == ui->stepsStack->count() - 1) {
+ ui->nextBtn->setText(tr("Install"));
+ }
+ ui->prevBtn->setEnabled(true);
+ activateCurrentPage();
+ } else {
+ this->accept();
+ }
+ }
+}
+
+void FomodInstallerDialog::on_prevBtn_clicked()
+{
+ if (ui->stepsStack->currentIndex() != 0) {
+ ui->stepsStack->setCurrentIndex(ui->stepsStack->currentIndex() - 1);
+ ui->nextBtn->setText(tr("Next"));
+ }
+ if (ui->stepsStack->currentIndex() == 0) {
+ ui->prevBtn->setEnabled(false);
+ }
+ activateCurrentPage();
+}
diff --git a/src/fomodinstallerdialog.h b/src/fomodinstallerdialog.h new file mode 100644 index 00000000..0fb5a5ec --- /dev/null +++ b/src/fomodinstallerdialog.h @@ -0,0 +1,210 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef FOMODINSTALLERDIALOG_H
+#define FOMODINSTALLERDIALOG_H
+
+#include "installdialog.h"
+#include <QDialog>
+#include <QAbstractButton>
+#include <QXmlStreamReader>
+#include <QGroupBox>
+#include <QSharedPointer>
+
+namespace Ui {
+class FomodInstallerDialog;
+}
+
+
+class Condition : public QObject {
+ Q_OBJECT
+public:
+ Condition(QObject *parent = NULL) : QObject(parent) { }
+ Condition(const Condition &reference) : QObject(reference.parent()), m_Name(reference.m_Name), m_Value(reference.m_Value) { }
+ Condition(const QString &name, const QString &value) : QObject(), m_Name(name), m_Value(value) { }
+ QString m_Name;
+ QString m_Value;
+private:
+ Condition &operator=(const Condition&);
+};
+
+Q_DECLARE_METATYPE(Condition)
+
+
+class FileDescriptor : public QObject {
+ Q_OBJECT
+public:
+ FileDescriptor(QObject *parent)
+ : QObject(parent), m_Source(), m_Destination(), m_Priority(0), m_IsFolder(false), m_AlwaysInstall(false),
+ m_InstallIfUsable(false) {}
+ FileDescriptor(const FileDescriptor &reference)
+ : QObject(reference.parent()), m_Source(reference.m_Source), m_Destination(reference.m_Destination),
+ m_Priority(reference.m_Priority), m_IsFolder(reference.m_IsFolder), m_AlwaysInstall(reference.m_AlwaysInstall),
+ m_InstallIfUsable(reference.m_InstallIfUsable) {}
+ QString m_Source;
+ QString m_Destination;
+ int m_Priority;
+ bool m_IsFolder;
+ bool m_AlwaysInstall;
+ bool m_InstallIfUsable;
+private:
+ FileDescriptor &operator=(const FileDescriptor&);
+};
+
+Q_DECLARE_METATYPE(FileDescriptor*)
+
+
+class FomodInstallerDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit FomodInstallerDialog(const QString &modName, const QString &fomodPath, QWidget *parent = 0);
+ ~FomodInstallerDialog();
+
+ void initData();
+
+ /**
+ * @return bool true if the user requested the manual dialog
+ **/
+ bool manualRequested() const { return m_Manual; }
+
+ /**
+ * @return QString the (user-modified) name to be used for the mod
+ **/
+ QString getName() const;
+
+ /**
+ * @brief retrieve the updated archive tree from the dialog. The caller is responsible to delete the returned tree.
+ *
+ * @note This call is destructive on the input tree!
+ *
+ * @param tree input tree. (TODO isn't this the same as the tree passed in the constructor?)
+ * @return DataTree* a new tree with only the selected options and directories arranged correctly. The caller takes custody of this pointer!
+ **/
+ DirectoryTree *updateTree(DirectoryTree *tree);
+
+protected:
+
+ virtual bool eventFilter(QObject *object, QEvent *event);
+
+private slots:
+
+ void on_cancelBtn_clicked();
+
+ void on_manualBtn_clicked();
+
+ void on_websiteLabel_linkActivated(const QString &link);
+
+ void on_nextBtn_clicked();
+
+ void on_prevBtn_clicked();
+
+private:
+
+ enum ItemOrder {
+ ORDER_ASCENDING,
+ ORDER_DESCENDING,
+ ORDER_EXPLICIT
+ };
+
+ enum GroupType {
+ TYPE_SELECTATLEASTONE,
+ TYPE_SELECTATMOSTONE,
+ TYPE_SELECTEXACTLYONE,
+ TYPE_SELECTANY,
+ TYPE_SELECTALL
+ };
+
+ enum PluginType {
+ TYPE_REQUIRED,
+ TYPE_RECOMMENDED,
+ TYPE_OPTIONAL,
+ TYPE_NOTUSABLE,
+ TYPE_COULDBEUSABLE
+ };
+
+ struct Plugin {
+ QString m_Name;
+ QString m_Description;
+ QString m_ImagePath;
+ PluginType m_Type;
+ std::vector<Condition> m_Conditions;
+ std::vector<FileDescriptor*> m_Files;
+ };
+
+ struct ConditionalInstall {
+ enum {
+ OP_AND,
+ OP_OR
+ } m_Operator;
+ std::vector<Condition> m_Conditions;
+ std::vector<FileDescriptor*> m_Files;
+ };
+
+private:
+
+ QString readContent(QXmlStreamReader &reader);
+ void parseInfo(const QByteArray &data);
+
+ static ItemOrder getItemOrder(const QString &orderString);
+ static GroupType getGroupType(const QString &typeString);
+ static PluginType getPluginType(const QString &typeString);
+ static bool byPriority(const FileDescriptor *LHS, const FileDescriptor *RHS);
+
+ bool copyFileIterator(DirectoryTree *sourceTree, DirectoryTree *destinationTree, FileDescriptor *descriptor);
+ void readFileList(QXmlStreamReader &reader, std::vector<FileDescriptor*> &fileList);
+ void readPluginType(QXmlStreamReader &reader, Plugin &plugin);
+ void readConditionFlags(QXmlStreamReader &reader, Plugin &plugin);
+ FomodInstallerDialog::Plugin readPlugin(QXmlStreamReader &reader);
+ void readPlugins(QXmlStreamReader &reader, GroupType groupType, QLayout *layout);
+ void readGroup(QXmlStreamReader &reader, QLayout *layout);
+ void readGroups(QXmlStreamReader &reader, QLayout *layout);
+ void readVisible(QXmlStreamReader &reader, QVariantList &conditions);
+ QGroupBox *readInstallerStep(QXmlStreamReader &reader);
+ ConditionalInstall readConditionalPattern(QXmlStreamReader &reader);
+ void readConditionalFileInstalls(QXmlStreamReader &reader);
+ void readInstallerSteps(QXmlStreamReader &reader);
+ void parseModuleConfig(const QByteArray &data);
+ void highlightControl(QAbstractButton *button);
+
+ bool testCondition(int maxIndex, const QString &flag, const QString &value);
+ bool testVisible(int pageIndex);
+ bool nextPage();
+ void activateCurrentPage();
+ void moveTree(DirectoryTree::Node *target, DirectoryTree::Node *source);
+ DirectoryTree::Node *findNode(DirectoryTree::Node *node, const QString &path, bool create);
+ void copyLeaf(DirectoryTree::Node *sourceTree, const QString &sourcePath,
+ DirectoryTree::Node *destinationTree, const QString &destinationPath);
+
+private:
+
+ Ui::FomodInstallerDialog *ui;
+
+ QString m_FomodPath;
+ bool m_Manual;
+
+// ItemOrder m_StepOrder;
+// std::vector<InstallationStep> m_Steps;
+ std::vector<FileDescriptor*> m_RequiredFiles;
+ std::vector<ConditionalInstall> m_ConditionalInstalls;
+
+};
+
+#endif // FOMODINSTALLERDIALOG_H
diff --git a/src/fomodinstallerdialog.ui b/src/fomodinstallerdialog.ui new file mode 100644 index 00000000..270ae64b --- /dev/null +++ b/src/fomodinstallerdialog.ui @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FomodInstallerDialog</class>
+ <widget class="QDialog" name="FomodInstallerDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>662</width>
+ <height>501</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>FOMOD Installation Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>15</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Author</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="versionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Website</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="websiteLabel">
+ <property name="text">
+ <string><a href="#">Link</a></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="descriptionText">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="screenshotLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="stepsStack">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="manualBtn">
+ <property name="text">
+ <string>Manual</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="prevBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Back</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="nextBtn">
+ <property name="text">
+ <string>Next</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gameinfoimpl.cpp b/src/gameinfoimpl.cpp new file mode 100644 index 00000000..bb46ee3f --- /dev/null +++ b/src/gameinfoimpl.cpp @@ -0,0 +1,50 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "gameinfoimpl.h"
+#include <gameinfo.h>
+#include <utility.h>
+#include <QDir>
+
+
+GameInfoImpl::GameInfoImpl()
+{
+}
+
+IGameInfo::Type GameInfoImpl::type() const
+{
+ switch (GameInfo::instance().getType()) {
+ case GameInfo::TYPE_OBLIVION: return IGameInfo::TYPE_OBLIVION;
+ case GameInfo::TYPE_FALLOUT3: return IGameInfo::TYPE_FALLOUT3;
+ case GameInfo::TYPE_FALLOUTNV: return IGameInfo::TYPE_FALLOUTNV;
+ case GameInfo::TYPE_SKYRIM: return IGameInfo::TYPE_SKYRIM;
+ default: throw MyException(QObject::tr("invalid game type %1").arg(GameInfo::instance().getType()));
+ }
+}
+
+
+QString GameInfoImpl::path() const
+{
+ return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+}
+
+QString GameInfoImpl::binaryName() const
+{
+ return ToQString(GameInfo::instance().getBinaryName());
+}
diff --git a/src/gameinfoimpl.h b/src/gameinfoimpl.h new file mode 100644 index 00000000..abde6cbd --- /dev/null +++ b/src/gameinfoimpl.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef GAMEINFOIMPL_H
+#define GAMEINFOIMPL_H
+
+
+#include <igameinfo.h>
+#include <QString>
+
+
+class GameInfoImpl : public IGameInfo
+{
+public:
+ GameInfoImpl();
+
+ virtual Type type() const;
+ virtual QString path() const;
+ virtual QString binaryName() const;
+
+};
+
+#endif // GAMEINFOIMPL_H
diff --git a/src/helper.cpp b/src/helper.cpp new file mode 100644 index 00000000..55b21a4b --- /dev/null +++ b/src/helper.cpp @@ -0,0 +1,118 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "helper.h"
+#include "report.h"
+#include "utility.h"
+#include <LMCons.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#include <QDir>
+
+
+namespace Helper {
+
+
+bool helperExec(LPCWSTR moDirectory, LPCWSTR commandLine)
+{
+ wchar_t fileName[MAX_PATH];
+ _snwprintf(fileName, MAX_PATH, L"%ls\\helper.exe", moDirectory);
+
+ SHELLEXECUTEINFOW execInfo = {0};
+
+ execInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ execInfo.hwnd = NULL;
+ execInfo.lpVerb = L"runas";
+ execInfo.lpFile = fileName;
+ execInfo.lpParameters = commandLine;
+ execInfo.lpDirectory = moDirectory;
+ execInfo.nShow = SW_SHOW;
+
+ ::ShellExecuteExW(&execInfo);
+
+ if (::WaitForSingleObject(execInfo.hProcess, INFINITE) != WAIT_OBJECT_0) {
+ reportError(QObject::tr("helper failed"));
+ return false;
+ }
+
+ DWORD exitCode;
+ GetExitCodeProcess(execInfo.hProcess, &exitCode);
+ return exitCode == NOERROR;
+}
+
+
+bool init(const std::wstring &moDirectory)
+{
+ DWORD userNameLen = UNLEN + 1;
+ wchar_t userName[UNLEN + 1];
+
+ if (!GetUserName(userName, &userNameLen)) {
+ reportError(QObject::tr("failed to determine account name"));
+ return false;
+ }
+ wchar_t *commandLine = new wchar_t[32768];
+
+ _snwprintf(commandLine, 32768, L"init \"%ls\" \"%ls\"",
+ moDirectory.c_str(), userName);
+
+ bool res = helperExec(moDirectory.c_str(), commandLine);
+ delete [] commandLine;
+
+ return res;
+}
+
+
+bool setNXMHandler(const std::wstring &moDirectory, bool enable)
+{
+ DWORD userNameLen = UNLEN + 1;
+ wchar_t userName[UNLEN + 1];
+
+ if (!GetUserName(userName, &userNameLen)) {
+ reportError(QObject::tr("failed to determine account name"));
+ return false;
+ }
+
+ wchar_t *commandLine = new wchar_t[32768];
+ _snwprintf(commandLine, 32768, L"handleNXM \"%ls\" %d",
+ moDirectory.c_str(), enable ? 1 : 0);
+
+ bool res = helperExec(moDirectory.c_str(), commandLine);
+ delete [] commandLine;
+
+ return res;
+}
+
+
+bool backdateBSAs(const std::wstring &moDirectory, const std::wstring &dataPath)
+{
+ wchar_t *commandLine = new wchar_t[32768];
+ _snwprintf(commandLine, 32768, L"backdateBSA \"%ls\"",
+ dataPath.c_str());
+
+ bool res = helperExec(moDirectory.c_str(), commandLine);
+ delete [] commandLine;
+
+ return res;
+}
+
+
+} // namespace
diff --git a/src/helper.h b/src/helper.h new file mode 100644 index 00000000..ee49a0cd --- /dev/null +++ b/src/helper.h @@ -0,0 +1,65 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef HELPER_H
+#define HELPER_H
+
+
+#include <QString>
+
+
+/**
+ * @brief Convenience functions to work with the external helper program.
+ *
+ * The mo_helper program is used to make changes on the system that require administrative
+ * rights, so that ModOrganizer itself can run without special privileges
+ **/
+namespace Helper {
+
+/**
+ * @brief initialise the specified directory for use with mod organizer.
+ *
+ * This will create all required sub-directories and give the user running ModOrganizer
+ * write-access
+ *
+ * @param moDirectory absolute path to the ModOrganizer base directory
+ * @return true on success
+ **/
+bool init(const std::wstring &moDirectory);
+
+/**
+ * @brief set or unset the current instance of ModOrganizer as the global handler for nxm links
+ *
+ * @param moDirectory absolute path to the modOrganizer base directory
+ * @param enable if true, ModOrganizer will become the handler for nxm links. If false, the nxm handler will be unset
+ * @return true on success
+ **/
+bool setNXMHandler(const std::wstring &moDirectory, bool enable);
+
+/**
+ * @brief sets the last modified time for all .bsa-files in the target directory well into the past
+ * @param moDirectory absolute path to the modOrganizer base directory
+ * @param dataPath the path taht contains the .bsa-files, usually the data directory of the game
+ **/
+bool backdateBSAs(const std::wstring &moDirectory, const std::wstring &dataPath);
+
+}
+
+
+#endif // HELPER_H
diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp new file mode 100644 index 00000000..859311fc --- /dev/null +++ b/src/icondelegate.cpp @@ -0,0 +1,77 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "icondelegate.h"
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPainter>
+
+
+IconDelegate::IconDelegate(QAbstractProxyModel *proxyModel, QObject *parent)
+ : QStyledItemDelegate(parent), m_ProxyModel(proxyModel)
+{
+}
+
+
+QIcon IconDelegate::getFlagIcon(ModInfo::EFlag flag) const
+{
+ switch (flag) {
+ case ModInfo::FLAG_BACKUP: return QIcon(":/MO/gui/emblem_backup");
+ case ModInfo::FLAG_INVALID: return QIcon(":/MO/gui/emblem_problem");
+ case ModInfo::FLAG_NOTENDORSED: return QIcon(":/MO/gui/emblem_notendorsed");
+ case ModInfo::FLAG_NOTES: return QIcon(":/MO/gui/emblem_notes");
+ case ModInfo::FLAG_CONFLICT_OVERWRITE: return QIcon(":/MO/gui/emblem_conflict_overwrite");
+ case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return QIcon(":/MO/gui/emblem_conflict_overwritten");
+ case ModInfo::FLAG_CONFLICT_MIXED: return QIcon(":/MO/gui/emblem_conflict_mixed");
+ case ModInfo::FLAG_CONFLICT_REDUNDANT: return QIcon(":MO/gui/emblem_conflict_redundant");
+ default: return QIcon();
+ }
+}
+
+
+void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyledItemDelegate::paint(painter, option, index);
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ProxyModel->mapToSource(index).row());
+ std::vector<ModInfo::EFlag> flags = info->getFlags();
+
+ int x = 4;
+ painter->save();
+ painter->translate(option.rect.topLeft());
+ for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
+ QIcon temp = getFlagIcon(*iter);
+ painter->drawPixmap(x, 2, 16, 16, temp.pixmap(QSize(16, 16)));
+ x += 20;
+ }
+
+ painter->restore();
+}
+
+
+QSize IconDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex &modelIndex) const
+{
+ unsigned int index = m_ProxyModel->mapToSource(modelIndex).row();
+ if (index < ModInfo::getNumMods()) {
+ ModInfo::Ptr info = ModInfo::getByIndex(index);
+ return QSize(info->getFlags().size() * 20, 20);
+ } else {
+ return QSize(1, 20);
+ }
+}
+
diff --git a/src/icondelegate.h b/src/icondelegate.h new file mode 100644 index 00000000..de49d810 --- /dev/null +++ b/src/icondelegate.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ICONDELEGATE_H
+#define ICONDELEGATE_H
+
+#include "modinfo.h"
+#include <QStyledItemDelegate>
+#include <QAbstractProxyModel>
+
+
+class IconDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+
+ explicit IconDelegate(QAbstractProxyModel *proxyModel, QObject *parent = 0);
+
+ virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+signals:
+
+public slots:
+
+private:
+
+ QIcon getFlagIcon(ModInfo::EFlag flag) const;
+
+private:
+
+ QAbstractProxyModel *m_ProxyModel;
+
+};
+
+#endif // ICONDELEGATE_H
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp new file mode 100644 index 00000000..e7784771 --- /dev/null +++ b/src/installationmanager.cpp @@ -0,0 +1,1302 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "installationmanager.h" + +#include "utility.h" +#include "installdialog.h" +#include "simpleinstalldialog.h" +#include "baincomplexinstallerdialog.h" +#include "fomodinstallerdialog.h" +#include "report.h" +#include "categories.h" +#include <scopeguard.h> +#include "questionboxmemory.h" +#include "settings.h" +#include "queryoverwritedialog.h" +#include "messagedialog.h" +#include "iplugininstallersimple.h" +#include "iplugininstallercustom.h" +#include "nexusinterface.h" +#include "selectiondialog.h" +#include <installationtester.h> +#include <gameinfo.h> +#include <QFileInfo> +#include <QLibrary> +#include <QInputDialog> +#include <QRegExp> +#include <QDir> +#include <QMessageBox> +#include <QSettings> +#include <Shellapi.h> +#include <QPushButton> +#include <QApplication> +#include <QDirIterator> +#include <boost/assign.hpp> + + +typedef Archive* (*CreateArchiveType)(); + + + +template <typename T> T resolveFunction(QLibrary &lib, const char *name) +{ + T temp = reinterpret_cast<T>(lib.resolve(name)); + if (temp == NULL) { + throw std::runtime_error(QObject::tr("invalid 7-zip32.dll: %1").arg(lib.errorString()).toLatin1().constData()); + } + return temp; +} + + +InstallationManager::InstallationManager(QWidget *parent) + : QObject(parent), m_ParentWidget(parent), + m_NCCPath(QApplication::applicationDirPath() + "/NCC/NexusClientCLI.exe"), + m_InstallationProgress(parent), m_SupportedExtensions(boost::assign::list_of("zip")("rar")("7z")("fomod")) +{ + QLibrary archiveLib("dlls\\archive.dll"); + if (!archiveLib.load()) { + throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString())); + } + + CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive"); + + m_CurrentArchive = CreateArchiveFunc(); + if (!m_CurrentArchive->isValid()) { + throw MyException(getErrorString(m_CurrentArchive->getLastError())); + } + +} + + +InstallationManager::~InstallationManager() +{ + delete m_CurrentArchive; +} + + +void InstallationManager::queryPassword(LPSTR password) +{ + QString result = QInputDialog::getText(NULL, tr("Password required"), tr("Password"), QLineEdit::Password); + strncpy(password, result.toLocal8Bit().constData(), MAX_PASSWORD_LENGTH); +} + + +void InstallationManager::mapToArchive(const DirectoryTree::Node *node, std::wstring path, FileData * const *data) +{ + if (path.length() > 0) { + path.append(L"\\"); + } + + for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) { + data[iter->getIndex()]->setSkip(false); + data[iter->getIndex()]->setOutputFileName(path.substr().append(ToWString(iter->getName())).c_str()); + } + + for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { + if ((*iter)->getData().index != -1) { + data[(*iter)->getData().index]->setSkip(false); + data[(*iter)->getData().index]->setOutputFileName(path.substr().append(ToWString((*iter)->getData().name)).c_str()); + } + mapToArchive(*iter, path.substr().append(ToWString((*iter)->getData().name)), data); + } +} + + +void InstallationManager::mapToArchive(const DirectoryTree::Node *baseNode) +{ + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + // first disable all files + folders, we will re-enable those present in baseNode + for (size_t i = 0; i < size; ++i) { + data[i]->setSkip(true); + } + + std::wstring currentPath; + + mapToArchive(baseNode, currentPath, data); +} + + +bool InstallationManager::unpackPackageTXT() +{ + return unpackSingleFile("package.txt"); +} + + +bool InstallationManager::unpackSingleFile(const QString &fileName) +{ + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + QString baseName = QFileInfo(fileName).fileName(); + + bool available = false; + for (size_t i = 0; i < size; ++i) { + if (_wcsicmp(data[i]->getFileName(), ToWString(fileName).c_str()) == 0) { + available = true; + data[i]->setSkip(false); + data[i]->setOutputFileName(ToWString(baseName).c_str()); + m_TempFilesToDelete.insert(baseName); + } else { + data[i]->setSkip(true); + } + } + + if (available) { + m_InstallationProgress.setWindowTitle(tr("Extracting files")); + m_InstallationProgress.setLabelText(QString()); + m_InstallationProgress.setValue(0); + m_InstallationProgress.setWindowModality(Qt::WindowModal); + m_InstallationProgress.show(); + + bool res = m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(QDir::tempPath())).c_str(), + new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError)); + + m_InstallationProgress.hide(); + + return res; + } else { + return false; + } +} + + +QString InstallationManager::extractFile(const QString &fileName) +{ + if (unpackSingleFile(fileName)) { + QString tempFileName = QDir::tempPath().append("/").append(QFileInfo(fileName).fileName()); + + m_FilesToDelete.insert(tempFileName); + + return tempFileName; + } else { + return QString(); + } +} + + +QString canonicalize(const QString &name) +{ + QString result(name); + if ((result.startsWith('/')) || + (result.startsWith('\\'))) { + result.remove(0, 1); + } + result.replace('/', '\\'); + + return result; +} + + +QStringList InstallationManager::extractFiles(const QStringList &filesOrig) +{ + QStringList files; + + foreach (const QString &file, filesOrig) { + files.append(canonicalize(file)); + } + + QStringList result; + + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + for (size_t i = 0; i < size; ++i) { + if (files.contains(ToQString(data[i]->getFileName()), Qt::CaseInsensitive)) { + const wchar_t *baseName = wcsrchr(data[i]->getFileName(), '\\'); + if (baseName == NULL) { + baseName = wcsrchr(data[i]->getFileName(), '/'); + } + if (baseName == NULL) { + qCritical("failed to find backslash in %ls", data[i]->getFileName()); + continue; + } + data[i]->setOutputFileName(baseName); + + result.append(QDir::tempPath().append("/").append(ToQString(baseName))); + + data[i]->setSkip(false); + m_TempFilesToDelete.insert(ToQString(baseName)); + } else { + data[i]->setSkip(true); + } + } + + m_InstallationProgress.setWindowTitle(tr("Extracting files")); + m_InstallationProgress.setLabelText(QString()); + m_InstallationProgress.setValue(0); + m_InstallationProgress.setWindowModality(Qt::WindowModal); + m_InstallationProgress.show(); + + // unpack only the files we need for the installer + if (!m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(QDir::tempPath())).c_str(), + new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) { + throw std::runtime_error("extracting failed"); + } + + m_InstallationProgress.hide(); + return result; +} + +IPluginInstaller::EInstallResult InstallationManager::installArchive(const QString &modName, const QString &archiveName) +{ + QString temp = modName; + bool iniTweaks; + if (install(archiveName, "", "modsdir", false, true, temp, iniTweaks)) { + return IPluginInstaller::RESULT_SUCCESS; + } else { + return IPluginInstaller::RESULT_FAILED; + } +} + + +DirectoryTree *InstallationManager::createFilesTree() +{ + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + QScopedPointer<DirectoryTree> result(new DirectoryTree); + + for (size_t i = 0; i < size; ++i) { + // the files are in a flat list where each file has a a full path relative to the archive root + // to create a tree, we have to iterate over each path component of each. This could be sped up by + // grouping the filenames first, but so far there doesn't seem to be an actual performance problem + DirectoryTree::Node *currentNode = result.data(); + + QString fileName = ToQString(data[i]->getFileName()); + QStringList components = fileName.split("\\"); + + // iterate over all path-components of this filename (including the filename itself) + for (QStringList::iterator componentIter = components.begin(); componentIter != components.end(); ++componentIter) { + if (componentIter->size() == 0) { + // empty string indicates fileName is actually only a directory name and we have + // completely processed it already. + break; + } + + bool exists = false; + // test if this path is already in the tree + for (DirectoryTree::node_iterator nodeIter = currentNode->nodesBegin(); nodeIter != currentNode->nodesEnd(); ++nodeIter) { + if ((*nodeIter)->getData().name == *componentIter) { + currentNode = *nodeIter; + exists = true; + break; + } + } + + if (!exists) { + if (componentIter + 1 == components.end()) { + // last path component. directory or file? + if (data[i]->isDirectory()) { + // this is a bit problematic. archives will often only list directories if they are empty, + // otherwise the dir only appears in the path of a file. In the UI however we allow the user + // to uncheck all files in a directory while keeping the dir checked. Those directories are + // currently not installed. + DirectoryTree::Node *newNode = new DirectoryTree::Node; + newNode->setData(DirectoryTreeInformation(*componentIter, i)); + currentNode->addNode(newNode, false); + currentNode = newNode; + } else { + currentNode->addLeaf(FileTreeInformation(*componentIter, i)); + } + } else { + DirectoryTree::Node *newNode = new DirectoryTree::Node; + newNode->setData(DirectoryTreeInformation(*componentIter, -1)); + currentNode->addNode(newNode, false); + currentNode = newNode; + } + } + } + } + + return result.take(); +} + + +bool InstallationManager::isSimpleArchiveTopLayer(const DirectoryTree::Node *node, bool bainStyle) +{ + // see if there is at least one directory that makes sense on the top level + for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { + if ((bainStyle && InstallationTester::isTopLevelDirectoryBain((*iter)->getData().name)) || + (!bainStyle && InstallationTester::isTopLevelDirectory((*iter)->getData().name))) { + qDebug("%s on the top level", (*iter)->getData().name.toUtf8().constData()); + return true; + } + } + + // see if there is a file that makes sense on the top level + for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) { + if (InstallationTester::isTopLevelSuffix(iter->getName())) { + return true; + } + } + return false; +} + + +DirectoryTree::Node *InstallationManager::getSimpleArchiveBase(DirectoryTree *dataTree) +{ + DirectoryTree::Node *currentNode = dataTree; + + while (true) { + if (isSimpleArchiveTopLayer(currentNode, false)) { + return currentNode; + } else if ((currentNode->numLeafs() == 0) && + (currentNode->numNodes() == 1)) { + currentNode = *currentNode->nodesBegin(); + } else { + qDebug("not a simple archive"); + return NULL; + } + } +} + + +bool InstallationManager::checkBainPackage(DirectoryTree *dataTree) +{ + int numDirs = dataTree->numNodes(); + // each directory would have to serve as a top-level directory + for (DirectoryTree::const_node_iterator iter = dataTree->nodesBegin(); + iter != dataTree->nodesEnd(); ++iter) { + const QString &dirName = (*iter)->getData().name; + if ((dirName.compare("fomod", Qt::CaseInsensitive) == 0) || + (dirName.startsWith("--"))) { + --numDirs; + continue; + } + if (!isSimpleArchiveTopLayer(*iter, true)) { + qDebug("%s is not a top layer directory", (*iter)->getData().name.toUtf8().constData()); + return false; + } + } + + if (numDirs < 2) { + // a complex bain package contains at least 2 directories to choose from + qDebug("only %d dirs", numDirs); + return false; + } + + return true; +} + + +bool InstallationManager::checkNMMInstaller() +{ + return QFile::exists(m_NCCPath); +} + + +bool InstallationManager::checkFomodPackage(DirectoryTree *dataTree, QString &offset, bool &xmlInstaller) +{ + bool scriptInstaller = false; + xmlInstaller = false; + for (DirectoryTree::const_node_iterator iter = dataTree->nodesBegin(); + iter != dataTree->nodesEnd(); ++iter) { + const QString &dirName = (*iter)->getData().name; + if (dirName.compare("fomod", Qt::CaseInsensitive) == 0) { + for (DirectoryTree::const_leaf_iterator fileIter = (*iter)->leafsBegin(); + fileIter != (*iter)->leafsEnd(); ++fileIter) { + if (fileIter->getName().compare("ModuleConfig.xml", Qt::CaseInsensitive) == 0) { + xmlInstaller = true; + } else if (fileIter->getName().compare("script.cs", Qt::CaseInsensitive) == 0) { + scriptInstaller = true; + } + } + break; + } + } + if (!xmlInstaller && !scriptInstaller && (dataTree->numNodes() == 1) && (dataTree->numLeafs() == 0)) { + DirectoryTree::Node *node = *dataTree->nodesBegin(); + offset = node->getData().name; + return checkFomodPackage(node, offset, xmlInstaller); + } + + return (xmlInstaller || scriptInstaller); +} + + +void InstallationManager::updateProgress(float percentage) +{ + m_InstallationProgress.setValue(static_cast<int>(percentage * 100.0)); + if (m_InstallationProgress.wasCanceled()) { + m_CurrentArchive->cancel(); + m_InstallationProgress.reset(); + } +} + + +void InstallationManager::updateProgressFile(LPCWSTR fileName) +{ + m_InstallationProgress.setLabelText(QString::fromUtf16(fileName)); +} + + +void InstallationManager::report7ZipError(LPCWSTR errorMessage) +{ + reportError(QString::fromUtf16(errorMessage)); +} + + +QString InstallationManager::generateBackupName(const QString &directoryName) +{ + QString backupName = directoryName + "_backup"; + if (QDir(backupName).exists()) { + int idx = 2; + QString temp = backupName + QString::number(idx); + while (QDir(temp).exists()) { + ++idx; + temp = backupName + QString::number(idx); + } + backupName = temp; + } + return backupName; +} + + +bool InstallationManager::testOverwrite(const QString &modsDirectory, QString &modName) +{ + QString targetDirectory = QDir::fromNativeSeparators(modsDirectory.mid(0).append("\\").append(modName)); + + while (QDir(targetDirectory).exists()) { + QueryOverwriteDialog overwriteDialog(m_ParentWidget); + if (overwriteDialog.exec()) { + if (overwriteDialog.backup()) { + QString backupDirectory = generateBackupName(targetDirectory); + if (!copyDir(targetDirectory, backupDirectory, false)) { + reportError(tr("failed to create backup")); + return false; + } + } + if (overwriteDialog.action() == QueryOverwriteDialog::ACT_RENAME) { + bool ok = false; + QString name = QInputDialog::getText(m_ParentWidget, tr("Mod Name"), tr("Name"), + QLineEdit::Normal, modName, &ok); + if (ok && !name.isEmpty()) { + modName = name; + if (!ensureValidModName(modName)) {
+ return false;
+ }
+ targetDirectory = QDir::fromNativeSeparators(modsDirectory.mid(0).append("\\").append(modName)); + } + } else if (overwriteDialog.action() == QueryOverwriteDialog::ACT_REPLACE) { + // save original settings like categories. Because it makes sense + QString metaFilename = targetDirectory.mid(0).append("/meta.ini"); + QFile settingsFile(metaFilename); + QByteArray originalSettings; + if (settingsFile.open(QIODevice::ReadOnly)) { + originalSettings = settingsFile.readAll(); + settingsFile.close(); + } + + // remove the directory with all content, then recreate it empty + removeDir(targetDirectory); + if (!QDir().mkdir(targetDirectory)) { + // windows may keep the directory around for a moment, preventing its re-creation + Sleep(100); + QDir().mkdir(targetDirectory); + } + // restore the saved settings + if (settingsFile.open(QIODevice::WriteOnly)) { + settingsFile.write(originalSettings); + settingsFile.close(); + } else { + qCritical("failed to restore original settings: %s", metaFilename.toUtf8().constData()); + } + return true; + } else if (overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE) { + return true; + } + } else { + return false; + } + } + + QDir().mkdir(targetDirectory); + + return true; +} + + +void InstallationManager::fixModName(QString &name) +{ +// name = name.remove("^[ ]*").trimmed(); + name = name.simplified(); + while (name.endsWith('.')) name.chop(1);
+
+ name.replace(QRegExp("[<>:\"/\\|?*]"), "");
+
+ static QString invalidNames[] = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" };
+ for (int i = 0; i < sizeof(invalidNames) / sizeof(QString); ++i) {
+ if (name == invalidNames[i]) {
+ name = "";
+ break;
+ }
+ }
+} + + +bool InstallationManager::ensureValidModName(QString &name)
+{
+ fixModName(name);
+
+ while (name.isEmpty()) {
+ bool ok;
+ name = QInputDialog::getText(m_ParentWidget, tr("Invalid name"),
+ tr("The name you entered is invalid, please enter a different one."),
+ QLineEdit::Normal, "", &ok);
+ if (!ok) {
+ return false;
+ }
+ fixModName(name);
+ }
+ return true;
+}
+
+
+bool InstallationManager::doInstall(const QString &modsDirectory, QString &modName, int modID,
+ const QString &version, const QString &newestVersion, int categoryID) +{ + if (!ensureValidModName(modName)) {
+ return false;
+ }
+
+ // determine target directory + if (!testOverwrite(modsDirectory, modName)) { + return false; + } + + QString targetDirectory = QDir::fromNativeSeparators(modsDirectory.mid(0).append("\\").append(modName)); + + qDebug("installing to \"%s\"", targetDirectory.toUtf8().constData()); + + m_InstallationProgress.setWindowTitle(tr("Extracting files")); + m_InstallationProgress.setLabelText(QString()); + m_InstallationProgress.setValue(0); + m_InstallationProgress.setWindowModality(Qt::WindowModal); + m_InstallationProgress.show(); + + if (!m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(targetDirectory)).c_str(), + new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::updateProgressFile), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) { + if (m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) { + return false; + } else { + throw std::runtime_error("extracting failed"); + } + } + + m_InstallationProgress.hide(); + + QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat); + + // overwrite settings only if they are actually are available or haven't been set before + if ((modID != 0) || !settingsFile.contains("modid")) { + settingsFile.setValue("modid", modID); + } + if (!version.isEmpty() || !settingsFile.contains("version")) { + settingsFile.setValue("version", version); + } + if (!newestVersion.isEmpty() || !settingsFile.contains("newestVersion")) { + settingsFile.setValue("newestVersion", newestVersion); + } + // issue #51 used to overwrite the manually set categories + if (!settingsFile.contains("category")) { + settingsFile.setValue("category", QString::number(categoryID)); + } + settingsFile.setValue("installationFile", m_CurrentFile); + + return true; +} + + +void InstallationManager::openFile(const QString &fileName) +{ + unpackSingleFile(fileName); + + QString tempFileName = QDir::tempPath().append("/").append(QFileInfo(fileName).fileName()); + + SHELLEXECUTEINFOW execInfo; + memset(&execInfo, 0, sizeof(SHELLEXECUTEINFOW)); + execInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + execInfo.lpVerb = L"open"; + std::wstring fileNameW = ToWString(tempFileName); + execInfo.lpFile = fileNameW.c_str(); + execInfo.nShow = SW_SHOWNORMAL; + if (!::ShellExecuteExW(&execInfo)) { + qCritical("failed to spawn %s: %d", tempFileName.toUtf8().constData(), ::GetLastError()); + } + + m_FilesToDelete.insert(tempFileName); +} + + +// copy and pasted from mo_dll +bool EndsWith(LPCWSTR string, LPCWSTR subString) +{ + size_t slen = wcslen(string); + size_t len = wcslen(subString); + if (slen < len) { + return false; + } + + for (size_t i = 0; i < len; ++i) { + if (towlower(string[slen - len + i]) != towlower(subString[i])) { + return false; + } + } + return true; +} + + +bool InstallationManager::installFomodInternal(DirectoryTree *&baseNode, const QString &fomodPath, const QString &modsDirectory, + int modID, const QString &version, const QString &newestVersion, int categoryID, + QString &modName, bool &manualRequest) +{ + qDebug("treating as fomod archive"); + + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + wchar_t *installerFiles[] = { L"fomod\\info.xml", L"fomod\\ModuleConfig.xml", + L"fomod\\script.cs", L"fomod\\screenshot.png", NULL }; + for (size_t i = 0; i < size; ++i) { + data[i]->setSkip(true); + if (data[i]->getFileName() == NULL) { + qCritical("invalid archive file name"); + } + for (int fileIdx = 0; installerFiles[fileIdx] != NULL; ++fileIdx) { + if (EndsWith(data[i]->getFileName(), installerFiles[fileIdx])) { + wchar_t *baseName = wcsrchr(installerFiles[fileIdx], '\\'); + if (baseName != NULL) { + data[i]->setSkip(false); + data[i]->setOutputFileName(baseName); + m_TempFilesToDelete.insert(ToQString(baseName)); + } else { + qCritical("failed to find backslash in %ls", installerFiles[fileIdx]); + } + break; + } + } + if (EndsWith(data[i]->getFileName(), L".png") || + EndsWith(data[i]->getFileName(), L".jpg") || + EndsWith(data[i]->getFileName(), L".gif") || + EndsWith(data[i]->getFileName(), L".bmp")) { + const wchar_t *baseName = wcsrchr(data[i]->getFileName(), '\\'); + if (baseName == NULL) { + baseName = data[i]->getFileName(); + } else { + ++baseName; + } + data[i]->setSkip(false); + data[i]->setOutputFileName(baseName); + m_TempFilesToDelete.insert(ToQString(baseName)); + } + } + + m_InstallationProgress.setWindowTitle(tr("Preparing installer")); + m_InstallationProgress.setLabelText(QString()); + m_InstallationProgress.setValue(0); + m_InstallationProgress.setWindowModality(Qt::WindowModal); + m_InstallationProgress.show(); + + // unpack only the files we need for the installer + if (!m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(QDir::tempPath())).c_str(), + new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile), + new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) { + throw std::runtime_error("extracting failed"); + } + + m_InstallationProgress.hide(); + + bool success = false; + try { + FomodInstallerDialog dialog(modName, fomodPath); + + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + // the installer will want to unpack screenshots... + for (size_t i = 0; i < size; ++i) { + data[i]->setSkip(true); + } + + dialog.initData(); + if (dialog.exec() == QDialog::Accepted) { + modName = dialog.getName(); + baseNode = dialog.updateTree(baseNode); + mapToArchive(baseNode); + + if (doInstall(modsDirectory, modName, modID, version, newestVersion, categoryID)) { + success = true; + } + } else { + if (dialog.manualRequested()) { + manualRequest = true; + modName = dialog.getName(); + } + } + } catch (const std::exception &e) { + reportError(tr("Installation as fomod failed: %1").arg(e.what())); + manualRequest = true; + } + return success; +} + + +bool InstallationManager::installFomodExternal(const QString &fileName, const QString &pluginsFileName, const QString &modDirectory) +{ + wchar_t binary[MAX_PATH]; + wchar_t parameters[1024]; // maximum: 2xMAX_PATH + approx 20 characters + wchar_t currentDirectory[MAX_PATH]; + + _snwprintf(binary, MAX_PATH, L"%ls", ToWString(QDir::toNativeSeparators(m_NCCPath)).c_str()); + _snwprintf(parameters, 1024, L"-g %ls -p \"%ls\" -i \"%ls\" \"%ls\"", + GameInfo::instance().getGameShortName().c_str(), + ToWString(QDir::toNativeSeparators(pluginsFileName)).c_str(), + ToWString(QDir::toNativeSeparators(fileName)).c_str(), + ToWString(QDir::toNativeSeparators(modDirectory)).c_str()); + _snwprintf(currentDirectory, MAX_PATH, L"%ls", ToWString(QFileInfo(m_NCCPath).absolutePath()).c_str()); + + GameInfo &gameInfo = GameInfo::instance(); + + QString binaryDestination = modDirectory.mid(0).append("/").append(ToQString(gameInfo.getBinaryName())); + + // NCC assumes the installation directory is the game directory and may try to access the binary to determine version information + QFile::copy(QDir::fromNativeSeparators(ToQString(gameInfo.getGameDirectory().append(L"\\").append(gameInfo.getBinaryName()))), + binaryDestination); + + ON_BLOCK_EXIT([&binaryDestination] { QFile::remove(binaryDestination); } ); + + SHELLEXECUTEINFOW execInfo = {0}; + execInfo.cbSize = sizeof(SHELLEXECUTEINFOW); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + execInfo.hwnd = NULL; + execInfo.lpVerb = L"open"; + execInfo.lpFile = binary; + execInfo.lpParameters = parameters; + execInfo.lpDirectory = currentDirectory; + execInfo.nShow = SW_SHOW; + + if (!::ShellExecuteExW(&execInfo)) { + reportError(tr("failed to start %1").arg(m_NCCPath)); + return false; + } + + QProgressDialog busyDialog(tr("Running external installer.\nNote: This installer will not be aware of other installed mods!"), tr("Force Close"), 0, 0, m_ParentWidget); + busyDialog.setWindowModality(Qt::WindowModal); + bool confirmCancel = false; + busyDialog.show(); + bool finished = false; + while (true) { + QCoreApplication::processEvents(); + DWORD res = ::WaitForSingleObject(execInfo.hProcess, 100); + if (res == WAIT_OBJECT_0) { + finished = true; + break; + } else if ((busyDialog.wasCanceled()) || (res != WAIT_TIMEOUT)) { + if (!confirmCancel) { + confirmCancel = true; + busyDialog.hide(); + busyDialog.reset(); + busyDialog.show(); + busyDialog.setCancelButtonText(tr("Confirm")); + } else { + break; + } + } + } + + if (!finished) { + ::TerminateProcess(execInfo.hProcess, 1); + return false; + } + + DWORD exitCode = 128; + ::GetExitCodeProcess(execInfo.hProcess, &exitCode); + + ::CloseHandle(execInfo.hProcess); + + + if ((exitCode == 0) || (exitCode == 10)) { // 0 = success, 10 = incomplete installation + bool errorOccured = false; + { // move all installed files from the data directory one directory up + QDirIterator dirIter(QDir(modDirectory).absoluteFilePath("Data"), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + bool hasFiles = false; + while (dirIter.hasNext()) { + dirIter.next(); + QFileInfo fileInfo = dirIter.fileInfo(); + + QDir dir(fileInfo.absolutePath()); + dir.cdUp(); + QString newName = dir.absoluteFilePath(fileInfo.fileName()); + if (QFile::exists(newName)) { + if (!QFile::remove(newName)) { + qCritical("failed to overwrite %s", qPrintable(newName)); + errorOccured = true; + } + } + if (!QFile::rename(fileInfo.absoluteFilePath(), newName)) { + qCritical("failed to move %s to %s", qPrintable(fileInfo.absoluteFilePath()), qPrintable(newName)); + errorOccured = true; + } + hasFiles = true; + } + // recognition of canceled installation in the external installer is broken so we assume the installation was + // canceled if no files were installed + if (!hasFiles) { + exitCode = 11; + } + } + + QString dataDir = modDirectory.mid(0).append("/Data"); + if (!removeDir(dataDir)) { + qCritical("failed to remove data directory from %s", dataDir.toUtf8().constData()); + errorOccured = true; + } + if (errorOccured) { + reportError(tr("Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details")); + } + } else if (exitCode != 11) { // 11 = manually canceled + reportError(tr("installation failed (errorcode %1)").arg(exitCode)); + } + + if ((exitCode == 0) || (exitCode == 10)) { + return true; + } else { + // after cancelation or error the installer may leave the empty mod directory + if (!removeDir(modDirectory)) { + qCritical ("failed to remove empty mod directory %s", modDirectory.toUtf8().constData()); + } + return false; + } +} + + +bool InstallationManager::wasCancelled() +{ + return m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED; +} + + +bool InstallationManager::install(const QString &fileName, const QString &pluginsFileName, const QString &modsDirectory, + bool preferIntegrated, bool enableQuickInstall, QString &modName, bool &hasIniTweaks) +{ + QFileInfo fileInfo(fileName); + bool success = false; + if (m_SupportedExtensions.find(fileInfo.suffix()) == m_SupportedExtensions.end()) { + reportError(tr("File format \"%1\" not supported").arg(fileInfo.completeSuffix())); + return false; + } + + // read out meta information from the download if available + int modID = 0; + QString version = ""; + QString newestVersion = ""; + int categoryID = 0; + + QString metaName = fileName.mid(0).append(".meta"); + if (QFile(metaName).exists()) { + QSettings metaFile(metaName, QSettings::IniFormat); + modID = metaFile.value("modID", 0).toInt(); + if (modName.isEmpty()) { + modName = metaFile.value("modName", "").toString(); + // it is possible we have a file-name but not the correct mod name. in this case, + // the stored mod name may be "\0" + if (modName.isEmpty() || (modName.length() < 2)) { + modName = metaFile.value("name", "").toString(); + } + } + version = metaFile.value("version", "").toString(); + newestVersion = metaFile.value("newestVersion", "").toString(); + unsigned int categoryIndex = CategoryFactory::instance().resolveNexusID(metaFile.value("category", 0).toInt()); + categoryID = CategoryFactory::instance().getCategoryID(categoryIndex); + } + + { // guess the mod name and mod if from the file name if there was no meta information + QString guessedModName; + int guessedModID = modID;
+ NexusInterface::interpretNexusFileName(QFileInfo(fileName).baseName(), guessedModName, guessedModID, false);
+ if ((modID == 0) && (guessedModID != -1)) {
+ modID = guessedModID; + } else if (modID != guessedModID) { + qDebug("passed mod id: %d, guessed id: %d", modID, guessedModID); + } + + if (modName.isEmpty()) { + modName = guessedModName; + } + } + fixModName(modName); + + qDebug("using mod name \"%s\" (id %d)", modName.toUtf8().constData(), modID); + m_CurrentFile = fileInfo.fileName(); + + // open the archive and construct the directory tree the installers work on + bool archiveOpen = m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(fileName)).c_str(), + new MethodCallback<InstallationManager, void, LPSTR>(this, &InstallationManager::queryPassword)); + + DirectoryTree *filesTree = archiveOpen ? createFilesTree() : NULL; + +/* IPluginInstaller::EInstallResult installResult = IPluginInstaller::RESULT_NOTATTEMPTED; + + std::sort(m_Installers.begin(), m_Installers.end(), [] (IPluginInstaller *LHS, IPluginInstaller *RHS) { + return LHS->priority() > RHS->priority(); + }); + + foreach (IPluginInstaller *installer, m_Installers) { + // don't use inactive installers + if (!installer->isActive()) { + continue; + } + + // try only manual installers if that was requested + if ((installResult == IPluginInstaller::RESULT_MANUALREQUESTED) && !installer->isManualInstaller()) { + continue; + } + + try { + { // simple case + IPluginInstallerSimple *installerSimple = dynamic_cast<IPluginInstallerSimple*>(installer); + + if ((installerSimple != NULL) && + (filesTree != NULL) && (installer->isArchiveSupported(*filesTree))) { + installResult = installerSimple->install(modName, *filesTree); + if (installResult == IPluginInstaller::RESULT_SUCCESS) { + mapToArchive(filesTree); + if (!doInstall(modsDirectory, modName, modID, version, newestVersion, categoryID)) { + installResult = IPluginInstaller::RESULT_FAILED; + } + } + } + } + + { // custom case + IPluginInstallerCustom *installerCustom = dynamic_cast<IPluginInstallerCustom*>(installer); + if ((installerCustom != NULL) && + (((filesTree != NULL) && installer->isArchiveSupported(*filesTree)) || + ((filesTree == NULL) && installerCustom->isArchiveSupported(fileName)))) { + std::set<QString> installerExtensions = installerCustom->supportedExtensions(); + if (installerExtensions.find(fileInfo.suffix()) != installerExtensions.end()) { + installResult = installerCustom->install(modName, fileName); + } + } + } + } catch (const IncompatibilityException &e) { + qCritical("plugin \"%s\" incompatible: %s", + qPrintable(installer->name()), e.what()); + } + + // act upon the installation result. at this point the files have already been + // extracted to the correct location + switch (installResult) { + case IPluginInstaller::RESULT_CANCELED: + case IPluginInstaller::RESULT_FAILED: { + return false; + } break; + case IPluginInstaller::RESULT_SUCCESS: { + DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + return true; + } break; + } + } + + reportError(tr("None of the available installer plugins were able to handle that archive")); + return false;*/ + + + + hasIniTweaks = false; + + + DirectoryTree::Node *baseNode = NULL; + bool manualRequest = false; + + if (!archiveOpen) { + reportError(tr("Failed to open \"%1\": %2").arg(QDir::toNativeSeparators(fileName)).arg(getErrorString(m_CurrentArchive->getLastError()))); + return false; + } + + // bundled fomod? + if ((baseNode == NULL) && !manualRequest) { + QStringList bundledFomods; + for (DirectoryTree::const_leaf_iterator fileIter = filesTree->leafsBegin(); fileIter != filesTree->leafsEnd(); ++fileIter) { + if (fileIter->getName().endsWith(".fomod", Qt::CaseInsensitive)) { + bundledFomods.append(fileIter->getName()); + } + } + QString bundledFomodInst; + if (bundledFomods.count() > 1) { + SelectionDialog selection(tr("This seems like a bundle of fomods, which one do you want to install?"), m_ParentWidget); + foreach (const QString &fomod, bundledFomods) { + selection.addChoice(fomod, fomod, QVariant()); + } + if (selection.exec() == QDialog::Accepted) { + bundledFomodInst = selection.getChoiceString(); + } else { + return false; + } + } else if (bundledFomods.count() == 1) { + bundledFomodInst = bundledFomods.at(0); + qDebug("archive contains fomod: %s", qPrintable(bundledFomodInst)); + } + if (!bundledFomodInst.isEmpty()) { + unpackSingleFile(bundledFomodInst); + m_CurrentArchive->close(); + return install(QDir::tempPath().append("/").append(bundledFomodInst), pluginsFileName, modsDirectory, preferIntegrated, + enableQuickInstall, modName, hasIniTweaks); + } + } + + // fomod installer? + if ((baseNode == NULL) && !manualRequest) { + QString fomodPath; + bool xmlInstaller = false; + if (checkFomodPackage(filesTree, fomodPath, xmlInstaller)) { + baseNode = filesTree; + bool nmmInstaller = checkNMMInstaller(); + + if (xmlInstaller || nmmInstaller) { + if (!xmlInstaller || (nmmInstaller && !preferIntegrated)) { + if (!ensureValidModName(modName) ||
+ !testOverwrite(modsDirectory, modName)) {
+ return false; + } + + QString targetDirectory = QDir::fromNativeSeparators(modsDirectory.mid(0).append("\\").append(modName)); + + if (installFomodExternal(fileName, pluginsFileName, targetDirectory)) { + QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat); + + // overwrite settings only if they are actually are available or haven't been set before + if ((modID != 0) || !settingsFile.contains("modid")) { + settingsFile.setValue("modid", modID); + } + if (!version.isEmpty() || !settingsFile.contains("version")) { + settingsFile.setValue("version", version); + } + if (!newestVersion.isEmpty() || !settingsFile.contains("newestVersion")) { + settingsFile.setValue("newestVersion", newestVersion); + } + if (!settingsFile.contains("category")) { + settingsFile.setValue("category", QString::number(categoryID)); + } + settingsFile.setValue("installationFile", m_CurrentFile); + + success = true; + } + } else { + if (installFomodInternal(baseNode, fomodPath, modsDirectory, + modID, version, newestVersion, categoryID, + modName, manualRequest)) { + success = true; + } + } + if (success) { + DirectoryTree::node_iterator iniTweakNode = baseNode->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != baseNode->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + } + if (baseNode != filesTree) { + delete baseNode; + } + } else { + if (QuestionBoxMemory::query(m_ParentWidget, Settings::instance().directInterface(), "missingNCC", + tr("Installer missing"), + tr("This package contains a scripted installer. To use this installer " + "you need the optional \"NCC\"-package and the .net runtime. " + "Do you want to continue, treating this as a manual installer?"), + QDialogButtonBox::Yes | QDialogButtonBox::Cancel) == QMessageBox::Yes) { + manualRequest = true; + } else { + MessageDialog::showMessage(tr("Please install NCC"), m_ParentWidget); + } + } + } + } + + // simple installer? + if ((baseNode == NULL) && enableQuickInstall && !manualRequest) { + baseNode = getSimpleArchiveBase(filesTree); + if (baseNode != NULL) { + qDebug("treating as simple archive (%d)", baseNode->numLeafs()); + SimpleInstallDialog dialog(modName, m_ParentWidget); + if (dialog.exec() == QDialog::Accepted) { + mapToArchive(baseNode); + modName = dialog.getName(); + if (doInstall(modsDirectory, modName, modID, version, newestVersion, categoryID)) { + success = true; + + DirectoryTree::node_iterator iniTweakNode = baseNode->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != baseNode->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + } + } else { + if (dialog.manualRequested()) { + manualRequest = true; + modName = dialog.getName(); + } + } + } + } + + // bain complex package? + if ((baseNode == NULL) && !manualRequest) { + if (checkBainPackage(filesTree)) { + bool hasPackageTXT = unpackPackageTXT(); + + baseNode = filesTree; + qDebug("treating as complex archive (%d)", filesTree->numNodes()); + BainComplexInstallerDialog dialog(filesTree, modName, hasPackageTXT, m_ParentWidget); + if (dialog.exec() == QDialog::Accepted) { + modName = dialog.getName(); + // create a new tree with the selected directories mapped to the + // base directory. This is destructive on the original tree + baseNode = dialog.updateTree(baseNode); + mapToArchive(baseNode); + + if (doInstall(modsDirectory, modName, modID, version, newestVersion, categoryID)) { + success = true; + + DirectoryTree::node_iterator iniTweakNode = baseNode->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != baseNode->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + } + delete baseNode; + } else { + if (dialog.manualRequested()) { + manualRequest = true; + modName = dialog.getName(); + } + } + QFile::remove(QDir::tempPath().append("/package.txt")); + } + } + + // final option: manual installer + if ((baseNode == NULL) || manualRequest) { + qDebug("offering installation dialog"); + InstallDialog dialog(filesTree, modName, m_ParentWidget); + connect(&dialog, SIGNAL(openFile(QString)), this, SLOT(openFile(QString))); + if (dialog.exec() == QDialog::Accepted) { + modName = dialog.getModName(); + baseNode = dialog.getDataTree(); + mapToArchive(baseNode); + if (doInstall(modsDirectory, modName, modID, version, newestVersion, categoryID)) { + success = true; + + DirectoryTree::node_iterator iniTweakNode = baseNode->nodeFind(DirectoryTreeInformation("INI Tweaks")); + hasIniTweaks = (iniTweakNode != baseNode->nodesEnd()) && + ((*iniTweakNode)->numLeafs() != 0); + } + delete baseNode; // baseNode is a new tree, independent of filesTree + } + } + + delete filesTree; + m_CurrentArchive->close(); + + for (std::set<QString>::iterator iter = m_FilesToDelete.begin(); + iter != m_FilesToDelete.end(); ++iter) { + QFile(*iter).remove(); + } + m_FilesToDelete.clear(); + + for (std::set<QString>::iterator iter = m_TempFilesToDelete.begin(); + iter != m_TempFilesToDelete.end(); ++iter) { + QFile(QDir::tempPath().append("/").append(*iter)).remove(); + } + + m_TempFilesToDelete.clear(); + + return success; +} + + + +QString InstallationManager::getErrorString(Archive::Error errorCode) +{ + switch (errorCode) { + case Archive::ERROR_NONE: { + return tr("no error"); + } break; + case Archive::ERROR_LIBRARY_NOT_FOUND: { + return tr("7z.dll not found"); + } break; + case Archive::ERROR_LIBRARY_INVALID: { + return tr("7z.dll isn't valid"); + } break; + case Archive::ERROR_ARCHIVE_NOT_FOUND: { + return tr("archive not found"); + } break; + case Archive::ERROR_FAILED_TO_OPEN_ARCHIVE: { + return tr("failed to open archive"); + } break; + case Archive::ERROR_INVALID_ARCHIVE_FORMAT: { + return tr("unsupported archive type"); + } break; + case Archive::ERROR_LIBRARY_ERROR: { + return tr("internal library error"); + } break; + case Archive::ERROR_ARCHIVE_INVALID: { + return tr("archive invalid"); + } break; + default: { + // this probably means the archiver.dll is newer than this + return tr("unknown archive error"); + } break; + } +} + + +void InstallationManager::registerInstaller(IPluginInstaller *installer) +{ + m_Installers.push_back(installer); + installer->setInstallationManager(this); + IPluginInstallerCustom *installerCustom = dynamic_cast<IPluginInstallerCustom*>(installer); + if (installerCustom != NULL) { + std::set<QString> extensions = installerCustom->supportedExtensions(); + m_SupportedExtensions.insert(extensions.begin(), extensions.end()); + } +} + +QStringList InstallationManager::getSupportedExtensions() const +{ + QStringList result; + foreach (const QString &extension, m_SupportedExtensions) { + result.append(extension); + } + return result; +} diff --git a/src/installationmanager.h b/src/installationmanager.h new file mode 100644 index 00000000..9ac97812 --- /dev/null +++ b/src/installationmanager.h @@ -0,0 +1,210 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef INSTALLATIONMANAGER_H
+#define INSTALLATIONMANAGER_H
+
+#include "installdialog.h"
+
+#include <iinstallationmanager.h>
+#include <iplugininstaller.h>
+
+#include <QObject>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <archive.h>
+#include <QProgressDialog>
+#include <set>
+#include <errorcodes.h>
+
+
+/**
+ * @brief manages the installation of mod archives
+ * This currently supports two special kind of archives:
+ * - "simple" archives: properly packaged archives without options, so they can be extracted to the (virtual) data directory directly
+ * - "complex" bain archives: archives with options for the bain system.
+ * All other archives are managed through the manual "InstallDialog"
+ * @todo this may be a good place to support plugins
+ **/
+class InstallationManager : public QObject, public IInstallationManager
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param parent parent object.
+ **/
+ explicit InstallationManager(QWidget *parent);
+
+ ~InstallationManager();
+
+ /**
+ * @brief install a mod from an archive
+ *
+ * @param fileName absolute file name of the archive to install
+ * @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod
+ * @param preferIntegrated if true, integrated installers are chosen over external installers
+ * @return true if the archive was installed, false if installation failed or was refused
+ * @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged)
+ **/
+ bool install(const QString &fileName, const QString &pluginsFileName, const QString &modsDirectory, bool preferIntegrated, bool enableQuickInstall, QString &modName, bool &hasIniTweaks);
+
+ /**
+ * @return true if the installation was canceled
+ **/
+ bool wasCancelled();
+
+ /**
+ * @brief retrieve a string describing the specified error code
+ *
+ * @param errorCode an error code as returned by the archiving function
+ * @return the error string
+ * @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file
+ **/
+ static QString getErrorString(Archive::Error errorCode);
+
+ void installManual(DirectoryTree::Node *baseNode, DirectoryTree *filesTree, bool &hasIniTweaks, QString &modName, int categoryID, const QString &modsDirectory, QString newestVersion, QString version, int modID, bool success, bool manualRequest);
+
+ /**
+ * @brief register an installer-plugin
+ * @param the installer to register
+ */
+ void registerInstaller(IPluginInstaller *installer);
+
+ /**
+ * @return list of file extensions we can install
+ */
+ QStringList getSupportedExtensions() const;
+
+ /**
+ * @brief extract the specified file from the currently open archive to a temporary location
+ * @param (relative) name of the file within the archive
+ * @return the absolute name of the temporary file
+ * @note the call will fail with an exception if no archive is open (plugins deriving
+ * from IPluginInstallerSimple can rely on that, custom installers shouldn't)
+ * @note the temporary file is automatically cleaned up after the installation
+ * @note This call can be very slow if the archive is large and "solid"
+ */
+ virtual QString extractFile(const QString &fileName);
+
+ /**
+ * @brief extract the specified files from the currently open archive to a temporary location
+ * @param (relative) names of files within the archive
+ * @return the absolute names of the temporary files
+ * @note the call will fail with an exception if no archive is open (plugins deriving
+ * from IPluginInstallerSimple can rely on that, custom installers shouldn't)
+ * @note the temporary file is automatically cleaned up after the installation
+ * @note This call can be very slow if the archive is large and "solid"
+ */
+ virtual QStringList extractFiles(const QStringList &files);
+
+ /**
+ * @brief installs an archive
+ * @param modName suggested name of the mod
+ * @param archiveFile path to the archive to install
+ * @return the installation result
+ */
+ virtual IPluginInstaller::EInstallResult installArchive(const QString &modName, const QString &archiveName);
+
+private:
+
+ void queryPassword(LPSTR password);
+ void updateProgress(float percentage);
+ void updateProgressFile(LPCWSTR fileName);
+ void report7ZipError(LPCWSTR errorMessage);
+
+ void dummyProgressFile(LPCWSTR) {}
+
+ DirectoryTree *createFilesTree();
+
+ // remap all files in the archive to the directory structure represented by baseNode
+ // files not present in baseNode are disabled
+ void mapToArchive(const DirectoryTree::Node *baseNode);
+
+ // recursive worker function for mapToArchive
+ void mapToArchive(const DirectoryTree::Node *node, std::wstring path, FileData * const *data);
+ bool unpackPackageTXT();
+ bool unpackSingleFile(const QString &fileName);
+
+
+ bool isSimpleArchiveTopLayer(const DirectoryTree::Node *node, bool bainStyle);
+ DirectoryTree::Node *getSimpleArchiveBase(DirectoryTree *dataTree);
+ bool checkBainPackage(DirectoryTree *dataTree);
+ bool checkFomodPackage(DirectoryTree *dataTree, QString &offset, bool &xmlInstaller);
+ bool checkNMMInstaller();
+
+ void fixModName(QString &name);
+
+ bool testOverwrite(const QString &modsDirectory, QString &modName);
+
+ bool doInstall(const QString &modsDirectory, QString &modName,
+ int modID, const QString &version, const QString &newestVersion, int categoryID);
+
+ bool installFomodExternal(const QString &fileName, const QString &pluginsFileName, const QString &modDirectory);
+ bool installFomodInternal(DirectoryTree *&baseNode, const QString &fomodPath, const QString &modsDirectory,
+ int modID, const QString &version, const QString &newestVersion,
+ int categoryID, QString &modName, bool &manualRequest);
+ QString generateBackupName(const QString &directoryName);
+
+ bool ensureValidModName(QString &name);
+
+private slots:
+
+ void openFile(const QString &fileName);
+
+private:
+
+ struct ByPriority {
+ bool operator()(IPluginInstaller *LHS, IPluginInstaller *RHS) const
+ {
+ return LHS->priority() > RHS->priority();
+ }
+ };
+
+ struct CaseInsensitive {
+ bool operator() (const QString &LHS, const QString &RHS) const
+ {
+ return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0;
+ }
+ };
+
+private:
+
+ QWidget *m_ParentWidget;
+
+ std::vector<IPluginInstaller*> m_Installers;
+ std::set<QString, CaseInsensitive> m_SupportedExtensions;
+
+ QString m_NCCPath;
+
+ Archive *m_CurrentArchive;
+ QString m_CurrentFile;
+
+ QProgressDialog m_InstallationProgress;
+
+ std::set<QString> m_FilesToDelete;
+ std::set<QString> m_TempFilesToDelete;
+
+};
+
+
+#endif // INSTALLATIONMANAGER_H
diff --git a/src/installdialog.cpp b/src/installdialog.cpp new file mode 100644 index 00000000..0ad7dc60 --- /dev/null +++ b/src/installdialog.cpp @@ -0,0 +1,305 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "installdialog.h"
+#include "ui_installdialog.h"
+
+#include "report.h"
+#include "utility.h"
+#include "installationtester.h"
+
+#include <QMenu>
+#include <QInputDialog>
+#include <QMessageBox>
+
+
+InstallDialog::InstallDialog(DirectoryTree *tree, const QString &modName, QWidget *parent)
+ : TutorableDialog("InstallDialog", parent), ui(new Ui::InstallDialog),
+ m_DataTree(tree), m_TreeRoot(NULL), m_DataRoot(NULL), m_TreeSelection(NULL),
+ m_Updating(false)
+{
+ ui->setupUi(this);
+
+ QLineEdit *editName = findChild<QLineEdit*>("editName");
+ editName->setText(modName);
+
+ m_Tree = findChild<ArchiveTree*>("treeContent");
+
+ m_ProblemLabel = findChild<QLabel*>("problemLabel");
+
+ connect(m_Tree, SIGNAL(changed()), this, SLOT(treeChanged()));
+
+ updatePreview();
+}
+
+InstallDialog::~InstallDialog()
+{
+ delete ui;
+}
+
+
+QString InstallDialog::getModName() const
+{
+ QLineEdit *editName = findChild<QLineEdit*>("editName");
+ return editName->text();
+}
+
+
+void InstallDialog::mapDataNode(DirectoryTree::Node *node, QTreeWidgetItem *baseItem) const
+{
+ for (int i = 0; i < baseItem->childCount(); ++i) {
+ QTreeWidgetItem *currentItem = baseItem->child(i);
+
+ if (currentItem->checkState(0) != Qt::Unchecked) {
+ if (currentItem->data(0, Qt::UserRole).isNull()) {
+ DirectoryTree::Node *newNode = new DirectoryTree::Node;
+ newNode->setData(currentItem->text(0));
+ mapDataNode(newNode, currentItem);
+ node->addNode(newNode, true);
+ } else {
+ node->addLeaf(FileTreeInformation(currentItem->text(0), currentItem->data(0, Qt::UserRole).toInt()));
+ }
+ }
+ }
+}
+
+
+DirectoryTree *InstallDialog::getDataTree() const
+{
+ DirectoryTree *base = new DirectoryTree;
+
+ mapDataNode(base, m_Tree->topLevelItem(0));
+ return base;
+}
+
+
+QString InstallDialog::getFullPath(const DirectoryTree::Node *node)
+{
+ QString result(node->getData().name);
+ const DirectoryTree::Node *parent = node->getParent();
+ while (parent != NULL) {
+ if (parent->getParent() != NULL) {
+ result.prepend("\\");
+ }
+ result.prepend(parent->getData().name);
+ parent = parent->getParent();
+ }
+ return result;
+}
+
+
+void InstallDialog::addDataToTree(DirectoryTree::Node *node, QTreeWidgetItem *treeItem)
+{
+ QString path = getFullPath(node);
+
+ // add directory elements
+ for (DirectoryTree::node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) {
+ QStringList fields((*iter)->getData().name);
+ QTreeWidgetItem *newNodeItem = new QTreeWidgetItem(treeItem, fields);
+ newNodeItem->setFlags(newNodeItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsTristate);
+ newNodeItem->setCheckState(0, Qt::Checked);
+ addDataToTree(*iter, newNodeItem);
+ treeItem->addChild(newNodeItem);
+ }
+
+ // add file elements
+ for (DirectoryTree::leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) {
+ QStringList fields(iter->getName());
+
+ QTreeWidgetItem *newLeafItem = new QTreeWidgetItem(treeItem, fields);
+ newLeafItem->setFlags(newLeafItem->flags() | Qt::ItemIsUserCheckable);
+ newLeafItem->setCheckState(0, Qt::Checked);
+ if (path.size() != 0) {
+ newLeafItem->setToolTip(0, path.mid(0).append("\\").append(iter->getName()));
+ } else {
+ newLeafItem->setToolTip(0, iter->getName());
+ }
+ newLeafItem->setData(0, Qt::UserRole, iter->getIndex());
+
+ treeItem->addChild(newLeafItem);
+ }
+}
+
+
+void InstallDialog::updatePreview()
+{
+ m_Updating = true;
+ m_Tree->clear();
+ delete m_TreeRoot;
+
+ m_TreeRoot = new QTreeWidgetItem(m_Tree, QStringList("<data>"));
+
+ addDataToTree(m_DataTree, m_TreeRoot);
+
+ setDataRoot(m_TreeRoot);
+ m_Updating = false;
+ updateProblems();
+}
+
+
+bool InstallDialog::testForProblem()
+{
+ bool ok = false;
+ QTreeWidgetItem *tlWidget = m_Tree->topLevelItem(0);
+ for (int i = 0; i < tlWidget->childCount(); ++i) {
+ QTreeWidgetItem *widget = tlWidget->child(i);
+ if (widget->checkState(0) == Qt::Unchecked) {
+ continue;
+ }
+
+ if (widget->data(0, Qt::UserRole).isValid()) {
+ // file
+ if (InstallationTester::isTopLevelSuffix(widget->text(0))) {
+ ok = true;
+ break;
+ }
+ } else {
+ // directory
+ if (InstallationTester::isTopLevelDirectory(widget->text(0))) {
+ ok = true;
+ break;
+ }
+ }
+ }
+ return ok;
+}
+
+
+void InstallDialog::updateProblems()
+{
+
+ if (testForProblem()) {
+ m_ProblemLabel->setText(tr("Looks good"));
+ m_ProblemLabel->setToolTip(tr("No problem detected"));
+ m_ProblemLabel->setStyleSheet("color: darkGreen;");
+ } else {
+ m_ProblemLabel->setText(tr("No game data on top level"));
+ m_ProblemLabel->setToolTip(tr("There is no esp/esm file or asset directory (textures, meshes, interface, ...) "
+ "on the top level."));
+ m_ProblemLabel->setStyleSheet("color: red;");
+ }
+}
+
+
+void InstallDialog::setDataRoot(QTreeWidgetItem* root)
+{
+ if (root != NULL) {
+ m_DataRoot = root;
+
+ m_Tree->takeTopLevelItem(0);
+ QTreeWidgetItem *temp = root->clone();
+// temp->setCheckState(0, Qt::Checked);
+ temp->setFlags(temp->flags() & ~(Qt::ItemIsUserCheckable | Qt::ItemIsTristate));
+ temp->setText(0, "<data>");
+ temp->setData(0, Qt::CheckStateRole, QVariant());
+ m_Tree->addTopLevelItem(temp);
+ temp->setExpanded(true);
+ } else {
+ m_Tree->takeTopLevelItem(0);
+ }
+ updateProblems();
+}
+
+
+void InstallDialog::use_as_data()
+{
+ if (m_TreeSelection != NULL) {
+ setDataRoot(m_TreeSelection);
+ m_TreeSelection = NULL;
+ }
+ updateProblems();
+}
+
+
+void InstallDialog::unset_data()
+{
+ m_TreeSelection = NULL;
+
+ setDataRoot(m_TreeRoot);
+ updateProblems();
+}
+
+
+void InstallDialog::create_directory()
+{
+ bool ok = false;
+ QString result = QInputDialog::getText(this, tr("Enter a directory name"), tr("Name"),
+ QLineEdit::Normal, QString(), &ok);
+ if (ok && !result.isEmpty()) {
+ for (int i = 0; i < m_TreeSelection->childCount(); ++i) {
+ if (m_TreeSelection->child(i)->text(0) == result) {
+ reportError(tr("A directory with that name exists"));
+ return;
+ }
+ }
+ QStringList fields(result);
+ QTreeWidgetItem *newItem = new QTreeWidgetItem(m_TreeSelection, fields);
+ newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable);
+ newItem->setCheckState(0, Qt::Checked);
+ m_TreeSelection->addChild(newItem);
+ updateProblems();
+ }
+}
+
+void InstallDialog::open_file()
+{
+ emit openFile(m_TreeSelection->toolTip(0));
+}
+
+
+void InstallDialog::on_treeContent_customContextMenuRequested(QPoint pos)
+{
+ m_TreeSelection = m_Tree->itemAt(pos);
+ if (m_TreeSelection == 0) {
+ return;
+ }
+
+ QMenu menu;
+ menu.addAction(tr("Set data directory"), this, SLOT(use_as_data()));
+ menu.addAction(tr("Unset data directory"), this, SLOT(unset_data()));
+ if (m_TreeSelection->data(0, Qt::UserRole).isNull()) {
+ menu.addAction(tr("Create directory..."), this, SLOT(create_directory()));
+ } else {
+ menu.addAction(tr("&Open"), this, SLOT(open_file()));
+ }
+ menu.exec(m_Tree->mapToGlobal(pos));
+}
+
+
+void InstallDialog::treeChanged()
+{
+ updateProblems();
+}
+
+
+void InstallDialog::on_okButton_clicked()
+{
+ if (!testForProblem()) {
+ if (QMessageBox::question(this, tr("Continue?"), tr("This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
+ return;
+ }
+ }
+ this->accept();
+}
+
+void InstallDialog::on_cancelButton_clicked()
+{
+ this->reject();
+}
diff --git a/src/installdialog.h b/src/installdialog.h new file mode 100644 index 00000000..14c9d733 --- /dev/null +++ b/src/installdialog.h @@ -0,0 +1,127 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef INSTALLDIALOG_H
+#define INSTALLDIALOG_H
+
+#include "mytree.h"
+#include "archivetree.h"
+#include "tutorabledialog.h"
+#include <QDialog>
+#include <QUuid>
+#include <QTreeWidgetItem>
+#include <QProgressDialog>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <archive.h>
+#include <directorytree.h>
+
+
+namespace Ui {
+ class InstallDialog;
+}
+
+
+/**
+ * a dialog presented to manually define how a mod is to be installed. It provides
+ * a tree view of the file contents that can modified directly
+ **/
+class InstallDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief constructor
+ *
+ * @param tree tree structure describing the vanilla archive structure. The InstallDialog does NOT take custody of this pointer!
+ * @param modName name of the mod. The name can be modified through the dialog
+ * @param parent parent widget
+ **/
+ explicit InstallDialog(DirectoryTree *tree, const QString &modName, QWidget *parent = 0);
+ ~InstallDialog();
+
+ /**
+ * @brief retrieve the (modified) mod name
+ *
+ * @return updated mod name
+ **/
+ QString getModName() const;
+
+ /**
+ * @brief retrieve the user-modified directory structure
+ *
+ * @return modified data structure. This is a NEW datatree object for which the caller takes custody
+ **/
+ DirectoryTree *getDataTree() const;
+
+signals:
+
+ void openFile(const QString fileName);
+
+private:
+
+ void updatePreview();
+ bool testForProblem();
+ void updateProblems();
+
+ void setDataRoot(QTreeWidgetItem* root);
+
+ void updateFileList(QTreeWidgetItem *item, QString targetName, FileData* const *fileData, size_t size) const;
+
+ void updateCheckState(QTreeWidgetItem *item);
+// void recursiveCheck(QTreeWidgetItem *item);
+// void recursiveUncheck(QTreeWidgetItem *item);
+
+ void addDataToTree(DirectoryTree::Node *node, QTreeWidgetItem *treeItem);
+
+ void mapDataNode(DirectoryTree::Node *node, QTreeWidgetItem *baseItem) const;
+
+ static QString getFullPath(const DirectoryTree::Node *node);
+
+private slots:
+
+ void on_treeContent_customContextMenuRequested(QPoint pos);
+
+ void unset_data();
+ void use_as_data();
+ void create_directory();
+ void open_file();
+
+ void treeChanged();
+
+ void on_cancelButton_clicked();
+
+ void on_okButton_clicked();
+
+private:
+ Ui::InstallDialog *ui;
+
+ DirectoryTree *m_DataTree;
+
+ ArchiveTree *m_Tree;
+ QLabel *m_ProblemLabel;
+ QTreeWidgetItem *m_TreeRoot;
+ QTreeWidgetItem *m_DataRoot;
+ QTreeWidgetItem *m_TreeSelection;
+ bool m_Updating;
+
+};
+
+#endif // INSTALLDIALOG_H
diff --git a/src/installdialog.ui b/src/installdialog.ui new file mode 100644 index 00000000..88019c77 --- /dev/null +++ b/src/installdialog.ui @@ -0,0 +1,165 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InstallDialog</class>
+ <widget class="QDialog" name="InstallDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>516</width>
+ <height>407</height>
+ </rect>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Install Mods</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="title">
+ <string>New Mod</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="editName">
+ <property name="toolTip">
+ <string>Pick a name for the mod</string>
+ </property>
+ <property name="whatsThis">
+ <string>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Content</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="ArchiveTree" name="treeContent">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></string>
+ </property>
+ <property name="locale">
+ <locale language="English" country="UnitedStates"/>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DragDrop</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="problemLabel">
+ <property name="font">
+ <font>
+ <pointsize>12</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Placeholder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ArchiveTree</class>
+ <extends>QTreeWidget</extends>
+ <header>archivetree.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/json.cpp b/src/json.cpp new file mode 100644 index 00000000..7bfaed39 --- /dev/null +++ b/src/json.cpp @@ -0,0 +1,588 @@ +/* Copyright 2011 Eeli Reilin. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of Eeli Reilin.
+ */
+
+/**
+ * \file json.cpp
+ */
+
+#include "json.h"
+#include <iostream>
+
+namespace QtJson
+{
+
+
+static QString sanitizeString(QString str)
+{
+ str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ str.replace(QLatin1String("\""), QLatin1String("\\\""));
+ str.replace(QLatin1String("\b"), QLatin1String("\\b"));
+ str.replace(QLatin1String("\f"), QLatin1String("\\f"));
+ str.replace(QLatin1String("\n"), QLatin1String("\\n"));
+ str.replace(QLatin1String("\r"), QLatin1String("\\r"));
+ str.replace(QLatin1String("\t"), QLatin1String("\\t"));
+ return QString(QLatin1String("\"%1\"")).arg(str);
+}
+
+static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep)
+{
+ QByteArray res;
+ Q_FOREACH(const QByteArray &i, list)
+ {
+ if(!res.isEmpty())
+ {
+ res += sep;
+ }
+ res += i;
+ }
+ return res;
+}
+
+/**
+ * parse
+ */
+QVariant Json::parse(const QString &json)
+{
+ bool success = true;
+ return Json::parse(json, success);
+}
+
+/**
+ * parse
+ */
+QVariant Json::parse(const QString &json, bool &success)
+{
+ success = true;
+
+ //Return an empty QVariant if the JSON data is either null or empty
+ if(!json.isNull() || !json.isEmpty())
+ {
+ QString data = json;
+ //We'll start from index 0
+ int index = 0;
+
+ //Parse the first value
+ QVariant value = Json::parseValue(data, index, success);
+
+ //Return the parsed value
+ return value;
+ }
+ else
+ {
+ //Return the empty QVariant
+ return QVariant();
+ }
+}
+
+QByteArray Json::serialize(const QVariant &data)
+{
+ bool success = true;
+ return Json::serialize(data, success);
+}
+
+QByteArray Json::serialize(const QVariant &data, bool &success)
+{
+ QByteArray str;
+ success = true;
+
+ if(!data.isValid()) // invalid or null?
+ {
+ str = "null";
+ }
+ else if((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list?
+ {
+ QList<QByteArray> values;
+ const QVariantList list = data.toList();
+ Q_FOREACH(const QVariant& v, list)
+ {
+ QByteArray serializedValue = serialize(v);
+ if(serializedValue.isNull())
+ {
+ success = false;
+ break;
+ }
+ values << serializedValue;
+ }
+
+ str = "[ " + join( values, ", " ) + " ]";
+ }
+ else if(data.type() == QVariant::Map) // variant is a map?
+ {
+ const QVariantMap vmap = data.toMap();
+ QMapIterator<QString, QVariant> it( vmap );
+ str = "{ ";
+ QList<QByteArray> pairs;
+ while(it.hasNext())
+ {
+ it.next();
+ QByteArray serializedValue = serialize(it.value());
+ if(serializedValue.isNull())
+ {
+ success = false;
+ break;
+ }
+ pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue;
+ }
+ str += join(pairs, ", ");
+ str += " }";
+ }
+ else if((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array?
+ {
+ str = sanitizeString(data.toString()).toUtf8();
+ }
+ else if(data.type() == QVariant::Double) // double?
+ {
+ str = QByteArray::number(data.toDouble());
+ if(!str.contains(".") && ! str.contains("e"))
+ {
+ str += ".0";
+ }
+ }
+ else if (data.type() == QVariant::Bool) // boolean value?
+ {
+ str = data.toBool() ? "true" : "false";
+ }
+ else if (data.type() == QVariant::ULongLong) // large unsigned number?
+ {
+ str = QByteArray::number(data.value<qulonglong>());
+ }
+ else if ( data.canConvert<qlonglong>() ) // any signed number?
+ {
+ str = QByteArray::number(data.value<qlonglong>());
+ }
+ else if (data.canConvert<long>())
+ {
+ str = sanitizeString(QString::number(data.value<long>())).toUtf8();
+ }
+ else if (data.canConvert<QString>()) // can value be converted to string?
+ {
+ // this will catch QDate, QDateTime, QUrl, ...
+ str = sanitizeString(data.toString()).toUtf8();
+ }
+ else
+ {
+ success = false;
+ }
+ if (success)
+ {
+ return str;
+ }
+ else
+ {
+ return QByteArray();
+ }
+}
+
+/**
+ * parseValue
+ */
+QVariant Json::parseValue(const QString &json, int &index, bool &success)
+{
+ //Determine what kind of data we should parse by
+ //checking out the upcoming token
+ switch(Json::lookAhead(json, index))
+ {
+ case JsonTokenString:
+ return Json::parseString(json, index, success);
+ case JsonTokenNumber:
+ return Json::parseNumber(json, index);
+ case JsonTokenCurlyOpen:
+ return Json::parseObject(json, index, success);
+ case JsonTokenSquaredOpen:
+ return Json::parseArray(json, index, success);
+ case JsonTokenTrue:
+ Json::nextToken(json, index);
+ return QVariant(true);
+ case JsonTokenFalse:
+ Json::nextToken(json, index);
+ return QVariant(false);
+ case JsonTokenNull:
+ Json::nextToken(json, index);
+ return QVariant();
+ case JsonTokenNone:
+ break;
+ }
+
+ //If there were no tokens, flag the failure and return an empty QVariant
+ success = false;
+ return QVariant();
+}
+
+/**
+ * parseObject
+ */
+QVariant Json::parseObject(const QString &json, int &index, bool &success)
+{
+ QVariantMap map;
+ int token;
+
+ //Get rid of the whitespace and increment index
+ Json::nextToken(json, index);
+
+ //Loop through all of the key/value pairs of the object
+ bool done = false;
+ while(!done)
+ {
+ //Get the upcoming token
+ token = Json::lookAhead(json, index);
+
+ if(token == JsonTokenNone)
+ {
+ success = false;
+ return QVariantMap();
+ }
+ else if(token == JsonTokenComma)
+ {
+ Json::nextToken(json, index);
+ }
+ else if(token == JsonTokenCurlyClose)
+ {
+ Json::nextToken(json, index);
+ return map;
+ }
+ else
+ {
+ //Parse the key/value pair's name
+ QString name = Json::parseString(json, index, success).toString();
+
+ if(!success)
+ {
+ return QVariantMap();
+ }
+
+ //Get the next token
+ token = Json::nextToken(json, index);
+
+ //If the next token is not a colon, flag the failure
+ //return an empty QVariant
+ if(token != JsonTokenColon)
+ {
+ success = false;
+ return QVariant(QVariantMap());
+ }
+
+ //Parse the key/value pair's value
+ QVariant value = Json::parseValue(json, index, success);
+
+ if(!success)
+ {
+ return QVariantMap();
+ }
+
+ //Assign the value to the key in the map
+ map[name] = value;
+ }
+ }
+
+ //Return the map successfully
+ return QVariant(map);
+}
+
+/**
+ * parseArray
+ */
+QVariant Json::parseArray(const QString &json, int &index, bool &success)
+{
+ QVariantList list;
+
+ Json::nextToken(json, index);
+
+ bool done = false;
+ while(!done)
+ {
+ int token = Json::lookAhead(json, index);
+
+ if(token == JsonTokenNone)
+ {
+ success = false;
+ return QVariantList();
+ }
+ else if(token == JsonTokenComma)
+ {
+ Json::nextToken(json, index);
+ }
+ else if(token == JsonTokenSquaredClose)
+ {
+ Json::nextToken(json, index);
+ break;
+ }
+ else
+ {
+ QVariant value = Json::parseValue(json, index, success);
+
+ if(!success)
+ {
+ return QVariantList();
+ }
+
+ list.push_back(value);
+ }
+ }
+
+ return QVariant(list);
+}
+
+/**
+ * parseString
+ */
+QVariant Json::parseString(const QString &json, int &index, bool &success)
+{
+ QString s;
+ QChar c;
+
+ Json::eatWhitespace(json, index);
+
+ c = json[index++];
+
+ bool complete = false;
+ while(!complete)
+ {
+ if(index == json.size())
+ {
+ break;
+ }
+
+ c = json[index++];
+
+ if(c == '\"')
+ {
+ complete = true;
+ break;
+ }
+ else if(c == '\\')
+ {
+ if(index == json.size())
+ {
+ break;
+ }
+
+ c = json[index++];
+
+ if(c == '\"')
+ {
+ s.append('\"');
+ }
+ else if(c == '\\')
+ {
+ s.append('\\');
+ }
+ else if(c == '/')
+ {
+ s.append('/');
+ }
+ else if(c == 'b')
+ {
+ s.append('\b');
+ }
+ else if(c == 'f')
+ {
+ s.append('\f');
+ }
+ else if(c == 'n')
+ {
+ s.append('\n');
+ }
+ else if(c == 'r')
+ {
+ s.append('\r');
+ }
+ else if(c == 't')
+ {
+ s.append('\t');
+ }
+ else if(c == 'u')
+ {
+ int remainingLength = json.size() - index;
+
+ if(remainingLength >= 4)
+ {
+ QString unicodeStr = json.mid(index, 4);
+
+ int symbol = unicodeStr.toInt(0, 16);
+
+ s.append(QChar(symbol));
+
+ index += 4;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ s.append(c);
+ }
+ }
+
+ if(!complete)
+ {
+ success = false;
+ return QVariant();
+ }
+
+ return QVariant(s);
+}
+
+/**
+ * parseNumber
+ */
+QVariant Json::parseNumber(const QString &json, int &index)
+{
+ Json::eatWhitespace(json, index);
+
+ int lastIndex = Json::lastIndexOfNumber(json, index);
+ int charLength = (lastIndex - index) + 1;
+ QString numberStr;
+
+ numberStr = json.mid(index, charLength);
+
+ index = lastIndex + 1;
+
+ if (numberStr.contains('.')) {
+ return QVariant(numberStr.toDouble(NULL));
+ } else if (numberStr.startsWith('-')) {
+ return QVariant(numberStr.toLongLong(NULL));
+ } else {
+ return QVariant(numberStr.toULongLong(NULL));
+ }
+}
+
+/**
+ * lastIndexOfNumber
+ */
+int Json::lastIndexOfNumber(const QString &json, int index)
+{
+ int lastIndex;
+
+ for(lastIndex = index; lastIndex < json.size(); lastIndex++)
+ {
+ if(QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1)
+ {
+ break;
+ }
+ }
+
+ return lastIndex -1;
+}
+
+/**
+ * eatWhitespace
+ */
+void Json::eatWhitespace(const QString &json, int &index)
+{
+ for(; index < json.size(); index++)
+ {
+ if(QString(" \t\n\r").indexOf(json[index]) == -1)
+ {
+ break;
+ }
+ }
+}
+
+/**
+ * lookAhead
+ */
+int Json::lookAhead(const QString &json, int index)
+{
+ int saveIndex = index;
+ return Json::nextToken(json, saveIndex);
+}
+
+/**
+ * nextToken
+ */
+int Json::nextToken(const QString &json, int &index)
+{
+ Json::eatWhitespace(json, index);
+
+ if(index == json.size())
+ {
+ return JsonTokenNone;
+ }
+
+ QChar c = json[index];
+ index++;
+ switch(c.toLatin1())
+ {
+ case '{': return JsonTokenCurlyOpen;
+ case '}': return JsonTokenCurlyClose;
+ case '[': return JsonTokenSquaredOpen;
+ case ']': return JsonTokenSquaredClose;
+ case ',': return JsonTokenComma;
+ case '"': return JsonTokenString;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '-': return JsonTokenNumber;
+ case ':': return JsonTokenColon;
+ }
+
+ index--;
+
+ int remainingLength = json.size() - index;
+
+ //True
+ if(remainingLength >= 4)
+ {
+ if (json[index] == 't' && json[index + 1] == 'r' &&
+ json[index + 2] == 'u' && json[index + 3] == 'e')
+ {
+ index += 4;
+ return JsonTokenTrue;
+ }
+ }
+
+ //False
+ if (remainingLength >= 5)
+ {
+ if (json[index] == 'f' && json[index + 1] == 'a' &&
+ json[index + 2] == 'l' && json[index + 3] == 's' &&
+ json[index + 4] == 'e')
+ {
+ index += 5;
+ return JsonTokenFalse;
+ }
+ }
+
+ //Null
+ if (remainingLength >= 4)
+ {
+ if (json[index] == 'n' && json[index + 1] == 'u' &&
+ json[index + 2] == 'l' && json[index + 3] == 'l')
+ {
+ index += 4;
+ return JsonTokenNull;
+ }
+ }
+
+ return JsonTokenNone;
+}
+
+
+} //end namespace
diff --git a/src/json.h b/src/json.h new file mode 100644 index 00000000..d2cfa9a8 --- /dev/null +++ b/src/json.h @@ -0,0 +1,204 @@ +/* Copyright 2011 Eeli Reilin. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of Eeli Reilin.
+ */
+
+/**
+ * \file json.h
+ */
+
+#ifndef JSON_H
+#define JSON_H
+
+#include <QVariant>
+#include <QString>
+
+namespace QtJson
+{
+
+/**
+ * \enum JsonToken
+ */
+enum JsonToken
+{
+ JsonTokenNone = 0,
+ JsonTokenCurlyOpen = 1,
+ JsonTokenCurlyClose = 2,
+ JsonTokenSquaredOpen = 3,
+ JsonTokenSquaredClose = 4,
+ JsonTokenColon = 5,
+ JsonTokenComma = 6,
+ JsonTokenString = 7,
+ JsonTokenNumber = 8,
+ JsonTokenTrue = 9,
+ JsonTokenFalse = 10,
+ JsonTokenNull = 11
+};
+
+/**
+ * \class Json
+ * \brief A JSON data parser
+ *
+ * Json parses a JSON data into a QVariant hierarchy.
+ */
+class Json
+{
+ public:
+ /**
+ * Parse a JSON string
+ *
+ * \param json The JSON data
+ */
+ static QVariant parse(const QString &json);
+
+ /**
+ * Parse a JSON string
+ *
+ * \param json The JSON data
+ * \param success The success of the parsing
+ */
+ static QVariant parse(const QString &json, bool &success);
+
+ /**
+ * This method generates a textual JSON representation
+ *
+ * \param data The JSON data generated by the parser.
+ * \param success The success of the serialization
+ */
+ static QByteArray serialize(const QVariant &data);
+
+ /**
+ * This method generates a textual JSON representation
+ *
+ * \param data The JSON data generated by the parser.
+ * \param success The success of the serialization
+ *
+ * \return QByteArray Textual JSON representation
+ */
+ static QByteArray serialize(const QVariant &data, bool &success);
+
+ private:
+ /**
+ * Parses a value starting from index
+ *
+ * \param json The JSON data
+ * \param index The start index
+ * \param success The success of the parse process
+ *
+ * \return QVariant The parsed value
+ */
+ static QVariant parseValue(const QString &json, int &index,
+ bool &success);
+
+ /**
+ * Parses an object starting from index
+ *
+ * \param json The JSON data
+ * \param index The start index
+ * \param success The success of the object parse
+ *
+ * \return QVariant The parsed object map
+ */
+ static QVariant parseObject(const QString &json, int &index,
+ bool &success);
+
+ /**
+ * Parses an array starting from index
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ * \param success The success of the array parse
+ *
+ * \return QVariant The parsed variant array
+ */
+ static QVariant parseArray(const QString &json, int &index,
+ bool &success);
+
+ /**
+ * Parses a string starting from index
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ * \param success The success of the string parse
+ *
+ * \return QVariant The parsed string
+ */
+ static QVariant parseString(const QString &json, int &index,
+ bool &success);
+
+ /**
+ * Parses a number starting from index
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ *
+ * \return QVariant The parsed number
+ */
+ static QVariant parseNumber(const QString &json, int &index);
+
+ /**
+ * Get the last index of a number starting from index
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ *
+ * \return The last index of the number
+ */
+ static int lastIndexOfNumber(const QString &json, int index);
+
+ /**
+ * Skip unwanted whitespace symbols starting from index
+ *
+ * \param json The JSON data
+ * \param index The start index
+ */
+ static void eatWhitespace(const QString &json, int &index);
+
+ /**
+ * Check what token lies ahead
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ *
+ * \return int The upcoming token
+ */
+ static int lookAhead(const QString &json, int index);
+
+ /**
+ * Get the next JSON token
+ *
+ * \param json The JSON data
+ * \param index The starting index
+ *
+ * \return int The next JSON token
+ */
+ static int nextToken(const QString &json, int &index);
+};
+
+
+} //end namespace
+
+#endif //JSON_H
diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp new file mode 100644 index 00000000..d10eca47 --- /dev/null +++ b/src/loadmechanism.cpp @@ -0,0 +1,285 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "loadmechanism.h"
+#include "utility.h"
+#include "util.h"
+#include <gameinfo.h>
+#include <appconfig.h>
+#include <QFile>
+#include <QFileInfo>
+#include <QDir>
+#include <QString>
+#include <QMessageBox>
+#include <QCryptographicHash>
+
+
+LoadMechanism::LoadMechanism()
+ : m_SelectedMechanism(LOAD_MODORGANIZER)
+{
+}
+
+void LoadMechanism::writeHintFile(const QDir &targetDirectory)
+{
+ QString hintFilePath = targetDirectory.absoluteFilePath("mo_path.txt");
+ QFile hintFile(hintFilePath);
+ if (hintFile.exists()) {
+ hintFile.remove();
+ }
+ if (!hintFile.open(QIODevice::WriteOnly)) {
+ throw MyException(QObject::tr("failed to open %1: %2").arg(hintFilePath).arg(hintFile.errorString()));
+ }
+ hintFile.write(ToString(GameInfo::instance().getOrganizerDirectory(), true).c_str());
+ hintFile.close();
+}
+
+
+void LoadMechanism::removeHintFile(QDir &targetDirectory)
+{
+ targetDirectory.remove("mo_path.txt");
+}
+
+
+bool LoadMechanism::isDirectLoadingSupported()
+{
+ if (GameInfo::instance().getType() == GameInfo::TYPE_OBLIVION) {
+ // oblivion can be loaded directly if it's not the steam variant
+ QString gamePath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+ QDir gameDir(gamePath);
+ // test if this is the steam version of oblivion
+ if (QFile(gameDir.absoluteFilePath("steam_api.dll")).exists()) {
+ return false;
+ }
+ }
+
+ // all other games work afaik
+ return true;
+}
+
+
+bool LoadMechanism::isScriptExtenderSupported()
+{
+ QString targetPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+ if ((QFile(targetPath.mid(0).append("/").append(ToQString(GameInfo::instance().getSEName())).append("_loader.exe")).exists()) ||
+ (QFile(targetPath.mid(0).append("/").append(ToQString(GameInfo::instance().getSEName())).append("_steam_loader.dll")).exists())) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool LoadMechanism::isProxyDLLSupported()
+{
+ QString targetPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+ targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget()));
+ return QFile(targetPath).exists();
+}
+
+
+bool LoadMechanism::hashIdentical(const QString &fileNameLHS, const QString &fileNameRHS)
+{
+ QFile fileLHS(fileNameLHS);
+ if (!fileLHS.open(QIODevice::ReadOnly)) {
+ throw MyException(QObject::tr("%1 not found").arg(fileNameLHS));
+ }
+ QByteArray dataLHS = fileLHS.readAll();
+ QByteArray hashLHS = QCryptographicHash::hash(dataLHS, QCryptographicHash::Md5);
+
+ fileLHS.close();
+
+ QFile fileRHS(fileNameRHS);
+ if (!fileRHS.open(QIODevice::ReadOnly)) {
+ throw MyException(QObject::tr("%1 not found").arg(fileNameRHS));
+ }
+ QByteArray dataRHS = fileRHS.readAll();
+ QByteArray hashRHS = QCryptographicHash::hash(dataRHS, QCryptographicHash::Md5);
+
+ fileRHS.close();
+
+ return hashLHS == hashRHS;
+}
+
+
+void LoadMechanism::deactivateScriptExtender()
+{
+ try {
+ QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+
+ QString pluginsDirPath = gameDirectory;
+ pluginsDirPath.append("/data/").append(ToQString(GameInfo::instance().getSEName())).append("/plugins");
+
+ QDir pluginsDir(pluginsDirPath);
+
+ QString hookDLLName = ToQString(AppConfig::hookDLLName());
+ if (QFile(pluginsDir.absoluteFilePath(hookDLLName)).exists()) {
+ // remove dll from SE plugins directory
+ if (!pluginsDir.remove(hookDLLName)) {
+ throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(hookDLLName)));
+ }
+ }
+
+ removeHintFile(pluginsDir);
+ } catch (const std::exception &e) {
+ QMessageBox::critical(NULL, QObject::tr("Failed to deactivate script extender loading"), e.what());
+ }
+}
+
+
+void LoadMechanism::deactivateProxyDLL()
+{
+ try {
+ QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+
+ QString targetPath = gameDirectory;
+ targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget()));
+
+ QFile targetDLL(targetPath);
+ if (targetDLL.exists()) {
+ QString origFile = gameDirectory.mid(0).append(ToQString(AppConfig::proxyDLLOrig()));
+ // determine if a proxy-dll is installed
+ // this is a very crude way of making this decision but it should be good enough
+ if ((targetDLL.size() < 24576) && (QFile(origFile).exists())) {
+ // remove proxy-dll
+ if (!targetDLL.remove()) {
+ throw MyException(QObject::tr("Failed to remove %1: %2").arg(targetPath).arg(targetDLL.errorString()));
+ } else if (!QFile::rename(origFile, targetPath)) {
+ throw MyException(QObject::tr("Failed to rename %1 to %2").arg(origFile, targetPath));
+ }
+ }
+ }
+
+ removeHintFile(QDir(gameDirectory));
+ } catch (const std::exception &e) {
+ QMessageBox::critical(NULL, QObject::tr("Failed to deactivate proxy-dll loading"), e.what());
+ }
+}
+
+
+void LoadMechanism::activateScriptExtender()
+{
+ try {
+ QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+
+ QString pluginsDirPath = gameDirectory;
+ pluginsDirPath.append("/data/").append(ToQString(GameInfo::instance().getSEName())).append("/plugins");
+
+ QDir pluginsDir(pluginsDirPath);
+
+ if (!pluginsDir.exists()) {
+ pluginsDir.mkpath(".");
+ }
+
+ QString targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::hookDLLName()));
+ QString hookDLLPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())).append("/").append(ToQString(AppConfig::hookDLLName()));
+
+ QFile dllFile(targetPath);
+
+ if (dllFile.exists()) {
+ // may be outdated
+ if (!hashIdentical(targetPath, hookDLLPath)) {
+ dllFile.remove();
+ }
+ }
+
+ if (!dllFile.exists()) {
+ // install dll to SE plugins
+ if (!QFile::copy(hookDLLPath, targetPath)) {
+ throw MyException(QObject::tr("Failed to copy %1 to %2").arg(hookDLLPath, targetPath));
+ }
+ }
+ writeHintFile(pluginsDir);
+ } catch (const std::exception &e) {
+ QMessageBox::critical(NULL, QObject::tr("Failed to set up script extender loading"), e.what());
+ }
+}
+
+
+void LoadMechanism::activateProxyDLL()
+{
+ try {
+ QString gameDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory()));
+
+ QString targetPath = gameDirectory;
+ targetPath.append("/").append(ToQString(AppConfig::proxyDLLTarget()));
+ QFile targetDLL(targetPath);
+ if (!targetDLL.exists()) {
+ return;
+ }
+
+ QString sourcePath = QDir::fromNativeSeparators(
+ ToQString(GameInfo::instance().getOrganizerDirectory())).append("/").append(ToQString(AppConfig::proxyDLLSource()));
+
+ // this is a very crude way of making this decision but it should be good enough
+ if (targetDLL.size() < 24576) {
+ // determine if a proxy-dll is already installed and if so, if it's the right one
+ if (!hashIdentical(targetPath, sourcePath)) {
+ // wrong proxy dll, probably outdated. delete and install the new one
+ if (!QFile::remove(targetPath)) {
+ throw MyException(QObject::tr("Failed to delete old proxy-dll %1").arg(targetPath));
+ }
+ if (!QFile::copy(sourcePath, targetPath)) {
+ throw MyException(QObject::tr("Failed to copy %1 to %2").arg(sourcePath).arg(targetPath));
+ }
+ } // otherwise the proxy-dll is already the right one
+ } else {
+ // no proxy dll installed yet. move the original and insert proxy-dll
+
+ QString origFile = gameDirectory;
+ origFile.append("/").append(ToQString(AppConfig::proxyDLLOrig()));
+
+ if (QFile(origFile).exists()) {
+ // orig-file exists. this may happen if the steam-api was updated or the user messed with the
+ // dlls.
+ if (!QFile::remove(origFile)) {
+ throw MyException(QObject::tr("Failed to overwrite %1").arg(origFile));
+ }
+ }
+ if (!QFile::rename(targetPath, origFile)) {
+ throw MyException(QObject::tr("Failed to rename %1 to %2").arg(targetPath).arg(origFile));
+ }
+ if (!QFile::copy(sourcePath, targetPath)) {
+ throw MyException(QObject::tr("Failed to copy %1 to %2").arg(sourcePath).arg(targetPath));
+ }
+ }
+ writeHintFile(QDir(gameDirectory));
+ } catch (const std::exception &e) {
+ QMessageBox::critical(NULL, QObject::tr("Failed to set up proxy-dll loading"), e.what());
+ }
+}
+
+
+void LoadMechanism::activate(EMechanism mechanism)
+{
+ switch (mechanism) {
+ case LOAD_MODORGANIZER: {
+ deactivateProxyDLL();
+ deactivateScriptExtender();
+ } break;
+ case LOAD_SCRIPTEXTENDER: {
+ deactivateProxyDLL();
+ activateScriptExtender();
+ } break;
+ case LOAD_PROXYDLL: {
+ deactivateScriptExtender();
+ activateProxyDLL();
+ } break;
+ }
+}
+
diff --git a/src/loadmechanism.h b/src/loadmechanism.h new file mode 100644 index 00000000..90ed5f4a --- /dev/null +++ b/src/loadmechanism.h @@ -0,0 +1,120 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef LOADMECHANISM_H
+#define LOADMECHANISM_H
+
+
+#include <QDir>
+#include <QString>
+
+
+/**
+ * @brief manages the various load mechanisms supported by Mod Organizer
+ * the load mechanisms is the means by which the mo-dll is injected into the target
+ * process. The default mode "mod organizer" requires the target process to be started
+ * from inside mod organizer. In certain cases (oblivion steam edition) this is not
+ * possible since the game can then only be started from steam.
+ * "Script Extender" is an alternative load mechanism that uses a script extender (obse,
+ * fose, nvse or skse) to load MO. This is reliable but prevents se plugins installed
+ * through MO from working.
+ * "Proxy DLL" replaces a dll belonging to the game by a proxy that will load MO and then
+ * chain-load the original dll. This currently only works with steam-versions of games and
+ * is intended as a last resort solution.
+ **/
+class LoadMechanism
+{
+public:
+
+ enum EMechanism {
+ LOAD_MODORGANIZER = 0,
+ LOAD_SCRIPTEXTENDER,
+ LOAD_PROXYDLL
+ };
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ **/
+ LoadMechanism();
+
+ /**
+ * activate the specified mechanism. This automatically disables any other mechanism active
+ *
+ * @param mechanism the mechanism to activate
+ **/
+ void activate(EMechanism mechanism);
+
+ /**
+ * @brief test whether the "Mod Organizer" load mechanism is supported for the current game
+ *
+ * @return true if the load mechanism is supported
+ **/
+ bool isDirectLoadingSupported();
+
+ /**
+ * @brief test whether the "Script Extender" load mechanism is supported for the current game
+ *
+ * @return true if the load mechanism is supported
+ **/
+ bool isScriptExtenderSupported();
+
+ /**
+ * @brief test whether the "Proxy DLL" load mechanism is supported for the current game
+ *
+ * @return true if the load mechanism is supported
+ **/
+ bool isProxyDLLSupported();
+
+private:
+
+ // write a hint file that is required for certain loading mechanisms for the dll to find
+ // the mod organizer installation
+ void writeHintFile(const QDir &targetDirectory);
+
+ // remove the hint file if it exists. does nothing if the file doesn't exist
+ void removeHintFile(QDir &targetDirectory);
+
+ // compare the two files by md5-hash, returns true if they are identical
+ bool hashIdentical(const QString &fileNameLHS, const QString &fileNameRHS);
+
+ // deactivate loading through script extender. does nothing if se-loading wasn't active
+ void deactivateScriptExtender();
+
+ // deactivate loading through proxy-dll. does nothing if se-loading wasn't active
+ void deactivateProxyDLL();
+
+ // activate loading through script extender. does nothing if already active. updates
+ // the dll if necessary
+ void activateScriptExtender();
+
+ // activate loading through proxy-dll. does nothing if already active. updates
+ // the dll if necessary
+ void activateProxyDLL();
+
+private:
+
+ EMechanism m_SelectedMechanism;
+
+};
+
+
+#endif // LOADMECHANISM_H
diff --git a/src/lockeddialog.cpp b/src/lockeddialog.cpp new file mode 100644 index 00000000..4c19c615 --- /dev/null +++ b/src/lockeddialog.cpp @@ -0,0 +1,67 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "lockeddialog.h"
+#include "ui_lockeddialog.h"
+#include <QResizeEvent>
+
+
+LockedDialog::LockedDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::LockedDialog), m_UnlockClicked(false)
+{
+ ui->setupUi(this);
+
+ this->setWindowFlags(this->windowFlags() | Qt::ToolTip | Qt::FramelessWindowHint);
+
+ if (parent != NULL) {
+ QPoint position = parent->mapToGlobal(QPoint(parent->width() / 2, parent->height() / 2));
+ position.rx() -= this->width() / 2;
+ position.ry() -= this->height() / 2;
+ move(position);
+ }
+}
+
+LockedDialog::~LockedDialog()
+{
+ delete ui;
+}
+
+
+void LockedDialog::setProcessName(const QString &name)
+{
+ ui->processLabel->setText(name);
+}
+
+
+void LockedDialog::resizeEvent(QResizeEvent *event)
+{
+ QWidget *par = parentWidget();
+ if (par != NULL) {
+ QPoint position = par->mapToGlobal(QPoint(par->width() / 2, par->height() / 2));
+ position.rx() -= event->size().width() / 2;
+ position.ry() -= event->size().height() / 2;
+ move(position);
+ }
+}
+
+void LockedDialog::on_unlockButton_clicked()
+{
+ m_UnlockClicked = true;
+}
diff --git a/src/lockeddialog.h b/src/lockeddialog.h new file mode 100644 index 00000000..5be398bc --- /dev/null +++ b/src/lockeddialog.h @@ -0,0 +1,67 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef LOCKEDDIALOG_H
+#define LOCKEDDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class LockedDialog;
+}
+
+/**
+ * a small borderless dialog displayed while the Mod Organizer UI is locked
+ * The dialog contains only a label and a button to force the UI to be unlocked
+ *
+ * The UI gets locked while running external applications since they may modify the
+ * data on which Mod Organizer works. After the UI is unlocked (manually or after the
+ * external application closed) MO will refresh all of its data sources
+ **/
+class LockedDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit LockedDialog(QWidget *parent = 0);
+ ~LockedDialog();
+
+ /**
+ * @brief see if the user clicked the unlock-button
+ *
+ * @return true if the user clicked the unlock button
+ **/
+ bool unlockClicked() const { return m_UnlockClicked; }
+
+ void setProcessName(const QString &name);
+
+protected:
+
+ virtual void resizeEvent(QResizeEvent *event);
+
+private slots:
+
+ void on_unlockButton_clicked();
+
+private:
+ Ui::LockedDialog *ui;
+ bool m_UnlockClicked;
+};
+
+#endif // LOCKEDDIALOG_H
diff --git a/src/lockeddialog.ui b/src/lockeddialog.ui new file mode 100644 index 00000000..623e8da1 --- /dev/null +++ b/src/lockeddialog.ui @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LockedDialog</class>
+ <widget class="QDialog" name="LockedDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>236</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Locked</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="toolTip">
+ <string>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</string>
+ </property>
+ <property name="text">
+ <string>MO is locked while the executable is running.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="processLabel">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: grey;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="unlockButton">
+ <property name="text">
+ <string>Unlock</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp new file mode 100644 index 00000000..6a1857fc --- /dev/null +++ b/src/logbuffer.cpp @@ -0,0 +1,157 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "logbuffer.h"
+#include "report.h"
+#include <QMutexLocker>
+#include <QFile>
+#include <Windows.h>
+
+QScopedPointer<LogBuffer> LogBuffer::s_Instance;
+QMutex LogBuffer::s_Mutex;
+
+
+LogBuffer::LogBuffer(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
+ : QObject(NULL), m_OutFileName(outputFileName), m_ShutDown(false),
+ m_MinMsgType(minMsgType), m_NumMessages(0)
+{
+ m_Messages.resize(messageCount);
+}
+
+LogBuffer::~LogBuffer()
+{
+#if QT_VERSION >= 0x050000
+ qInstallMessageHandler(0);
+#else
+ qInstallMsgHandler(0);
+#endif
+ if (!m_ShutDown) {
+ write();
+ }
+}
+
+
+void LogBuffer::logMessage(QtMsgType type, const QString &message)
+{
+ if (type >= m_MinMsgType) {
+ m_Messages.at(m_NumMessages % m_Messages.size()) = message;
+ ++m_NumMessages;
+ if (type >= QtCriticalMsg) {
+ write();
+ }
+ }
+}
+
+
+void LogBuffer::write() const
+{
+ if (m_NumMessages == 0) {
+ return;
+ }
+
+ QFile file(m_OutFileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ reportError(tr("failed to write log to %1: %2").arg(m_OutFileName).arg(file.errorString()));
+ return;
+ }
+
+ unsigned int i = (m_NumMessages > m_Messages.size()) ? m_NumMessages - m_Messages.size()
+ : 0U;
+ for (; i < m_NumMessages; ++i) {
+ file.write(m_Messages.at(i % m_Messages.size()).toUtf8());
+ file.write("\r\n");
+ }
+}
+
+
+void LogBuffer::init(int messageCount, QtMsgType minMsgType, const QString &outputFileName)
+{
+ QMutexLocker guard(&s_Mutex);
+
+ if (!s_Instance.isNull()) {
+ s_Instance.reset();
+ }
+ s_Instance.reset(new LogBuffer(messageCount, minMsgType, outputFileName));
+#if QT_VERSION >= 0x050000
+ qInstallMessageHandler(LogBuffer::log);
+#else
+ qInstallMsgHandler(LogBuffer::log);
+#endif
+}
+
+#if QT_VERSION >= 0x050000
+
+void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
+{
+ QMutexLocker guard(&s_Mutex);
+ if (!s_Instance.isNull()) {
+ s_Instance->logMessage(type, message);
+ }
+ fprintf(stdout, "(%s:%u, %s) %s\n", context.file, context.line, context.function, message.toLocal8Bit());
+ fflush(stdout);
+}
+
+#else
+
+void LogBuffer::log(QtMsgType type, const char *message)
+{
+ QMutexLocker guard(&s_Mutex);
+ if (!s_Instance.isNull()) {
+ s_Instance->logMessage(type, message);
+ }
+ fprintf(stdout, "%s\n", message);
+ fflush(stdout);
+}
+
+#endif
+
+void LogBuffer::writeNow()
+{
+ QMutexLocker guard(&s_Mutex);
+ if (!s_Instance.isNull()) {
+ s_Instance->write();
+ }
+}
+
+
+void LogBuffer::cleanQuit()
+{
+ QMutexLocker guard(&s_Mutex);
+ if (!s_Instance.isNull()) {
+ s_Instance->m_ShutDown = true;
+ }
+}
+
+void log(const char *format, ...)
+{
+ va_list argList;
+ va_start(argList, format);
+
+ static const int BUFFERSIZE = 1000;
+
+ char buffer[BUFFERSIZE + 1];
+ buffer[BUFFERSIZE] = '\0';
+
+ vsnprintf(buffer, BUFFERSIZE, format, argList);
+
+ qCritical("%s", buffer);
+
+ va_end(argList);
+}
+
diff --git a/src/logbuffer.h b/src/logbuffer.h new file mode 100644 index 00000000..d1e292b9 --- /dev/null +++ b/src/logbuffer.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef LOGBUFFER_H
+#define LOGBUFFER_H
+
+#include <QObject>
+#include <QMutex>
+#include <QScopedPointer>
+#include <vector>
+
+
+class LogBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static void init(int messageCount, QtMsgType minMsgType, const QString &outputFileName);
+#if QT_VERSION >= 0x050000
+ static void log(QtMsgType type, const QMessageLogContext &context, const QString &message);
+#else
+ static void log(QtMsgType type, const char *message);
+#endif
+
+ static void writeNow();
+ static void cleanQuit();
+
+public:
+
+ virtual ~LogBuffer();
+
+ void logMessage(QtMsgType type, const QString &message);
+
+signals:
+
+public slots:
+
+private:
+
+ explicit LogBuffer(int messageCount, QtMsgType minMsgType, const QString &outputFileName);
+ LogBuffer(const LogBuffer &reference); // not implemented
+ LogBuffer &operator=(const LogBuffer &reference); // not implemented
+
+ void write() const;
+
+private:
+
+ static QScopedPointer<LogBuffer> s_Instance;
+ static QMutex s_Mutex;
+
+ QString m_OutFileName;
+ bool m_ShutDown;
+ QtMsgType m_MinMsgType;
+ unsigned int m_NumMessages;
+ std::vector<QString> m_Messages;
+
+};
+
+#endif // LOGBUFFER_H
diff --git a/src/loghighlighter.cpp b/src/loghighlighter.cpp new file mode 100644 index 00000000..1c95fc2f --- /dev/null +++ b/src/loghighlighter.cpp @@ -0,0 +1,52 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "loghighlighter.h"
+#include <QRegExp>
+
+LogHighlighter::LogHighlighter(QObject *parent) :
+ QSyntaxHighlighter(parent)
+{
+}
+
+
+void LogHighlighter::highlightBlock(const QString &text)
+{
+ int spacePos = text.indexOf(" ");
+ if (spacePos != -1) {
+ QString type = text.mid(0, spacePos);
+ if (type == "DEBUG") {
+ setFormat(0, text.length(), Qt::gray);
+ } else if (type == "INFO") {
+ setFormat(0, text.length(), Qt::darkGreen);
+ } else if (type == "ERROR") {
+ setFormat(0, text.length(), Qt::red);
+ }
+ }
+
+ int markPos = text.indexOf("injecting to");
+ if (markPos != -1) {
+ setFormat(markPos + 12, text.length(), Qt::blue);
+ }
+
+ markPos = text.indexOf("using profile");
+ if (markPos != -1) {
+ setFormat(markPos + 13, text.length(), Qt::blue);
+ }
+}
diff --git a/src/loghighlighter.h b/src/loghighlighter.h new file mode 100644 index 00000000..127d3228 --- /dev/null +++ b/src/loghighlighter.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef LOGHIGHLIGHTER_H
+#define LOGHIGHLIGHTER_H
+
+#include <QSyntaxHighlighter>
+
+/**
+ * @brief Syntax highlighter to make log files from mo.dll more readable.
+ * @note this is currently not used!
+ **/
+class LogHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+public:
+ explicit LogHighlighter(QObject *parent = 0);
+
+signals:
+
+public slots:
+
+protected:
+
+ virtual void highlightBlock(const QString &text);
+
+};
+
+#endif // LOGHIGHLIGHTER_H
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..0f1fb7c3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,440 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <QApplication>
+#include <QPushButton>
+#include <QListWidget>
+#include <QComboBox>
+#include <QCheckBox>
+#include <QDir>
+#include <QFileInfo>
+#include <QSettings>
+#include <QWhatsThis>
+#include <QToolBar>
+#include <QFileDialog>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <DbgHelp.h>
+#include <cstdarg>
+#include <inject.h>
+#include <appconfig.h>
+#include <stdexcept>
+#include "mainwindow.h"
+#include "report.h"
+#include "modlist.h"
+#include "profile.h"
+#include "gameinfo.h"
+#include "fallout3info.h"
+#include "falloutnvinfo.h"
+#include "oblivioninfo.h"
+#include "skyriminfo.h"
+#include "spawn.h"
+#include "executableslist.h"
+#include "singleinstance.h"
+#include "utility.h"
+#include "helper.h"
+#include "logbuffer.h"
+#include "selectiondialog.h"
+#include "moapplication.h"
+#include "tutorialmanager.h"
+#include <QLibrary>
+#include <iostream>
+#include <QMessageBox>
+#include <QSharedMemory>
+#include <QBuffer>
+#include <QSplashScreen>
+#include <QDirIterator>
+#include <eh.h>
+#include <windows_error.h>
+
+#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
+
+
+void removeOldLogfiles()
+{
+ QFileInfoList files = QDir(ToQString(GameInfo::instance().getLogDir())).entryInfoList(QStringList("ModOrganizer*.log"),
+ QDir::Files, QDir::Name);
+
+ if (files.count() > 5) {
+ for (int i = 0; i < files.count() - 5; ++i) {
+ QFile::remove(files.at(i).absoluteFilePath());
+ }
+ }
+}
+
+
+// set up required folders (for a first install or after an update or to fix a broken installation)
+bool bootstrap()
+{
+ GameInfo &gameInfo = GameInfo::instance();
+
+ // remove the temporary backup directory in case we're restarting after an update
+ QString moDirectory = QDir::fromNativeSeparators(ToQString(gameInfo.getOrganizerDirectory()));
+ QString backupDirectory = moDirectory.mid(0).append("/update_backup");
+ if (QDir(backupDirectory).exists()) {
+ removeDir(backupDirectory);
+ }
+
+ // cycle logfile
+ removeOldLogfiles();
+
+ // create organizer directories
+ QString dirNames[] = {
+ QDir::fromNativeSeparators(ToQString(gameInfo.getProfilesDir())),
+ QDir::fromNativeSeparators(ToQString(gameInfo.getModsDir())),
+ QDir::fromNativeSeparators(ToQString(gameInfo.getDownloadDir())),
+ QDir::fromNativeSeparators(ToQString(gameInfo.getOverwriteDir())),
+ QDir::fromNativeSeparators(ToQString(gameInfo.getLogDir())),
+ QDir::fromNativeSeparators(ToQString(gameInfo.getTutorialDir()))
+ };
+ static const int NUM_DIRECTORIES = sizeof(dirNames) / sizeof(QString);
+
+ // optimistic run: try to simply create the directories:
+ for (int i = 0; i < NUM_DIRECTORIES; ++i) {
+ if (!QDir(dirNames[i]).exists()) {
+ QDir().mkdir(dirNames[i]);
+ }
+ }
+
+ // verify all directories exist and are writable,
+ // otherwise invoke the helper to create them and make them writable
+ for (int i = 0; i < NUM_DIRECTORIES; ++i) {
+ QFileInfo fileInfo(dirNames[i]);
+ if (!fileInfo.exists() || !fileInfo.isWritable()) {
+ if (QMessageBox::question(NULL, QObject::tr("Permissions required"),
+ QObject::tr("The current user account doesn't have the required access rights to run "
+ "Mod Organizer. The neccessary changes can be made automatically (the MO directory "
+ "will be made writable for the current user account). You will be asked to run "
+ "\"helper.exe\" with administrative rights)."),
+ QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) {
+ if (!Helper::init(GameInfo::instance().getOrganizerDirectory())) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ // no matter which directory didn't exist/wasn't writable, the helper
+ // should have created them all so we can break the loop
+ break;
+ }
+ }
+
+ // verify the hook-dll exists
+ QString dllName = qApp->applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName());
+ HMODULE dllMod = ::LoadLibraryW(ToWString(dllName).c_str());
+ if (dllMod == NULL) {
+ throw windows_error("hook.dll is missing or invalid");
+ }
+ ::FreeLibrary(dllMod);
+
+ return true;
+}
+
+
+void cleanupDir()
+{
+ // files from previous versions of MO that are no longer
+ // required (in that location)
+ QString fileNames[] = {
+ "ModOrganiser.exe",
+ "ModOrganizer.log",
+ "ModOrganizer.log.old",
+ "7z.dll",
+ "mo1.dll",
+ "mo_archive.dll",
+ "mo_helper.exe",
+ "msvcp90.dll",
+ "msvcr90.dll",
+ "phonon4.dll",
+ "QtCore4.dll",
+ "QtGui4.dll",
+ "QtNetwork4.dll",
+ "QtXml4.dll",
+ "QtWebKit4.dll",
+ "qjpeg4.dll"
+ };
+
+ static const int NUM_FILES = sizeof(fileNames) / sizeof(QString);
+
+ for (int i = 0; i < NUM_FILES; ++i) {
+ if (QFile::remove(QApplication::applicationDirPath().append("/").append(fileNames[i]))) {
+ qDebug("%s removed in cleanup",
+ QApplication::applicationDirPath().append("/").append(fileNames[i]).toUtf8().constData());
+ }
+ }
+}
+
+
+bool isNxmLink(const QString &link)
+{
+ return link.left(6).toLower() == "nxm://";
+}
+
+
+LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs)
+{
+ typedef BOOL (WINAPI *FuncMiniDumpWriteDump)(HANDLE process, DWORD pid, HANDLE file, MINIDUMP_TYPE dumpType,
+ const PMINIDUMP_EXCEPTION_INFORMATION exceptionParam,
+ const PMINIDUMP_USER_STREAM_INFORMATION userStreamParam,
+ const PMINIDUMP_CALLBACK_INFORMATION callbackParam);
+ LONG result = EXCEPTION_CONTINUE_SEARCH;
+
+ HMODULE dbgDLL = ::LoadLibrary(L"dbghelp.dll");
+
+ static const int errorLen = 200;
+ char errorBuffer[errorLen + 1];
+ memset(errorBuffer, '\0', errorLen + 1);
+
+ if (dbgDLL) {
+ FuncMiniDumpWriteDump funcDump = (FuncMiniDumpWriteDump)::GetProcAddress(dbgDLL, "MiniDumpWriteDump");
+ if (funcDump) {
+
+ if (QMessageBox::question(NULL, QObject::tr("Woops"),
+ QObject::tr("ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file "
+ "by email (sherb@gmx.net), the bug is a lot more likely to be fixed. "
+ "Please include a short description of what you were doing when the crash happened"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+
+ std::wstring dumpName = ToWString(qApp->applicationFilePath().append(".dmp"));
+
+ HANDLE dumpFile = ::CreateFile(dumpName.c_str(),
+ GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (dumpFile != INVALID_HANDLE_VALUE) {
+ _MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
+ exceptionInfo.ThreadId = ::GetCurrentThreadId();
+ exceptionInfo.ExceptionPointers = exceptionPtrs;
+ exceptionInfo.ClientPointers = NULL;
+
+ BOOL success = funcDump(::GetCurrentProcess(), ::GetCurrentProcessId(), dumpFile, MiniDumpNormal, &exceptionInfo, NULL, NULL);
+
+ ::CloseHandle(dumpFile);
+ if (success) {
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ _snprintf(errorBuffer, errorLen, "failed to save minidump to %ls (error %lu)",
+ dumpName.c_str(), ::GetLastError());
+ } else {
+ _snprintf(errorBuffer, errorLen, "failed to create %ls (error %lu)",
+ dumpName.c_str(), ::GetLastError());
+ }
+ } else {
+ return result;
+ }
+ } else {
+ _snprintf(errorBuffer, errorLen, "dbghelp.dll outdated");
+ }
+ } else {
+ _snprintf(errorBuffer, errorLen, "dbghelp.dll not found");
+ }
+
+ QMessageBox::critical(NULL, QObject::tr("Woops"),
+ QObject::tr("ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1").arg(errorBuffer));
+ return result;
+}
+
+
+void registerMetaTypes()
+{
+ registerExecutable();
+}
+
+
+int main(int argc, char *argv[])
+{
+ MOApplication application(argc, argv);
+ SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
+
+ LogBuffer::init(20, QtDebugMsg, application.applicationDirPath().append("/logs/mo_interface.log"));
+ QPixmap pixmap(":/MO/gui/splash");
+ QSplashScreen splash(pixmap);
+ splash.show();
+
+ registerMetaTypes();
+
+ QStringList arguments = application.arguments();
+
+ bool update = false;
+ if (arguments.contains("update")) {
+ arguments.removeAll("update");
+ update = true;
+ }
+
+ try {
+ SingleInstance instance(update);
+ if (!instance.primaryInstance()) {
+ if ((arguments.size() == 2) &&
+ isNxmLink(arguments.at(1))) {
+ instance.sendMessage(arguments.at(1));
+ return 0;
+ } else if (arguments.size() == 1) {
+ QMessageBox::information(NULL, QObject::tr("Mod Organizer"), QObject::tr("An instance of Mod Organizer is already running"));
+ return 0;
+ }
+ } // we continue for the primary instance OR if MO has been called with parameters
+
+
+ // TODO: this should be MAX_PATH_UNICODE!
+ wchar_t omoPath[MAX_PATH];
+ memset(omoPath, 0, sizeof(TCHAR) * MAX_PATH);
+ ::GetModuleFileNameW(NULL, omoPath, MAX_PATH);
+ wchar_t *lastBSlash = wcsrchr(omoPath, TEXT('\\'));
+ if (lastBSlash != NULL) {
+ *lastBSlash = TEXT('\0');
+ }
+ QSettings settings(ToQString(std::wstring(omoPath).append(L"\\ModOrganizer.ini")), QSettings::IniFormat);
+
+ QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
+
+ bool done = false;
+ while (!done) {
+ if (!GameInfo::init(omoPath, ToWString(gamePath))) {
+ if (!gamePath.isEmpty()) {
+ reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
+ "the game binary and its launcher.").arg(gamePath));
+ }
+ SelectionDialog selection(QObject::tr("Please select the game to manage"), NULL);
+
+ { // add options
+ QString skyrimPath = ToQString(SkyrimInfo::getRegPathStatic());
+ QString falloutNVPath = ToQString(FalloutNVInfo::getRegPathStatic());
+ QString fallout3Path = ToQString(Fallout3Info::getRegPathStatic());
+ QString oblivionPath = ToQString(OblivionInfo::getRegPathStatic());
+ if (skyrimPath.length() != 0) {
+ selection.addChoice(QString("Skyrim"), skyrimPath, skyrimPath);
+ }
+ if (falloutNVPath.length() != 0) {
+ selection.addChoice(QString("Fallout NV"), falloutNVPath, falloutNVPath);
+ }
+ if (fallout3Path.length() != 0) {
+ selection.addChoice(QString("Fallout 3"), fallout3Path, fallout3Path);
+ }
+ if (oblivionPath.length() != 0) {
+ selection.addChoice(QString("Oblivion"), oblivionPath, oblivionPath);
+ }
+
+ selection.addChoice(QString("Browse..."), QString(), QString());
+ }
+
+ if (selection.exec() == QDialog::Rejected) {
+ gamePath = "";
+ done = true;
+ } else {
+ gamePath = QDir::cleanPath(selection.getChoiceData().toString());
+ if (gamePath.isEmpty()) {
+ gamePath = QFileDialog::getExistingDirectory(NULL, QObject::tr("Please select the game to manage"), QString(),
+ QFileDialog::ShowDirsOnly);
+ }
+ }
+ } else {
+ done = true;
+ gamePath = ToQString(GameInfo::instance().getGameDirectory());
+ }
+ }
+
+ if (gamePath.isEmpty()) {
+ // game not found and user canceled
+ return -1;
+ } else if (gamePath.length() != 0) {
+ // user selected a folder and game was initialised with it
+ settings.setValue("gamePath", gamePath.toUtf8().constData());
+ }
+ ExecutablesList executablesList;
+
+ executablesList.init();
+
+ if (!bootstrap()) { // requires gameinfo to be initialised!
+ return -1;
+ }
+
+ cleanupDir();
+
+ int numCustomExecutables = settings.beginReadArray("customExecutables");
+ for (int i = 0; i < numCustomExecutables; ++i) {
+ settings.setArrayIndex(i);
+ CloseMOStyle closeMO = settings.value("closeOnStart").toBool() ? DEFAULT_CLOSE : DEFAULT_STAY;
+ executablesList.addExecutable(settings.value("title").toString(),
+ settings.value("binary").toString(),
+ settings.value("arguments").toString(),
+ settings.value("workingDirectory", "").toString(),
+ closeMO,
+ settings.value("steamAppID", "").toString());
+ }
+
+ settings.endArray();
+
+ TutorialManager::init(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getTutorialDir())).append("/"));
+
+ application.setStyleFile(settings.value("Settings/style", "").toString());
+
+ // set up main window and its data structures
+ MainWindow mainWindow(argv[0], settings);
+ QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString)));
+
+ QObject::connect(&instance, SIGNAL(messageSent(QString)), &mainWindow, SLOT(externalMessage(QString)));
+
+ mainWindow.setExecutablesList(executablesList);
+ mainWindow.readSettings();
+
+ QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray());
+
+ { // see if there is a profile on the command line
+ int profileIndex = arguments.indexOf("-p", 1);
+ if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) {
+ selectedProfileName = arguments.at(profileIndex + 1);
+ }
+ arguments.removeAt(profileIndex);
+ arguments.removeAt(profileIndex);
+ }
+
+ // if we have a command line parameter, it is either a nxm link or
+ // a binary to start
+ if ((arguments.size() > 1) && (!isNxmLink(arguments.at(1)))) {
+ QString exeName = arguments.at(1);
+ arguments.removeFirst(); // remove application name (ModOrganizer.exe)
+ arguments.removeFirst(); // remove binary name
+ // pass the remaining parameters to the binary
+ mainWindow.spawnProgram(exeName, arguments.join(" "), selectedProfileName, QDir());
+ return 0;
+ }
+
+ mainWindow.createFirstProfile();
+
+ if (selectedProfileName.length() != 0) {
+ if (!mainWindow.setCurrentProfile(selectedProfileName)) {
+ mainWindow.setCurrentProfile(1);
+ qWarning("failed to set profile: %s",
+ selectedProfileName.toUtf8().constData());
+ }
+ } else {
+ mainWindow.setCurrentProfile(1);
+ }
+
+ mainWindow.show();
+
+ if ((arguments.size() > 1) &&
+ (isNxmLink(arguments.at(1)))) {
+ mainWindow.externalMessage(arguments.at(1));
+ }
+ splash.finish(&mainWindow);
+ return application.exec();
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ return 1;
+ }
+}
diff --git a/src/main.patch b/src/main.patch new file mode 100644 index 00000000..96b076b4 --- /dev/null +++ b/src/main.patch @@ -0,0 +1,41 @@ +Index: ./main.cpp +=================================================================== +--- ./main.cpp (revision 77) ++++ ./main.cpp (revision 94) +@@ -36,6 +36,7 @@ + #include <QMessageBox> + #include <QSharedMemory> + #include <QBuffer> ++#include <QSplashScreen> + #include <eh.h> + + //#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='*' version='1.0.0.0' type='win32' \"") +@@ -114,6 +115,7 @@ + + + class MyApplication : public QApplication { ++ + public: + + MyApplication(int argc, char **argv) +@@ -202,8 +204,10 @@ + { + MyApplication application(argc, argv); + SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); +- + LogBuffer::init(20, QtDebugMsg, application.applicationDirPath().append("/mo_interface.log")); ++ QPixmap pixmap(":/new/guiresources/splash.png"); ++ QSplashScreen splash(pixmap); ++ splash.show(); + + QStringList arguments = application.arguments(); + +@@ -390,7 +394,7 @@ + (isNxmLink(arguments.at(1)))) { + mainWindow.externalMessage(arguments.at(1)); + } +- ++ splash.finish(&mainWindow); + return application.exec(); + } catch (const std::exception &e) { + reportError(e.what()); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 00000000..7493505c --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,3751 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include <archive.h>
+#include "spawn.h"
+#include "report.h"
+#include "modlist.h"
+#include "profile.h"
+#include "pluginlist.h"
+#include "installdialog.h"
+#include "profilesdialog.h"
+#include "editexecutablesdialog.h"
+#include "categories.h"
+#include "categoriesdialog.h"
+#include "utility.h"
+#include "modinfodialog.h"
+#include "overwriteinfodialog.h"
+#include "activatemodsdialog.h"
+#include "downloadlist.h"
+#include "downloadlistwidget.h"
+#include "downloadlistwidgetcompact.h"
+#include "messagedialog.h"
+#include "installationmanager.h"
+#include "textviewer.h"
+#include "lockeddialog.h"
+#include "syncoverwritedialog.h"
+#include "logbuffer.h"
+#include "downloadlistsortproxy.h"
+#include "modlistsortproxy.h"
+#include "motddialog.h"
+#include "filedialogmemory.h"
+#include "questionboxmemory.h"
+#include "tutorialmanager.h"
+#include "icondelegate.h"
+#include "credentialsdialog.h"
+#include "gameinfoimpl.h"
+#include <gameinfo.h>
+#include <appconfig.h>
+#include <utility.h>
+#include <map>
+#include <ctime>
+#include <QTime>
+#include <util.h>
+#include <QInputDialog>
+#include <QSettings>
+#include <QWhatsThis>
+#include <wchar.h>
+#include <sstream>
+#include <QProcess>
+#include <QMenu>
+#include <QBuffer>
+#include <QInputDialog>
+#include <QDirIterator>
+#include <QHelpEvent>
+#include <QToolTip>
+#include <QFileDialog>
+#include <QTimer>
+#include <QMessageBox>
+#include <QDebug>
+#include <QBuffer>
+#include <QWidgetAction>
+#include <QToolButton>
+#include <QGraphicsObject>
+#include <QPluginLoader>
+#include <QRadioButton>
+#include <QDesktopWidget>
+#include <boost/bind.hpp>
+#include <Psapi.h>
+#include <shlobj.h>
+#include <TlHelp32.h>
+
+//TODO factor out functionality and structure the rest!
+//TODO name slots more consistently
+//TODO turn operations on various trees/lists into actions for easier support in QMenus?
+//TODO verify slots don't throw exceptions
+
+MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent)
+ : QMainWindow(parent), ui(new Ui::MainWindow), m_Tutorial(this, "MainWindow"),
+ m_ExeName(exeName), m_OldProfileIndex(-1),
+ m_DirectoryStructure(new DirectoryEntry(L"data", NULL, 0)),
+ m_ModList(NexusInterface::instance()),
+ m_OldExecutableIndex(-1), m_GamePath(ToQString(GameInfo::instance().getGameDirectory())),
+ m_NexusDialog(NexusInterface::instance()->getAccessManager(), NULL),
+ m_DownloadManager(NexusInterface::instance(), this),
+ m_InstallationManager(this), m_Translator(NULL), m_TranslatorQt(NULL),
+ m_Updater(NexusInterface::instance(), this), m_CategoryFactory(CategoryFactory::instance()),
+ m_CurrentProfile(NULL), m_AskForNexusPW(false), m_LoginAttempted(false),
+ m_ArchivesInit(false), m_ContextItem(NULL), m_CurrentSaveView(NULL),
+ m_GameInfo(new GameInfoImpl())
+{
+ ui->setupUi(this);
+
+ this->setWindowTitle(ToQString(GameInfo::instance().getGameName()).append(" Mod Organizer v").append(m_Updater.getVersion().canonicalString()));
+
+ m_RefreshProgress = new QProgressBar(statusBar());
+ m_RefreshProgress->setTextVisible(true);
+ m_RefreshProgress->setRange(0, 100);
+ m_RefreshProgress->setValue(0);
+ statusBar()->addWidget(m_RefreshProgress, 1000);
+ statusBar()->clearMessage();
+
+ ui->actionEndorseMO->setVisible(false);
+
+ updateProblemsButton();
+
+ updateToolBar();
+ ui->toolBar->blockSignals(true);
+ createHelpWidget();
+
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure);
+
+ // set up mod list
+ m_ModListSortProxy = new ModListSortProxy(m_CurrentProfile, this);
+ m_ModListSortProxy->setSourceModel(&m_ModList);
+ ui->modList->setModel(m_ModListSortProxy);
+
+ ui->modList->sortByColumn(ModList::COL_PRIORITY, Qt::AscendingOrder);
+ ui->modList->setItemDelegateForColumn(ModList::COL_FLAGS, new IconDelegate(m_ModListSortProxy));
+ ui->modList->header()->installEventFilter(&m_ModList);
+ ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray());
+ ui->modList->installEventFilter(&m_ModList);
+ // restoreState also seems to restores the resize mode from previous session,
+ // I don't really like that
+#if QT_VERSION >= 0x50000
+ for (int i = 0; i < ui->modList->header()->count(); ++i) {
+ ui->modList->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ ui->modList->header()->setSectionResizeMode(ModList::COL_NAME, QHeaderView::Stretch);
+#else
+ for (int i = 0; i < ui->modList->header()->count(); ++i) {
+ ui->modList->header()->setResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ ui->modList->header()->setResizeMode(ModList::COL_NAME, QHeaderView::Stretch);
+#endif
+
+ // set up plugin list
+ m_PluginListSortProxy = new PluginListSortProxy(this);
+ m_PluginListSortProxy->setSourceModel(&m_PluginList);
+ ui->espList->setModel(m_PluginListSortProxy);
+ ui->espList->sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder);
+ ui->espList->header()->restoreState(initSettings.value("plugin_list_state").toByteArray());
+ ui->espList->installEventFilter(&m_PluginList);
+#if QT_VERSION >= 0x50000
+ for (int i = 0; i < ui->espList->header()->count(); ++i) {
+ ui->espList->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ ui->espList->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+#else
+ for (int i = 0; i < ui->espList->header()->count(); ++i) {
+ ui->espList->header()->setResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ ui->espList->header()->setResizeMode(0, QHeaderView::Stretch);
+#endif
+
+ QMenu *linkMenu = new QMenu(this);
+ linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Desktop"), this, SLOT(linkDesktop()));
+ linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Start Menu"), this, SLOT(linkMenu()));
+ ui->linkButton->setMenu(linkMenu);
+
+ m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory());
+
+ NexusInterface::instance()->setCacheDirectory(m_Settings.getCacheDirectory());
+ NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion());
+
+ updateDownloadListDelegate();
+ connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), this, SLOT(displayColumnSelection(QPoint)));
+
+ connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString)));
+
+ connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
+ connect(&m_NexusDialog, SIGNAL(requestDownload(QNetworkReply*, int, QString)), this, SLOT(downloadRequested(QNetworkReply*, int, QString)));
+
+ ui->savegameList->installEventFilter(this);
+ ui->savegameList->setMouseTracking(true);
+ connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)),
+ this, SLOT(saveSelectionChanged(QListWidgetItem*)));
+
+ connect(&m_PluginList, SIGNAL(esplist_changed()), this, SLOT(esplist_changed()));
+ connect(&m_ModList, SIGNAL(modorder_changed()), this, SLOT(modorder_changed()));
+ connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString)));
+ connect(&m_ModList, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString)));
+ connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), this, SLOT(modRenamed(QString,QString)));
+ connect(ui->modFilterEdit, SIGNAL(textChanged(QString)), m_ModListSortProxy, SLOT(updateFilter(QString)));
+ connect(&m_ModList, SIGNAL(modlist_changed(int)), m_ModListSortProxy, SLOT(invalidate()));
+ connect(&m_ModList, SIGNAL(removeSelectedMods()), this, SLOT(removeMod_clicked()));
+
+ connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
+ connect(&m_DirectoryRefresher, SIGNAL(progress(int)), this, SLOT(refresher_progress(int)));
+ connect(&m_DirectoryRefresher, SIGNAL(error(QString)), this, SLOT(showError(QString)));
+
+ connect(&m_Settings, SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString)));
+ connect(&m_Settings, SIGNAL(styleChanged(QString)), this, SIGNAL(styleChanged(QString)));
+
+ connect(&m_Updater, SIGNAL(restart()), this, SLOT(close()));
+ connect(&m_Updater, SIGNAL(updateAvailable()), this, SLOT(updateAvailable()));
+ connect(&m_Updater, SIGNAL(motdAvailable(QString)), this, SLOT(motdReceived(QString)));
+
+ connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool)));
+ connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
+
+ connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString)));
+
+ m_DirectoryRefresher.moveToThread(&m_RefresherThread);
+ m_RefresherThread.start();
+
+ setCompactDownloads(initSettings.value("compact_downloads", false).toBool());
+ m_AskForNexusPW = initSettings.value("ask_for_nexuspw", true).toBool();
+ setCategoryListVisible(initSettings.value("categorylist_visible", true).toBool());
+ FileDialogMemory::restore(initSettings);
+
+ fixCategories();
+ m_Updater.testForUpdate();
+ m_StartTime = QTime::currentTime();
+
+ m_Tutorial.expose("modList", &m_ModList);
+ m_Tutorial.expose("espList", &m_PluginList);
+ loadPlugins();
+}
+
+
+MainWindow::~MainWindow()
+{
+ m_RefresherThread.exit();
+ m_RefresherThread.wait();
+ m_NexusDialog.close();
+ delete ui;
+ delete m_GameInfo;
+}
+
+
+void MainWindow::resizeEvent(QResizeEvent *event)
+{
+ m_Tutorial.resize(event->size());
+ QMainWindow::resizeEvent(event);
+}
+
+
+void MainWindow::actionToToolButton(QAction *&sourceAction)
+{
+ QToolButton *button = new QToolButton(ui->toolBar);
+ button->setObjectName(sourceAction->objectName());
+ button->setIcon(sourceAction->icon());
+ button->setText(sourceAction->text());
+ button->setPopupMode(QToolButton::InstantPopup);
+ button->setToolButtonStyle(ui->toolBar->toolButtonStyle());
+ button->setToolTip(sourceAction->toolTip());
+ button->setShortcut(sourceAction->shortcut());
+ QMenu *buttonMenu = new QMenu(sourceAction->text());
+ button->setMenu(buttonMenu);
+ QAction *newAction = ui->toolBar->insertWidget(sourceAction, button);
+ newAction->setObjectName(sourceAction->objectName());
+ ui->toolBar->removeAction(sourceAction);
+ sourceAction->deleteLater();
+ sourceAction = newAction;
+}
+
+
+void MainWindow::updateToolBar()
+{
+ QWidget *spacer = new QWidget(ui->toolBar);
+ spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+
+ actionToToolButton(ui->actionTool);
+ actionToToolButton(ui->actionHelp);
+
+ foreach (QAction *action, ui->toolBar->actions()) {
+ if (action->objectName().length() == 0) {
+ // insert spacers
+ ui->toolBar->insertWidget(action, spacer);
+ }
+ }
+}
+
+
+void MainWindow::updateProblemsButton()
+{
+ QString problemDescription;
+ if (checkForProblems(problemDescription)) {
+ ui->actionProblems->setEnabled(true);
+ ui->actionProblems->setIconText(tr("Problems"));
+ ui->actionProblems->setToolTip(tr("There are potential problems with your setup"));
+ } else {
+ ui->actionProblems->setIconText(tr("No Problems"));
+ ui->actionProblems->setToolTip(tr("Everything seems to be in order"));
+ }
+}
+
+
+bool MainWindow::errorReported(QString &logFile)
+{
+ QDir dir(ToQString(GameInfo::instance().getLogDir()));
+ QFileInfoList files = dir.entryInfoList(QStringList("ModOrganizer_??_??_??_??_??.log"),
+ QDir::Files, QDir::Name | QDir::Reversed);
+
+ if (files.count() > 0) {
+ logFile = files.at(0).absoluteFilePath();
+ QFile file(logFile);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ char buffer[1024];
+ int line = 0;
+ while (!file.atEnd()) {
+ file.readLine(buffer, 1024);
+ if (strncmp(buffer, "ERROR", 5) == 0) {
+ return true;
+ }
+
+ // prevent this function from taking forever
+ if (line++ >= 50000) {
+ break;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool MainWindow::checkForProblems(QString &problemDescription)
+{
+ problemDescription = "";
+
+ foreach (IPluginDiagnose *diagnose, m_DiagnosisPlugins) {
+ std::vector<unsigned int> activeProblems = diagnose->activeProblems();
+ foreach (unsigned int key, activeProblems) {
+ problemDescription.append(tr("<li>%1</li>").arg(diagnose->shortDescription(key)));
+ }
+ }
+
+ QString NCCBinary = QCoreApplication::applicationDirPath().mid(0).append("/NCC/NexusClientCLI.exe");
+ if (!QFile::exists(NCCBinary)) {
+ problemDescription.append(tr("<li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href=\"http://skyrim.nexusmods.com/downloads/file.php?id=1334\">the MO page on nexus</a></li>"));
+ } else {
+ VS_FIXEDFILEINFO versionInfo = GetFileVersion(ToWString(QDir::toNativeSeparators(NCCBinary)));
+ if ((versionInfo.dwFileVersionMS & 0xFFFF) != 0x02) {
+ problemDescription.append(tr("<li>NCC version may be incompatible.</li>"));
+ }
+ }
+
+ if (QSettings("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\NET Framework Setup\\NDP\\v3.5",
+ QSettings::NativeFormat).value("Install", 0) != 1) {
+ QString dotNetUrl = "http://www.microsoft.com/en-us/download/details.aspx?id=17851";
+ problemDescription.append(tr("<li>dotNet is not installed or outdated. This is required to use NCC. "
+ "Get it from here: <a href=\"%1\">%1</a></li>").arg(dotNetUrl));
+ }
+
+ QString logFile;
+ if (errorReported(logFile)) {
+ problemDescription.append(tr("<li>There was an error reported in your last log. Please see %1</li>").arg(logFile));
+ }
+
+ bool res = problemDescription.length() != 0;
+ if (res) {
+ problemDescription.prepend("<ul>").append("</ul>");
+
+ ui->actionProblems->setEnabled(true);
+ ui->actionProblems->setIconText(tr("Problems"));
+ ui->actionProblems->setToolTip(tr("There are potential problems with your setup"));
+ } else {
+ ui->actionProblems->setToolTip(tr("Everything seems to be in order"));
+ }
+ return res;
+}
+
+
+void MainWindow::createHelpWidget()
+{
+ QToolButton *toolBtn = qobject_cast<QToolButton*>(ui->toolBar->widgetForAction(ui->actionHelp));
+ QMenu *buttonMenu = toolBtn->menu();
+
+ QAction *helpAction = new QAction(tr("Help on UI"), buttonMenu);
+ connect(helpAction, SIGNAL(triggered()), this, SLOT(helpTriggered()));
+ buttonMenu->addAction(helpAction);
+
+ QAction *wikiAction = new QAction(tr("Documentation Wiki"), buttonMenu);
+ connect(wikiAction, SIGNAL(triggered()), this, SLOT(wikiTriggered()));
+ buttonMenu->addAction(wikiAction);
+
+ QAction *issueAction = new QAction(tr("Report Issue"), buttonMenu);
+ connect(issueAction, SIGNAL(triggered()), this, SLOT(issueTriggered()));
+ buttonMenu->addAction(issueAction);
+
+ QMenu *tutorialMenu = new QMenu(tr("Tutorials"), buttonMenu);
+
+ typedef std::vector<std::pair<int, QAction*> > ActionList;
+
+ ActionList tutorials;
+ QDirIterator dirIter("tutorials", QStringList("*.js"), QDir::Files);
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ QString fileName = dirIter.fileName();
+ QFile file(dirIter.filePath());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open " << fileName;
+ continue;
+ }
+ QString firstLine = QString::fromUtf8(file.readLine());
+ if (firstLine.startsWith("//TL")) {
+ QStringList params = firstLine.mid(4).trimmed().split('#');
+ if (params.size() != 2) {
+ qCritical() << "invalid header line for tutorial " << fileName << " expected 2 parameters";
+ continue;
+ }
+ QAction *tutAction = new QAction(params.at(0), tutorialMenu);
+ tutAction->setData(fileName);
+ tutorials.push_back(std::make_pair(params.at(1).toInt(), tutAction));
+ }
+ }
+
+ std::sort(tutorials.begin(), tutorials.end(),
+ [](const ActionList::value_type &LHS, const ActionList::value_type &RHS) {
+ return LHS.first < RHS.first; } );
+
+ for (auto iter = tutorials.begin(); iter != tutorials.end(); ++iter) {
+ connect(iter->second, SIGNAL(triggered()), this, SLOT(tutorialTriggered()));
+ tutorialMenu->addAction(iter->second);
+ }
+
+ buttonMenu->addMenu(tutorialMenu);
+}
+
+
+bool MainWindow::saveCurrentLists()
+{
+ if (m_DirectoryUpdate) {
+ qWarning("not saving lists during directory update");
+ return false;
+ }
+
+ // save plugin list
+
+ try {
+ m_PluginList.saveTo(m_CurrentProfile->getPluginsFileName(),
+ m_CurrentProfile->getLoadOrderFileName(),
+ m_CurrentProfile->getLockedOrderFileName(),
+ m_CurrentProfile->getDeleterFileName(),
+ m_Settings.hideUncheckedPlugins());
+
+ if (!m_PluginList.saveLoadOrder(*m_DirectoryStructure)) {
+ MessageDialog::showMessage(tr("load order could not be saved"), this);
+ } else {
+ ui->btnSave->setEnabled(false);
+ }
+ } catch (const std::exception &e) {
+ reportError(tr("failed to save load order: %1").arg(e.what()));
+ }
+
+ if (m_ArchivesInit) {
+ QFile archiveFile(m_CurrentProfile->getArchivesFileName());
+ if (archiveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = ui->bsaList->topLevelItem(i);
+ if ((item != NULL) && (item->checkState(0) == Qt::Checked)) {
+ archiveFile.write(item->text(0).toUtf8().append("\r\n"));
+ }
+ }
+ } else {
+ reportError(tr("failed to save archives order, do you have write access "
+ "to \"%1\"?").arg(m_CurrentProfile->getArchivesFileName()));
+ }
+ archiveFile.close();
+ } else {
+ qWarning("archive list not initialised");
+ }
+ return true;
+}
+
+
+bool MainWindow::addProfile()
+{
+ QComboBox *profileBox = findChild<QComboBox*>("profileBox");
+ bool okClicked = false;
+
+ QString name = QInputDialog::getText(this, tr("Name"),
+ tr("Please enter a name for the new profile"),
+ QLineEdit::Normal, QString(), &okClicked);
+ if (okClicked && (name.size() > 0)) {
+ try {
+ profileBox->addItem(name);
+ profileBox->setCurrentIndex(profileBox->count() - 1);
+ return true;
+ } catch (const std::exception& e) {
+ reportError(tr("failed to create profile: %1").arg(e.what()));
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+
+void MainWindow::hookUpWindowTutorials()
+{
+ QDirIterator dirIter("tutorials", QStringList("*.js"), QDir::Files);
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ QString fileName = dirIter.fileName();
+ QFile file(dirIter.filePath());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open " << fileName;
+ continue;
+ }
+ QString firstLine = QString::fromUtf8(file.readLine());
+ if (firstLine.startsWith("//WIN")) {
+ QString windowName = firstLine.mid(6).trimmed();
+ if (!m_Settings.directInterface().value("CompletedWindowTutorials/" + windowName, false).toBool()) {
+ TutorialManager::instance().activateTutorial(windowName, fileName);
+ }
+ }
+ }
+}
+
+
+void MainWindow::showEvent(QShowEvent *event)
+{
+ refreshFilters();
+
+ QMainWindow::showEvent(event);
+ m_Tutorial.registerControl();
+
+ hookUpWindowTutorials();
+
+ if (m_Settings.directInterface().value("first_start", true).toBool()) {
+ QString firstStepsTutorial = ToQString(AppConfig::firstStepsTutorial());
+ if (TutorialManager::instance().hasTutorial(firstStepsTutorial)) {
+ if (QMessageBox::question(this, tr("Show tutorial?"),
+ tr("You are starting Mod Organizer for the first time. "
+ "Do you want to show a tutorial of its basic features? If you choose "
+ "no you can always start the tutorial from the \"Help\"-menu."),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ TutorialManager::instance().activateTutorial("MainWindow", firstStepsTutorial);
+ }
+ } else {
+ qCritical() << firstStepsTutorial << " missing";
+ QPoint pos = ui->toolBar->mapToGlobal(QPoint());
+ pos.rx() += ui->toolBar->width() / 2;
+ pos.ry() += ui->toolBar->height();
+ QWhatsThis::showText(pos,
+ QObject::tr("Please use \"Help\" from the toolbar to get usage instructions to all elements"));
+ }
+
+ m_Settings.directInterface().setValue("first_start", false);
+ }
+}
+
+
+void MainWindow::closeEvent(QCloseEvent* event)
+{
+ if (m_DownloadManager.downloadsInProgress() &&
+ QMessageBox::question(this, tr("Downloads in progress"),
+ tr("There are still downloads in progress, do you really want to quit?"),
+ QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Cancel) {
+ event->ignore();
+ return;
+ }
+
+ setCursor(Qt::WaitCursor);
+
+ m_NexusDialog.close();
+
+ storeSettings();
+
+ // profile has to be cleaned up before the modinfo-buffer is cleared
+ delete m_CurrentProfile;
+ m_CurrentProfile = NULL;
+
+ ModInfo::clear();
+ LogBuffer::cleanQuit();
+ m_ModList.setProfile(NULL);
+}
+
+
+void MainWindow::createFirstProfile()
+{
+ if (!refreshProfiles(false)) {
+ Profile newProf("Default", false);
+ refreshProfiles(false);
+ }
+}
+
+
+void MainWindow::setBrowserGeometry(const QByteArray &geometry)
+{
+ m_NexusDialog.restoreGeometry(geometry);
+}
+
+
+SaveGameGamebryo *MainWindow::getSaveGame(const QString &name)
+{
+ return new SaveGameGamebryo(this, name);
+}
+
+
+SaveGameGamebryo *MainWindow::getSaveGame(QListWidgetItem *item)
+{
+ try {
+ SaveGameGamebryo *saveGame = getSaveGame(item->data(Qt::UserRole).toString());
+ saveGame->setParent(item->listWidget());
+ return saveGame;
+ } catch (const std::exception &e) {
+ reportError(tr("failed to read savegame: %1").arg(e.what()));
+ return NULL;
+ }
+}
+
+
+void MainWindow::displaySaveGameInfo(const SaveGameGamebryo *save, QPoint pos)
+{
+ if (m_CurrentSaveView == NULL) {
+ m_CurrentSaveView = new SaveGameInfoWidgetGamebryo(save, &m_PluginList, this);
+ } else {
+ m_CurrentSaveView->setSave(save);
+ }
+
+ QRect screenRect = QApplication::desktop()->availableGeometry(m_CurrentSaveView);
+
+ if (pos.x() + m_CurrentSaveView->width() > screenRect.right()) {
+ pos.rx() -= (m_CurrentSaveView->width() + 2);
+ } else {
+ pos.rx() += 5;
+ }
+
+ if (pos.y() + m_CurrentSaveView->height() > screenRect.bottom()) {
+ pos.ry() -= (m_CurrentSaveView->height() + 10);
+ } else {
+ pos.ry() += 20;
+ }
+ m_CurrentSaveView->move(pos);
+
+ m_CurrentSaveView->show();
+ ui->savegameList->activateWindow();
+ connect(m_CurrentSaveView, SIGNAL(closeSaveInfo()), this, SLOT(hideSaveGameInfo()));
+}
+
+
+void MainWindow::saveSelectionChanged(QListWidgetItem *newItem)
+{
+ if (newItem == NULL) {
+ hideSaveGameInfo();
+ } else if ((m_CurrentSaveView == NULL) || (newItem != m_CurrentSaveView->property("displayItem").value<void*>())) {
+ const SaveGameGamebryo *save = getSaveGame(newItem);
+ if (save != NULL) {
+ displaySaveGameInfo(save, QCursor::pos());
+ m_CurrentSaveView->setProperty("displayItem", qVariantFromValue((void*)newItem));
+ }
+ }
+}
+
+
+
+void MainWindow::hideSaveGameInfo()
+{
+ if (m_CurrentSaveView != NULL) {
+ disconnect(m_CurrentSaveView, SIGNAL(closeSaveInfo()), this, SLOT(hideSaveGameInfo()));
+ m_CurrentSaveView->deleteLater();
+ m_CurrentSaveView = NULL;
+ }
+}
+
+
+bool MainWindow::eventFilter(QObject* object, QEvent *event)
+{
+ if ((object == ui->savegameList) &&
+ ((event->type() == QEvent::Leave) || (event->type() == QEvent::WindowDeactivate))) {
+ hideSaveGameInfo();
+ }
+
+ return false;
+}
+
+
+bool MainWindow::testForSteam()
+{
+ DWORD processIDs[1024];
+ DWORD bytesReturned;
+ if (!::EnumProcesses(processIDs, sizeof(processIDs), &bytesReturned)) {
+ qWarning("failed to determine if steam is running");
+ return true;
+ }
+
+ TCHAR processName[MAX_PATH];
+ for (unsigned int i = 0; i < bytesReturned / sizeof(DWORD); ++i) {
+ memset(processName, '\0', sizeof(TCHAR) * MAX_PATH);
+ if (processIDs[i] != 0) {
+ HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]);
+
+ if (process != NULL) {
+ HMODULE module;
+ DWORD ignore;
+
+ // first module in a process is always the binary
+ if (EnumProcessModules(process, &module, sizeof(HMODULE) * 1, &ignore)) {
+ GetModuleBaseName(process, module, processName, MAX_PATH);
+ if ((_tcsicmp(processName, TEXT("steam.exe")) == 0) ||
+ (_tcsicmp(processName, TEXT("steamservice.exe")) == 0)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool MainWindow::verifyPlugin(IPlugin *plugin)
+{
+ if (plugin == NULL) {
+ return false;
+ } else if (!plugin->init(this)) {
+ qWarning("plugin failed to initialize");
+ return false;
+ }
+ return true;
+}
+
+
+void MainWindow::toolPluginInvoke()
+{
+ QAction *triggeredAction = qobject_cast<QAction*>(sender());
+ IPluginTool *plugin = (IPluginTool*)triggeredAction->data().value<void*>();
+ try {
+ plugin->display();
+ } catch (const std::exception &e) {
+ reportError(tr("Plugin \"%1\" failed: %2").arg(plugin->name()).arg(e.what()));
+ }
+}
+
+
+void MainWindow::registerPluginTool(IPluginTool *tool)
+{
+ QAction *action = new QAction(tool->icon(), tool->displayName(), ui->toolBar);
+ action->setToolTip(tool->tooltip());
+ tool->setParentWidget(this);
+ action->setData(qVariantFromValue((void*)tool));
+ connect(action, SIGNAL(triggered()), this, SLOT(toolPluginInvoke()));
+ QToolButton *toolBtn = qobject_cast<QToolButton*>(ui->toolBar->widgetForAction(ui->actionTool));
+ toolBtn->menu()->addAction(action);
+}
+
+
+bool MainWindow::registerPlugin(QObject *plugin)
+{
+ { // generic treatment for all plugins
+ IPlugin *pluginObj = qobject_cast<IPlugin*>(plugin);
+ if (pluginObj == NULL) {
+ return false;
+ }
+ m_Settings.registerPlugin(pluginObj);
+ }
+
+ { // diagnosis plugins
+ IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin);
+ if (diagnose != NULL) {
+ m_DiagnosisPlugins.push_back(diagnose);
+ }
+ }
+
+ { // tool plugins
+ IPluginTool *tool = qobject_cast<IPluginTool*>(plugin);
+ if (verifyPlugin(tool)) {
+ registerPluginTool(tool);
+ return true;
+ }
+ }
+ { // installer plugins
+ IPluginInstaller *installer = qobject_cast<IPluginInstaller*>(plugin);
+ if (verifyPlugin(installer)) {
+ installer->setParentWidget(this);
+ m_InstallationManager.registerInstaller(installer);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void MainWindow::loadPlugins()
+{
+ m_DiagnosisPlugins.clear();
+
+ m_Settings.clearPlugins();
+
+ foreach (QObject *plugin, QPluginLoader::staticInstances()) {
+ registerPlugin(plugin);
+ }
+
+ QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath());
+ qDebug("looking for plugins in %s", pluginPath.toUtf8().constData());
+ QDirIterator iter(pluginPath, QDir::Files | QDir::NoDotAndDotDot);
+ while (iter.hasNext()) {
+ iter.next();
+ QString pluginName = iter.filePath();
+ if (QLibrary::isLibrary(pluginName)) {
+ QPluginLoader pluginLoader(pluginName);
+ if (pluginLoader.instance() == NULL) {
+ qCritical("failed to load plugin %s: %s",
+ pluginName.toUtf8().constData(), pluginLoader.errorString().toUtf8().constData());
+ } else {
+ if (registerPlugin(pluginLoader.instance())) {
+ qDebug("loaded plugin \"%s\"", pluginName.toUtf8().constData());
+ } else {
+ qWarning("plugin \"%s\" failed to load", pluginName.toUtf8().constData());
+ }
+ }
+ }
+ }
+}
+
+IGameInfo &MainWindow::gameInfo() const
+{
+ return *m_GameInfo;
+}
+
+
+QString MainWindow::profileName() const
+{
+ return m_CurrentProfile->getName();
+}
+
+QString MainWindow::profilePath() const
+{
+ return m_CurrentProfile->getPath();
+}
+
+VersionInfo MainWindow::appVersion() const
+{
+ return m_Updater.getVersion();
+}
+
+
+IModInterface *MainWindow::getMod(const QString &name)
+{
+ unsigned int index = ModInfo::getIndex(name);
+ if (index == UINT_MAX) {
+ return NULL;
+ } else {
+ return ModInfo::getByIndex(index).data();
+ }
+}
+
+
+IModInterface *MainWindow::createMod(const QString &name)
+{
+ unsigned int index = ModInfo::getIndex(name);
+ if (index != UINT_MAX) {
+ throw MyException(tr("The mod \"%1\" already exists!").arg(name));
+ }
+
+ QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(name.trimmed());
+
+ QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat);
+
+ settingsFile.setValue("modid", 0);
+ settingsFile.setValue("version", 0);
+ settingsFile.setValue("newestVersion", 0);
+ settingsFile.setValue("category", 0);
+ settingsFile.setValue("installationFile", 0);
+ return ModInfo::createFrom(QDir(targetDirectory), &m_DirectoryStructure).data();
+}
+
+bool MainWindow::removeMod(IModInterface *mod)
+{
+ return ModInfo::removeMod(ModInfo::getIndex(mod->name()));
+}
+
+
+void MainWindow::modDataChanged(IModInterface*)
+{
+ refreshModList();
+}
+
+QVariant MainWindow::pluginSetting(const QString &pluginName, const QString &key) const
+{
+ return m_Settings.pluginSetting(pluginName, key);
+}
+
+
+void MainWindow::startSteam()
+{
+ QSettings steamSettings("HKEY_CURRENT_USER\\Software\\Valve\\Steam",
+ QSettings::NativeFormat);
+ QString exe = steamSettings.value("SteamExe", "").toString();
+ if (!exe.isEmpty()) {
+ QString temp = QString("\"%1\"").arg(exe);
+ if (!QProcess::startDetached(temp)) {
+ reportError(tr("Failed to start \"%1\"").arg(temp));
+ } else {
+ QMessageBox::information(this, tr("Waiting"), tr("Please press OK once you're logged into steam."));
+ }
+ }
+}
+
+
+HANDLE MainWindow::spawnBinaryDirect(const QFileInfo &binary, const QString &arguments, const QString &profileName,
+ const QDir ¤tDirectory, const QString &steamAppID)
+{
+ storeSettings();
+
+ if (!binary.exists()) {
+ reportError(tr("\"%1\" not found").arg(binary.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (!steamAppID.isEmpty()) {
+ ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str());
+ } else {
+ ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(m_Settings.getSteamAppID()).c_str());
+ }
+
+ if ((GameInfo::instance().requiresSteam()) &&
+ (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
+ if (!testForSteam()) {
+ if (QuestionBoxMemory::query(this->isVisible() ? this : NULL,
+ m_Settings.directInterface(), "steamQuery", tr("Start Steam?"),
+ tr("Steam is required to be running already to correctly start the game. "
+ "Should MO try to start steam now?"),
+ QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::Yes) {
+ startSteam();
+ }
+ }
+ }
+
+ return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
+}
+
+
+void MainWindow::spawnProgram(const QString &fileName, const QString &argumentsArg,
+ const QString &profileName, const QDir ¤tDirectory)
+{
+ QFileInfo binary;
+ QString arguments = argumentsArg;
+ QString steamAppID;
+ try {
+ const Executable &exe = m_ExecutablesList.find(fileName);
+ steamAppID = exe.m_SteamAppID;
+ if (arguments == "") {
+ arguments = exe.m_Arguments;
+ }
+ binary = exe.m_BinaryInfo;
+ } catch (const std::runtime_error&) {
+ qWarning("\"%s\" not set up as executable", fileName.toUtf8().constData());
+ binary = QFileInfo(fileName);
+ }
+ spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
+}
+
+
+void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, bool closeAfterStart, const QString &steamAppID)
+{
+ storeSettings();
+
+ HANDLE processHandle = spawnBinaryDirect(binary, arguments, m_CurrentProfile->getName(), currentDirectory, steamAppID);
+ if (processHandle != INVALID_HANDLE_VALUE) {
+ if (closeAfterStart) {
+ close();
+ } else {
+ this->setEnabled(false);
+
+ LockedDialog *dialog = new LockedDialog(this);
+ dialog->show();
+
+ QCoreApplication::processEvents();
+
+ while ((::WaitForSingleObject(processHandle, 1000) == WAIT_TIMEOUT) &&
+ !dialog->unlockClicked()) {
+ // keep processing events so the app doesn't appear dead
+ QCoreApplication::processEvents();
+ }
+
+ this->setEnabled(true);
+ refreshDirectoryStructure();
+ refreshDataTree();
+ if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
+ QFile::remove(m_CurrentProfile->getLoadOrderFileName());
+ }
+ refreshLists();
+ dialog->hide();
+ }
+ }
+}
+
+
+void MainWindow::refreshModList()
+{
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure);
+ m_CurrentProfile->refreshModStatus();
+
+ m_ModList.notifyChange(-1);
+
+ refreshDirectoryStructure();
+}
+
+
+void MainWindow::setExecutablesList(const ExecutablesList &executablesList)
+{
+ m_ExecutablesList = executablesList;
+ refreshExecutablesList();
+}
+
+void MainWindow::setExecutableIndex(int index)
+{
+ QComboBox *executableBox = findChild<QComboBox*>("executablesListBox");
+
+ if ((index != 0) && (executableBox->count() > index)) {
+ executableBox->setCurrentIndex(index);
+ } else {
+ executableBox->setCurrentIndex(1);
+ }
+
+ const Executable &selectedExecutable = executableBox->itemData(executableBox->currentIndex()).value<Executable>();
+
+ QIcon addIcon(":/MO/gui/link");
+ QIcon removeIcon(":/MO/gui/remove");
+
+ QFileInfo linkDesktopFile(QDir::fromNativeSeparators(getDesktopDirectory()) + "/" + selectedExecutable.m_Title + ".lnk");
+ QFileInfo linkMenuFile(QDir::fromNativeSeparators(getStartMenuDirectory()) + "/" + selectedExecutable.m_Title + ".lnk");
+
+ ui->linkButton->menu()->actions().at(0)->setIcon(linkDesktopFile.exists() ? removeIcon : addIcon);
+ ui->linkButton->menu()->actions().at(1)->setIcon(linkMenuFile.exists() ? removeIcon : addIcon);
+}
+
+
+void MainWindow::activateSelectedProfile()
+{
+ QString profileName = ui->profileBox->currentText();
+ qDebug() << "activate profile " << profileName;
+ QString profileDir = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir()))
+ .append("/").append(profileName);
+ delete m_CurrentProfile;
+ m_CurrentProfile = new Profile(QDir(profileDir));
+ m_ModList.setProfile(m_CurrentProfile);
+
+ m_ModListSortProxy->setProfile(m_CurrentProfile);
+
+ connect(m_CurrentProfile, SIGNAL(modStatusChanged(uint)), this, SLOT(modStatusChanged(uint)));
+
+ refreshModList();
+ refreshSaveList();
+}
+
+
+void MainWindow::on_profileBox_currentIndexChanged(int index)
+{
+ if (ui->profileBox->isEnabled()) {
+ int previousIndex = m_OldProfileIndex;
+ m_OldProfileIndex = index;
+
+ if ((previousIndex != -1) &&
+ (m_CurrentProfile != NULL) &&
+ m_CurrentProfile->exists()) {
+ saveCurrentLists();
+ }
+
+ if (ui->profileBox->currentIndex() == 0) {
+ ui->profileBox->setCurrentIndex(previousIndex);
+ ProfilesDialog(m_GamePath).exec();
+ while (!refreshProfiles()) {
+ ProfilesDialog(m_GamePath).exec();
+ }
+ } else {
+ activateSelectedProfile();
+ }
+ }
+}
+
+
+void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const DirectoryEntry &directoryEntry, bool conflictsOnly)
+{
+ {
+ std::vector<FileEntry*> files = directoryEntry.getFiles();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ FileEntry *current = *iter;
+ if (conflictsOnly && (current->getAlternatives().size() == 0)) {
+ continue;
+ }
+
+ QString fileName = ToQString(current->getName());
+ QStringList columns(fileName);
+ bool isArchive = false;
+ int originID = current->getOrigin(isArchive);
+ QString source = ToQString(m_DirectoryStructure->getOriginByID(originID).getName());
+ std::wstring archive = current->getArchive();
+ if (archive.length() != 0) {
+ source.append(" (").append(ToQString(archive)).append(")");
+ }
+ columns.append(source);
+ QTreeWidgetItem *fileChild = new QTreeWidgetItem(columns);
+ if (isArchive) {
+ QFont font = fileChild->font(0);
+ font.setItalic(true);
+ fileChild->setFont(0, font);
+ fileChild->setFont(1, font);
+ } else if (fileName.endsWith(ModInfo::s_HiddenExt)) {
+ QFont font = fileChild->font(0);
+ font.setStrikeOut(true);
+ fileChild->setFont(0, font);
+ fileChild->setFont(1, font);
+ }
+ fileChild->setData(0, Qt::UserRole, ToQString(current->getFullPath()));
+ fileChild->setData(0, Qt::UserRole + 1, isArchive);
+ fileChild->setData(1, Qt::UserRole, source);
+ fileChild->setData(1, Qt::UserRole + 1, originID);
+
+ std::vector<int> alternatives = current->getAlternatives();
+
+ if (!alternatives.empty()) {
+ std::wostringstream altString;
+ altString << ToWString(tr("Also in: <br>"));
+ for (std::vector<int>::iterator altIter = alternatives.begin();
+ altIter != alternatives.end(); ++altIter) {
+ if (altIter != alternatives.begin()) {
+ altString << " , ";
+ }
+ altString << "<span style=\"white-space: nowrap;\"><i>" << m_DirectoryStructure->getOriginByID(*altIter).getName() << "</font></span>";
+ }
+ fileChild->setToolTip(1, QString("%1").arg(ToQString(altString.str())));
+ fileChild->setForeground(1, QBrush(Qt::red));
+ } else {
+ fileChild->setToolTip(1, tr("No conflict"));
+ }
+ subTree->addChild(fileChild);
+ }
+ }
+
+ std::wostringstream temp;
+ temp << directorySoFar << "\\" << directoryEntry.getName();
+ {
+ std::vector<DirectoryEntry*>::const_iterator current, end;
+ directoryEntry.getSubDirectories(current, end);
+ for (; current != end; ++current) {
+ QStringList columns(ToQString((*current)->getName()));
+ columns.append("");
+ QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
+ updateTo(directoryChild, temp.str(), **current, conflictsOnly);
+ if (directoryChild->childCount() != 0) {
+ subTree->addChild(directoryChild);
+ }
+ }
+ }
+ subTree->sortChildren(0, Qt::AscendingOrder);
+}
+
+
+bool MainWindow::refreshProfiles(bool selectProfile)
+{
+ QComboBox* profileBox = findChild<QComboBox*>("profileBox");
+
+ QString currentProfileName = profileBox->currentText();
+
+ profileBox->blockSignals(true);
+ profileBox->clear();
+ profileBox->addItem(QObject::tr("<Manage...>"));
+
+ QDir profilesDir(ToQString(GameInfo::instance().getProfilesDir()));
+ profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+
+ QDirIterator profileIter(profilesDir);
+
+ int newIndex = profileIter.hasNext() ? 1 : 0;
+ int currentIndex = 0;
+ while (profileIter.hasNext()) {
+ profileIter.next();
+ ++currentIndex;
+ try {
+ profileBox->addItem(profileIter.fileName());
+ if (currentProfileName == profileIter.fileName()) {
+ newIndex = currentIndex;
+ }
+ } catch (const std::runtime_error& error) {
+ reportError(QObject::tr("failed to parse profile %1: %2").arg(profileIter.fileName()).arg(error.what()));
+ }
+ }
+
+ // now select one of the profiles, preferably the one that was selected before
+ profileBox->blockSignals(false);
+
+ if (selectProfile) {
+ if (profileBox->count() > 1) {
+ if (currentProfileName.length() != 0) {
+ if ((newIndex != 0) && (profileBox->count() > newIndex)) {
+ profileBox->setCurrentIndex(newIndex);
+ } else {
+ profileBox->setCurrentIndex(1);
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return profileBox->count() > 1;
+ }
+}
+
+
+void MainWindow::refreshDirectoryStructure()
+{
+ m_DirectoryUpdate = true;
+ std::vector<std::tuple<QString, QString, int> > activeModList = m_CurrentProfile->getActiveMods();
+ m_DirectoryRefresher.setMods(activeModList);
+
+ statusBar()->show();
+// m_RefreshProgress->setVisible(true);
+ m_RefreshProgress->setRange(0, 100);
+
+ QTimer::singleShot(0, &m_DirectoryRefresher, SLOT(refresh()));
+}
+
+
+void MainWindow::refreshExecutablesList()
+{
+ QComboBox* executablesList = findChild<QComboBox*>("executablesListBox");
+ executablesList->setEnabled(false);
+ executablesList->clear();
+ executablesList->addItem(tr("<Edit...>"));
+
+ QAbstractItemModel *model = executablesList->model();
+
+ std::vector<Executable>::const_iterator current, end;
+ m_ExecutablesList.getExecutables(current, end);
+ for(int i = 0; current != end; ++current, ++i) {
+ QIcon icon(":/MO/gui/executable");
+ HICON winIcon;
+ QVariant temp;
+ temp.setValue(*current);
+ UINT res = ::ExtractIconExW(ToWString(current->m_BinaryInfo.filePath()).c_str(),
+ 0, &winIcon, NULL, 1);
+ if (res == 1) {
+// icon = pixmapFromHICON(winIcon);
+ icon = QIcon(QPixmap::fromWinHICON(winIcon));
+ ::DestroyIcon(winIcon);
+ }
+ executablesList->addItem(icon, current->m_Title, temp);
+ model->setData(model->index(i, 0), QSize(0, executablesList->iconSize().height() + 4), Qt::SizeHintRole);
+ }
+
+ setExecutableIndex(1);
+ executablesList->setEnabled(true);
+}
+
+
+void MainWindow::refreshDataTree()
+{
+ QCheckBox *conflictsBox = findChild<QCheckBox*>("conflictsCheckBox");
+ QTreeWidget *tree = findChild<QTreeWidget*>("dataTree");
+ tree->clear();
+ QStringList columns("data");
+ columns.append("");
+ QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
+ updateTo(subTree, L"", *m_DirectoryStructure, conflictsBox->isChecked());
+ tree->insertTopLevelItem(0, subTree);
+ subTree->setExpanded(true);
+ tree->header()->resizeSection(0, 200);
+}
+
+
+void MainWindow::refreshSaveList()
+{
+ refreshLists();
+ ui->savegameList->clear();
+
+ QDir savesDir;
+ if (m_CurrentProfile->localSavesEnabled()) {
+ savesDir.setPath(m_CurrentProfile->getPath() + "/saves");
+ } else {
+ wchar_t path[MAX_PATH];
+ ::GetPrivateProfileStringW(L"General", L"SLocalSavePath", L"Saves",
+ path, MAX_PATH,
+ (ToWString(m_CurrentProfile->getPath()) + L"\\" + GameInfo::instance().getIniFileNames().at(0)).c_str());
+ savesDir.setPath(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getDocumentsDir() + L"\\" + path)));
+ }
+
+ QStringList filters;
+ filters << ToQString(GameInfo::instance().getSaveGameExtension());
+ savesDir.setNameFilters(filters);
+
+ QFileInfoList files = savesDir.entryInfoList(QDir::Files, QDir::Time);
+
+ foreach (const QFileInfo &file, files) {
+ QListWidgetItem *item = new QListWidgetItem(file.fileName());
+ item->setData(Qt::UserRole, file.absoluteFilePath());
+ ui->savegameList->addItem(item);
+ }
+}
+
+
+void MainWindow::refreshLists()
+{
+ if (m_DirectoryStructure->isPopulated()) {
+ refreshESPList();
+ refreshBSAList();
+ } // no point in refreshing lists if no files have been added to the directory tree
+}
+
+
+void MainWindow::refreshESPList()
+{
+ m_CurrentProfile->writeModlist();
+
+ // clear list
+ m_PluginList.refresh(m_CurrentProfile->getName(), *m_DirectoryStructure,
+ m_CurrentProfile->getPluginsFileName(),
+ m_CurrentProfile->getLoadOrderFileName(),
+ m_CurrentProfile->getLockedOrderFileName());
+ //m_PluginList.readFrom(m_CurrentProfile->getPluginsFileName());
+
+ findChild<QPushButton*>("btnSave")->setEnabled(false);
+}
+
+
+static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*> &LHS, const std::pair<UINT32, QTreeWidgetItem*> &RHS)
+{
+ return LHS.first < RHS.first;
+}
+
+
+void MainWindow::refreshBSAList()
+{
+ m_ArchivesInit = false;
+ ui->bsaList->clear();
+#if QT_VERSION >= 0x50000
+ ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+#else
+ ui->bsaList->header()->setResizeMode(QHeaderView::ResizeToContents);
+#endif
+
+ m_DefaultArchives.clear();
+
+ wchar_t buffer[256];
+ std::wstring iniFileName = ToWString(QDir::toNativeSeparators(m_CurrentProfile->getIniFileName()));
+ if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ L"", buffer, 256, iniFileName.c_str()) != 0) {
+ m_DefaultArchives = ToQString(buffer).split(',');
+ }
+
+ if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().append(L"2").c_str(),
+ L"", buffer, 256, iniFileName.c_str()) != 0) {
+ m_DefaultArchives.append(ToQString(buffer).split(','));
+ }
+
+ for (int i = 0; i < m_DefaultArchives.count(); ++i) {
+ m_DefaultArchives[i] = m_DefaultArchives[i].trimmed();
+ }
+
+ m_ActiveArchives.clear();
+
+ QFile archiveFile(m_CurrentProfile->getArchivesFileName());
+ if (archiveFile.open(QIODevice::ReadOnly)) {
+ while (!archiveFile.atEnd()) {
+ m_ActiveArchives.append(QString::fromUtf8(archiveFile.readLine()));
+ }
+ archiveFile.close();
+
+ for (int i = 0; i < m_ActiveArchives.count(); ++i) {
+ m_ActiveArchives[i] = m_ActiveArchives[i].trimmed();
+ }
+ } else {
+ m_ActiveArchives = m_DefaultArchives;
+ }
+
+ std::vector<std::pair<UINT32, QTreeWidgetItem*> > items;
+
+ std::vector<FileEntry*> files = m_DirectoryStructure->getFiles();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ FileEntry *current = *iter;
+
+ QString filename = ToQString(current->getName().c_str());
+ QString extension = filename.right(3).toLower();
+
+ if (extension == "bsa") {
+ if (filename.compare("update.bsa", Qt::CaseInsensitive) == 0) {
+ // hack: ignore update.bsa because it confuses people
+ continue;
+ }
+ int index = m_ActiveArchives.indexOf(filename);
+ QStringList strings(filename);
+ bool isArchive = false;
+ int origin = current->getOrigin(isArchive);
+ strings.append(ToQString(m_DirectoryStructure->getOriginByID(origin).getName()));
+ QTreeWidgetItem *newItem = new QTreeWidgetItem(strings);
+ newItem->setData(0, Qt::UserRole, index);
+ newItem->setData(1, Qt::UserRole, origin);
+ newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable);
+ newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
+ if (m_Settings.forceEnableCoreFiles() && m_DefaultArchives.contains(filename)) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ } else {
+ newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
+ }
+
+ if (index < 0) index = 0;
+ UINT32 sortValue = ((m_DirectoryStructure->getOriginByID(origin).getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
+ items.push_back(std::make_pair(sortValue, newItem));
+ }
+ }
+
+ std::sort(items.begin(), items.end(), BySortValue);
+
+ for (std::vector<std::pair<UINT32, QTreeWidgetItem*> >::iterator iter = items.begin(); iter != items.end(); ++iter) {
+ ui->bsaList->addTopLevelItem(iter->second);
+ }
+
+ checkBSAList();
+ m_ArchivesInit = true;
+}
+
+
+void MainWindow::checkBSAList()
+{
+ ui->bsaList->blockSignals(true);
+
+ bool warning = false;
+
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = ui->bsaList->topLevelItem(i);
+ QString filename = item->text(0);
+ item->setIcon(0, QIcon());
+ item->setToolTip(0, QString());
+
+ if (item->checkState(0) == Qt::Unchecked) {
+ if (m_DefaultArchives.contains(filename)) {
+ item->setIcon(0, QIcon(":/MO/gui/resources/dialog-warning.png"));
+ item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!"));
+ warning = true;
+ } else {
+ QString espName = filename.mid(0, filename.length() - 3).append("esp").toLower();
+ QString esmName = filename.mid(0, filename.length() - 3).append("esm").toLower();
+ if (m_PluginList.isEnabled(espName) || m_PluginList.isEnabled(esmName)) {
+ item->setIcon(0, QIcon(":/MO/gui/resources/dialog-warning.png"));
+ item->setToolTip(0, tr("This archive will still be loaded since there is a plugin of the same name but "
+ "its files will not follow installation order!"));
+ warning = true;
+ }
+ }
+ }
+ }
+
+ if (warning) {
+ ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/resources/dialog-warning.png"));
+ } else {
+ ui->tabWidget->setTabIcon(1, QIcon());
+ }
+
+ ui->bsaList->blockSignals(false);
+}
+
+
+void MainWindow::fixCategories()
+{
+ for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
+ std::set<int> categories = modInfo->getCategories();
+ for (std::set<int>::iterator iter = categories.begin();
+ iter != categories.end(); ++iter) {
+ if (!m_CategoryFactory.categoryExists(*iter)) {
+ modInfo->setCategory(*iter, false);
+ }
+ }
+ }
+}
+
+
+void MainWindow::readSettings()
+{
+ QSettings settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat);
+
+ if (settings.contains("window_geometry")) {
+ restoreGeometry(settings.value("window_geometry").toByteArray());
+ }
+
+ if (settings.contains("browser_geometry")) {
+ setBrowserGeometry(settings.value("browser_geometry").toByteArray());
+ }
+
+ bool filtersVisible = settings.value("filters_visible", false).toBool();
+ setCategoryListVisible(filtersVisible);
+ ui->displayCategoriesBtn->setChecked(filtersVisible);
+
+
+ QString language = settings.value("Settings/language", QLocale::system().name()).toString();
+ languageChange(language);
+ int selectedExecutable = settings.value("selected_executable").toInt();
+ setExecutableIndex(selectedExecutable);
+}
+
+
+void MainWindow::storeSettings()
+{
+ if (m_CurrentProfile == NULL) {
+ return;
+ }
+ m_CurrentProfile->writeModlist();
+ m_CurrentProfile->createTweakedIniFile();
+ saveCurrentLists();
+ m_Settings.setupLoadMechanism();
+ QSettings settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat);
+ if (m_CurrentProfile != NULL) {
+ settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData());
+ } else {
+ settings.remove("selected_profile");
+ }
+
+ settings.setValue("mod_list_state", ui->modList->header()->saveState());
+
+ settings.setValue("plugin_list_state", ui->espList->header()->saveState());
+ settings.setValue("compact_downloads", ui->compactBox->isChecked());
+ settings.setValue("ask_for_nexuspw", m_AskForNexusPW);
+
+ settings.setValue("window_geometry", this->saveGeometry());
+ settings.setValue("browser_geometry", m_NexusDialog.saveGeometry());
+
+ settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked());
+
+ settings.remove("customExecutables");
+ settings.beginWriteArray("customExecutables");
+ std::vector<Executable>::const_iterator current, end;
+ m_ExecutablesList.getExecutables(current, end);
+ int count = 0;
+ for (; current != end; ++current) {
+ const Executable &item = *current;
+ if (item.m_Custom) {
+ settings.setArrayIndex(count++);
+ settings.setValue("binary", item.m_BinaryInfo.absoluteFilePath());
+ settings.setValue("title", item.m_Title);
+ settings.setValue("arguments", item.m_Arguments);
+ settings.setValue("workingDirectory", item.m_WorkingDirectory);
+ settings.setValue("closeOnStart", item.m_CloseMO == DEFAULT_CLOSE);
+ settings.setValue("steamAppID", item.m_SteamAppID);
+ }
+ }
+ settings.endArray();
+
+ QComboBox *executableBox = findChild<QComboBox*>("executablesListBox");
+ settings.setValue("selected_executable", executableBox->currentIndex());
+}
+
+
+void MainWindow::on_btnRefreshData_clicked()
+{
+ if (!m_DirectoryUpdate) {
+ refreshDirectoryStructure();
+ refreshDataTree();
+ } else {
+ qDebug("directory update");
+ }
+}
+
+void MainWindow::on_tabWidget_currentChanged(int index)
+{
+ saveCurrentLists();
+ if (index == 0) {
+ refreshESPList();
+ } else if (index == 1) {
+ refreshBSAList();
+ } else if (index == 2) {
+ refreshDataTree();
+ } else if (index == 3) {
+ refreshSaveList();
+ } else if (index == 4) {
+ ui->downloadView->scrollToBottom();
+ }
+}
+
+
+static QString guessModName(const QString &fileName)
+{
+ return QFileInfo(fileName).baseName();
+}
+
+
+void MainWindow::installMod(const QString &fileName)
+{
+ bool hasIniTweaks = false;
+ QString modName;
+ m_CurrentProfile->writeModlistNow();
+ if (m_InstallationManager.install(fileName, m_CurrentProfile->getPluginsFileName(), m_Settings.getModDirectory(), m_Settings.preferIntegratedInstallers(),
+ m_Settings.enableQuickInstaller(), modName, hasIniTweaks)) {
+ MessageDialog::showMessage(tr("Installation successful"), this);
+ refreshModList();
+
+ QModelIndexList posList = m_ModList.match(m_ModList.index(0, 0), Qt::DisplayRole, modName);
+ if (posList.count() == 1) {
+ ui->modList->scrollTo(posList.at(0));
+ }
+ int modIndex = ModInfo::getIndex(modName);
+ if (modIndex != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ if (hasIniTweaks &&
+ (QMessageBox::question(this, tr("Configure Mod"),
+ tr("This mod contains ini tweaks. Do you want to configure them now?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
+ displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
+ }
+ testExtractBSA(modIndex);
+ } else {
+ reportError(tr("mod \"%1\" not found").arg(modName));
+ }
+ } else if (m_InstallationManager.wasCancelled()) {
+ QMessageBox::information(this, tr("Installation cancelled"), tr("The mod was not installed completely."), QMessageBox::Ok);
+ }
+}
+
+
+void MainWindow::installMod()
+{
+ try {
+ QStringList extensions = m_InstallationManager.getSupportedExtensions();
+ for (auto iter = extensions.begin(); iter != extensions.end(); ++iter) {
+ *iter = "*." + *iter;
+ }
+
+ QString fileName = QFileDialog::getOpenFileName(this,
+ tr("Choose Mod"), QString(),
+ tr("Mod Archive").append(QString(" (%1)").arg(extensions.join(" "))));
+
+ if (fileName.length() == 0) {
+ return;
+ } else {
+ installMod(fileName);
+ }
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ }
+}
+
+
+void MainWindow::on_btnSave_clicked()
+{
+ saveCurrentLists();
+}
+
+
+void MainWindow::on_startButton_clicked()
+{
+ QComboBox* executablesList = findChild<QComboBox*>("executablesListBox");
+
+ Executable selectedExecutable = executablesList->itemData(executablesList->currentIndex()).value<Executable>();
+
+ spawnBinary(selectedExecutable.m_BinaryInfo,
+ selectedExecutable.m_Arguments,
+ selectedExecutable.m_WorkingDirectory.length() != 0 ? selectedExecutable.m_WorkingDirectory
+ : selectedExecutable.m_BinaryInfo.absolutePath(),
+ selectedExecutable.m_CloseMO == DEFAULT_CLOSE,
+ selectedExecutable.m_SteamAppID);
+}
+
+
+static HRESULT CreateShortcut(LPCWSTR targetFileName, LPCWSTR arguments,
+ LPCSTR linkFileName, LPCWSTR description,
+ LPCWSTR currentDirectory)
+{
+ HRESULT result = E_INVALIDARG;
+ if ((targetFileName != NULL) && (wcslen(targetFileName) > 0) &&
+ (arguments != NULL) &&
+ (linkFileName != NULL) && (strlen(linkFileName) > 0) &&
+ (description != NULL) &&
+ (currentDirectory != NULL)) {
+
+ IShellLink* shellLink;
+ result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLink, (LPVOID*)&shellLink);
+
+ if (!SUCCEEDED(result)) {
+ qCritical("failed to create IShellLink instance");
+ return result;
+ }
+ if (!SUCCEEDED(result)) return result;
+
+ result = shellLink->SetPath(targetFileName);
+ if (!SUCCEEDED(result)) {
+ qCritical("failed to set target path %ls", targetFileName);
+ shellLink->Release();
+ return result;
+ }
+ result = shellLink->SetArguments(arguments);
+ if (!SUCCEEDED(result)) {
+ qCritical("failed to set arguments: %ls", arguments);
+ shellLink->Release();
+ return result;
+ }
+
+ if (wcslen(description) > 0) {
+ result = shellLink->SetDescription(description);
+ if (!SUCCEEDED(result)) {
+ qCritical("failed to set description: %ls", description);
+ shellLink->Release();
+ return result;
+ }
+ }
+
+ if (wcslen(currentDirectory) > 0) {
+ result = shellLink->SetWorkingDirectory(currentDirectory);
+ if (!SUCCEEDED(result)) {
+ qCritical("failed to set working directory: %ls", currentDirectory);
+ shellLink->Release();
+ return result;
+ }
+ }
+
+ IPersistFile* persistFile;
+ result = shellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&persistFile);
+ if (SUCCEEDED(result)) {
+ wchar_t linkFileNameW[MAX_PATH];
+ MultiByteToWideChar(CP_ACP, 0, linkFileName, -1, linkFileNameW, MAX_PATH);
+ result = persistFile->Save(linkFileNameW, TRUE);
+ persistFile->Release();
+ } else {
+ qCritical("failed to create IPersistFile instance");
+ }
+
+ shellLink->Release();
+ }
+ return result;
+}
+
+
+bool MainWindow::modifyExecutablesDialog()
+{
+ bool result = false;
+ try {
+ EditExecutablesDialog dialog(m_ExecutablesList);
+ if (dialog.exec() == QDialog::Accepted) {
+ m_ExecutablesList = dialog.getExecutablesList();
+ result = true;
+ }
+ refreshExecutablesList();
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ }
+ return result;
+}
+
+void MainWindow::on_executablesListBox_currentIndexChanged(int index)
+{
+ QComboBox* executablesList = findChild<QComboBox*>("executablesListBox");
+
+ int previousIndex = m_OldExecutableIndex;
+ m_OldExecutableIndex = index;
+
+ if (executablesList->isEnabled()) {
+
+ if (executablesList->itemData(index).isNull()) {
+ if (modifyExecutablesDialog()) {
+ setExecutableIndex(previousIndex);
+// executablesList->setCurrentIndex(previousIndex);
+ }
+ } else {
+ setExecutableIndex(index);
+ }
+ }
+}
+
+void MainWindow::helpTriggered()
+{
+ QWhatsThis::enterWhatsThisMode();
+}
+
+void MainWindow::wikiTriggered()
+{
+// ::ShellExecuteW(NULL, L"open", L"http://issue.tannin.eu/tbg/wiki/Modorganizer%3AMainPage", NULL, NULL, SW_SHOWNORMAL);
+ ::ShellExecuteW(NULL, L"open", L"http://wiki.step-project.com/Guide:Mod_Organizer", NULL, NULL, SW_SHOWNORMAL);
+}
+
+void MainWindow::issueTriggered()
+{
+ ::ShellExecuteW(NULL, L"open", L"http://issue.tannin.eu/tbg", NULL, NULL, SW_SHOWNORMAL);
+}
+
+
+void MainWindow::tutorialTriggered()
+{
+ QAction *tutorialAction = qobject_cast<QAction*>(sender());
+ if (tutorialAction != NULL) {
+ if (QMessageBox::question(this, tr("Start Tutorial?"),
+ tr("You're about to start a tutorial. For technical reasons it's not possible to end "
+ "the tutorial early. Continue?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ TutorialManager::instance().activateTutorial("MainWindow", tutorialAction->data().toString());
+ }
+ }
+}
+
+
+void MainWindow::on_actionInstallMod_triggered()
+{
+ installMod();
+}
+
+void MainWindow::on_actionAdd_Profile_triggered()
+{
+ bool repeat = true;
+ while (repeat) {
+ ProfilesDialog profilesDialog(m_GamePath);
+ profilesDialog.exec();
+ if (refreshProfiles() && !profilesDialog.failed()) {
+ repeat = false;
+ }
+ }
+// addProfile();
+}
+
+void MainWindow::on_actionModify_Executables_triggered()
+{
+ if (modifyExecutablesDialog()) {
+ setExecutableIndex(m_OldExecutableIndex);
+ }
+}
+
+
+void MainWindow::setModListSorting(int index)
+{
+ Qt::SortOrder order = ((index & 0x01) != 0) ? Qt::DescendingOrder : Qt::AscendingOrder;
+ int column = index >> 1;
+ ui->modList->header()->setSortIndicator(column, order);
+}
+
+
+void MainWindow::setESPListSorting(int index)
+{
+ switch (index) {
+ case 0: {
+ ui->espList->header()->setSortIndicator(1, Qt::AscendingOrder);
+ } break;
+ case 1: {
+ ui->espList->header()->setSortIndicator(1, Qt::DescendingOrder);
+ } break;
+ case 2: {
+ ui->espList->header()->setSortIndicator(0, Qt::AscendingOrder);
+ } break;
+ case 3: {
+ ui->espList->header()->setSortIndicator(0, Qt::DescendingOrder);
+ } break;
+ }
+}
+
+
+void MainWindow::setCompactDownloads(bool compact)
+{
+ ui->compactBox->setChecked(compact);
+}
+
+
+bool MainWindow::queryLogin(QString &username, QString &password)
+{
+ CredentialsDialog dialog(this);
+ int res = dialog.exec();
+ if (dialog.neverAsk()) {
+ m_AskForNexusPW = false;
+ }
+ if (res == QDialog::Accepted) {
+ username = dialog.username();
+ password = dialog.password();
+ if (dialog.store()) {
+ m_Settings.setNexusLogin(username, password);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool MainWindow::setCurrentProfile(int index)
+{
+ QComboBox *profilesBox = findChild<QComboBox*>("profileBox");
+ if (index >= profilesBox->count()) {
+ return false;
+ } else {
+ profilesBox->setCurrentIndex(index);
+ return true;
+ }
+}
+
+bool MainWindow::setCurrentProfile(const QString &name)
+{
+ QComboBox *profilesBox = findChild<QComboBox*>("profileBox");
+ for (int i = 0; i < profilesBox->count(); ++i) {
+ if (QString::compare(profilesBox->itemText(i), name, Qt::CaseInsensitive) == 0) {
+ profilesBox->setCurrentIndex(i);
+ return true;
+ }
+ }
+ // profile not valid
+ profilesBox->setCurrentIndex(1);
+ return false;
+}
+
+
+void MainWindow::esplist_changed()
+{
+ findChild<QPushButton*>("btnSave")->setEnabled(true);
+}
+
+
+void MainWindow::refresher_progress(int percent)
+{
+ m_RefreshProgress->setValue(percent);
+}
+
+
+void MainWindow::directory_refreshed()
+{
+ DirectoryEntry *newStructure = m_DirectoryRefresher.getDirectoryStructure();
+ if (newStructure != NULL) {
+ delete m_DirectoryStructure;
+ m_DirectoryStructure = newStructure;
+ } else {
+ // TODO: don't know why this happens, this slot seems to get called twice with only one emit
+ return;
+ }
+ m_DirectoryUpdate = false;
+ refreshLists();
+// m_RefreshProgress->setVisible(false);
+ statusBar()->hide();
+}
+
+
+void MainWindow::externalMessage(const QString &message)
+{
+ if (message.left(6).toLower() == "nxm://") {
+ MessageDialog::showMessage(tr("Download started"), this);
+ downloadRequestedNXM(message);
+ }
+}
+
+
+void MainWindow::modStatusChanged(unsigned int index)
+{
+ try {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ if (m_CurrentProfile->modEnabled(index)) {
+ DirectoryRefresher::addModToStructure(m_DirectoryStructure, modInfo->name(), m_CurrentProfile->getModPriority(index), modInfo->absolutePath());
+/* m_DirectoryStructure->addFromOrigin(ToWString(modInfo->name()),
+ ToWString(QDir::toNativeSeparators(modInfo->absolutePath())),
+ m_CurrentProfile->getModPriority(index));*/
+ DirectoryRefresher::cleanStructure(m_DirectoryStructure);
+ } else {
+ if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) {
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
+ origin.enable(false);
+ }
+ }
+ refreshLists();
+ } catch (const std::exception& e) {
+ reportError(tr("failed to update mod list: %1").arg(e.what()));
+ }
+}
+
+
+void MainWindow::removeOrigin(const QString &name)
+{
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(name));
+ origin.enable(false);
+ refreshLists();
+}
+
+
+void MainWindow::modorder_changed()
+{
+ for (unsigned int i = 0; i < m_CurrentProfile->numMods(); ++i) {
+ int priority = m_CurrentProfile->getModPriority(i);
+ if (m_CurrentProfile->modEnabled(i)) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
+ m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())).setPriority(priority);
+ }
+ }
+ m_DirectoryStructure->getFileRegister()->sortOrigins();
+}
+
+void MainWindow::procError(QProcess::ProcessError error)
+{
+ reportError(tr("failed to spawn notepad.exe: %1").arg(error));
+ this->sender()->deleteLater();
+}
+
+void MainWindow::procFinished(int, QProcess::ExitStatus)
+{
+ this->sender()->deleteLater();
+}
+
+
+void MainWindow::on_profileRefreshBtn_clicked()
+{
+ m_CurrentProfile->writeModlist();
+
+// m_ModList.updateModCollection();
+ refreshModList();
+}
+
+
+void MainWindow::showMessage(const QString &message)
+{
+ MessageDialog::showMessage(message, this);
+}
+
+
+void MainWindow::showError(const QString &message)
+{
+ reportError(message);
+}
+
+
+void MainWindow::installMod_clicked()
+{
+ installMod();
+}
+
+
+void MainWindow::renameModInList(QFile &modList, const QString &oldName, const QString &newName)
+{
+ //TODO this code needs to be merged with ModList::readFrom
+ if (!modList.open(QIODevice::ReadWrite)) {
+ reportError(tr("failed to open %1").arg(modList.fileName()));
+ return;
+ }
+
+ QBuffer outBuffer;
+ outBuffer.open(QIODevice::WriteOnly);
+
+ while (!modList.atEnd()) {
+ QByteArray line = modList.readLine();
+ if (line.length() == 0) {
+ break;
+ }
+ if (line.at(0) == '#') {
+ outBuffer.write(line);
+ continue;
+ }
+ QString modName = QString::fromUtf8(line.constData()).trimmed();
+ if (modName.isEmpty()) {
+ break;
+ }
+
+ bool disabled = false;
+ if (modName.at(0) == '-') {
+ disabled = true;
+ modName = modName.mid(1);
+ } else if (modName.at(0) == '+') {
+ modName = modName.mid(1);
+ }
+
+ if (modName == oldName) {
+ modName = newName;
+ }
+
+ if (disabled) {
+ outBuffer.write("-");
+ } else {
+ outBuffer.write("+");
+ }
+ outBuffer.write(modName.toUtf8().constData());
+ outBuffer.write("\r\n");
+ }
+
+ modList.resize(0);
+ modList.write(outBuffer.buffer());
+ modList.close();
+}
+
+
+void MainWindow::modRenamed(const QString &oldName, const QString &newName)
+{
+ // fix the profiles directly on disc
+ for (int i = 0; i < ui->profileBox->count(); ++i) {
+ QString profileName = ui->profileBox->itemText(i);
+
+ //TODO this functionality should be in the Profile class
+ QString modlistName = QString("%1/%2/modlist.txt")
+ .arg(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())))
+ .arg(profileName);
+
+ QFile modList(modlistName);
+ if (modList.exists()) {
+ qDebug("rewrite modlist %s", QDir::toNativeSeparators(modlistName).toUtf8().constData());
+ renameModInList(modList, oldName, newName);
+ }
+ }
+
+ // immediately refresh the active profile because the data in memory is invalid
+ m_CurrentProfile->refreshModStatus();
+
+ // also fix the directory structure
+ try {
+ if (m_DirectoryStructure->originExists(ToWString(oldName))) {
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(oldName));
+ origin.setName(ToWString(newName));
+ } else {
+
+ }
+ } catch (const std::exception &e) {
+ reportError(tr("failed to change origin name: %1").arg(e.what()));
+ }
+}
+
+
+void MainWindow::addFilterItem(const QString &name, int categoryID)
+{
+ QListWidgetItem *item = new QListWidgetItem(name);
+ item->setData(Qt::UserRole, categoryID);
+ ui->categoriesList->addItem(item);
+}
+
+
+void MainWindow::refreshFilters()
+{
+ ui->modList->setCurrentIndex(QModelIndex());
+
+ // save previous filter text so we can restore it later, in case the filter still exists then
+ QListWidgetItem *currentItem = ui->categoriesList->currentItem();
+ QString previousFilter = currentItem != NULL ? currentItem->text() : tr("<All>");
+
+ ui->categoriesList->clear();
+ addFilterItem(tr("<All>"), CategoryFactory::CATEGORY_NONE);
+ addFilterItem(tr("<Checked>"), CategoryFactory::CATEGORY_SPECIAL_CHECKED);
+ addFilterItem(tr("<Unchecked>"), CategoryFactory::CATEGORY_SPECIAL_UNCHECKED);
+ addFilterItem(tr("<Update>"), CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE);
+ addFilterItem(tr("<No category>"), CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY);
+ addFilterItem(tr("<Conflicted>"), CategoryFactory::CATEGORY_SPECIAL_CONFLICT);
+
+ for (unsigned int i = 1; i < m_CategoryFactory.numCategories(); ++i) {
+ bool categoryUsed = false;
+ int categoryId = m_CategoryFactory.getCategoryID(i);
+ for (unsigned int modIdx = 0; modIdx < ModInfo::getNumMods(); ++modIdx) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIdx);
+ if (modInfo->categorySet(categoryId)) {
+ categoryUsed = true;
+ }
+ }
+
+ if (categoryUsed) {
+ addFilterItem(m_CategoryFactory.getCategoryName(i), categoryId);
+ }
+ }
+
+ for (int i = 0; i < ui->categoriesList->count(); ++i) {
+ if (ui->categoriesList->item(i)->text() == previousFilter) {
+ ui->categoriesList->setCurrentRow(i);
+ break;
+ }
+ }
+}
+
+
+void MainWindow::renameMod_clicked()
+{
+ try {
+ QModelIndex treeIdx = m_ModListSortProxy->mapFromSource(m_ModList.index(m_ContextRow, 0));
+ ui->modList->setCurrentIndex(treeIdx);
+ ui->modList->edit(treeIdx);
+ } catch (const std::exception &e) {
+ reportError(tr("failed to rename mod: %1").arg(e.what()));
+ }
+}
+
+
+void MainWindow::restoreBackup_clicked()
+{
+ QRegExp backupRegEx("(.*)_backup[0-9]*$");
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ if (backupRegEx.indexIn(modInfo->name()) != -1) {
+ QString regName = backupRegEx.cap(1);
+ QDir modDir(QDir::fromNativeSeparators(m_Settings.getModDirectory()));
+ if (!modDir.exists(regName) ||
+ (QMessageBox::question(this, tr("Overwrite?"),
+ tr("This will replace the existing mod \"%1\". Continue?").arg(regName),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
+ if (modDir.exists(regName) && !removeDir(modDir.absoluteFilePath(regName))) {
+ reportError(tr("failed to remove mod \"%1\"").arg(regName));
+ } else {
+ QString destinationPath = QDir::fromNativeSeparators(m_Settings.getModDirectory()) + "/" + regName;
+ if (!modDir.rename(modInfo->absolutePath(), destinationPath)) {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(modInfo->absolutePath()).arg(destinationPath));
+ }
+ refreshModList();
+ }
+ }
+ }
+}
+
+
+void MainWindow::removeMod_clicked()
+{
+ try {
+ QItemSelectionModel *selection = ui->modList->selectionModel();
+ if (selection->hasSelection() && selection->selectedRows().count() > 1 ) {
+ QString mods;
+ QStringList modNames;
+ foreach (QModelIndex idx, selection->selectedRows()) {
+ QString name = ModInfo::getByIndex(m_ModListSortProxy->mapToSource(idx).row())->name();
+ mods += "<li>" + name + "</li>";
+ modNames.append(name);
+ }
+ if (QMessageBox::question(this, tr("Confirm"),
+ tr("Remove the following mods?<br><ul>%1</ul>").arg(mods),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ // use mod names instead of indexes because those become invalid during the removal
+ foreach (QString name, modNames) {
+ m_ModList.removeRowForce(ModInfo::getIndex(name));
+ }
+ }
+ } else {
+ m_ModList.removeRow(m_ContextRow, QModelIndex());
+ }
+ } catch (const std::exception &e) {
+ reportError(tr("failed to remove mod: %1").arg(e.what()));
+ }
+}
+
+
+void MainWindow::reinstallMod_clicked()
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ QString installationFile = modInfo->getInstallationFile();
+ if (installationFile.length() != 0) {
+ // there was a bug where mods installed through NCC had the absolute download path stored
+ if (QFileInfo(installationFile).isAbsolute()) {
+ installationFile = QFileInfo(installationFile).fileName();
+ }
+ QString fullInstallationFile = m_DownloadManager.getOutputDirectory().append("/").append(installationFile);
+ if (QFile::exists(fullInstallationFile)) {
+ installMod(fullInstallationFile);
+ } else {
+ QMessageBox::information(this, tr("Failed"), tr("Installation file no longer exists"));
+ }
+ } else {
+ QMessageBox::information(this, tr("Failed"),
+ tr("Mods installed with old versions of MO can't be reinstalled in this way."));
+ }
+}
+
+
+void MainWindow::endorseMod(ModInfo::Ptr mod)
+{
+ if (NexusInterface::instance()->getAccessManager()->loggedIn()) {
+ mod->endorse(true);
+ } else {
+ QString username, password;
+ if (m_Settings.getNexusLogin(username, password)) {
+ m_PostLoginTasks.push_back(boost::bind(&MainWindow::endorseMod, _1, mod));
+ m_NexusDialog.login(username, password);
+ } else {
+ MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this);
+ }
+ }
+}
+
+
+void MainWindow::endorse_clicked()
+{
+ endorseMod(ModInfo::getByIndex(m_ContextRow));
+}
+
+
+void MainWindow::unendorse_clicked()
+{
+ QString username, password;
+ if (NexusInterface::instance()->getAccessManager()->loggedIn()) {
+ ModInfo::getByIndex(m_ContextRow)->endorse(false);
+ } else {
+ if (m_Settings.getNexusLogin(username, password)) {
+ m_PostLoginTasks.push_back(boost::mem_fn(&MainWindow::unendorse_clicked));
+ m_NexusDialog.login(username, password);
+ } else {
+ MessageDialog::showMessage(tr("You need to be logged in with Nexus to endorse"), this);
+ }
+ }
+}
+
+
+void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab)
+{
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+ if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
+ OverwriteInfoDialog dialog(modInfo, this);
+ dialog.exec();
+ } else {
+ ModInfoDialog dialog(modInfo, m_DirectoryStructure, this);
+ connect(&dialog, SIGNAL(nexusLinkActivated(QString)), this, SLOT(nexusLinkActivated(QString)));
+ connect(&dialog, SIGNAL(downloadRequest(QString)), this, SLOT(downloadRequestedNXM(QString)));
+ connect(&dialog, SIGNAL(modOpen(QString, int)), this, SLOT(displayModInformation(QString, int)));
+ connect(&dialog, SIGNAL(originModified(int)), this, SLOT(originModified(int)));
+ connect(&dialog, SIGNAL(endorseMod(ModInfo::Ptr)), this, SLOT(endorseMod(ModInfo::Ptr)));
+
+ dialog.openTab(tab);
+ dialog.exec();
+
+ modInfo->saveMeta();
+ emit modInfoDisplayed();
+ }
+
+ if (m_CurrentProfile->modEnabled(index)) {
+ FilesOrigin& origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
+ origin.enable(false);
+
+ if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) {
+ FilesOrigin& origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
+ origin.enable(false);
+
+/* m_DirectoryStructure->addFromOrigin(ToWString(modInfo->name()),
+ ToWString(QDir::toNativeSeparators(modInfo->absolutePath())),
+ m_CurrentProfile->getModPriority(index));*/
+ DirectoryRefresher::addModToStructure(m_DirectoryStructure,
+ modInfo->name(), m_CurrentProfile->getModPriority(index),
+ modInfo->absolutePath());
+ DirectoryRefresher::cleanStructure(m_DirectoryStructure);
+ refreshLists();
+ }
+ }
+}
+
+
+void MainWindow::displayModInformation(const QString &modName, int tab)
+{
+ unsigned int index = ModInfo::getIndex(modName);
+ if (index == UINT_MAX) {
+ qCritical("failed to resolve mod name %s", modName.toUtf8().constData());
+ return;
+ }
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ displayModInformation(modInfo, index, tab);
+}
+
+
+void MainWindow::displayModInformation(int row, int tab)
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+ displayModInformation(modInfo, row, tab);
+}
+
+
+void MainWindow::testExtractBSA(int modIndex)
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ QDir dir(modInfo->absolutePath());
+
+ QFileInfoList archives = dir.entryInfoList(QStringList("*.bsa"));
+ if (archives.length() != 0 &&
+ (QuestionBoxMemory::query(this, m_Settings.directInterface(), "unpackBSA", tr("Extract BSA"),
+ tr("This mod contains at least one BSA. Do you want to unpack it?\n"
+ "(This removes the BSA after completion. If you don't know about BSAs, just select no)"),
+ QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::No) == QMessageBox::Yes)) {
+
+
+ foreach (QFileInfo archiveInfo, archives) {
+ BSA::Archive archive;
+
+ BSA::EErrorCode result = archive.read(archiveInfo.absoluteFilePath().toLocal8Bit().constData());
+ if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) {
+ reportError(tr("failed to read %1: %2").arg(archiveInfo.fileName()).arg(result));
+ return;
+ }
+
+ QProgressDialog progress(this);
+ progress.setMaximum(100);
+ progress.setValue(0);
+ progress.show();
+
+ archive.extractAll(modInfo->absolutePath().toUtf8().constData(),
+ boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2));
+
+ if (result == BSA::ERROR_INVALIDHASHES) {
+ reportError(tr("This archive contains invalid hashes. Some files may be broken."));
+ }
+
+ archive.close();
+
+ if (!QFile::remove(archiveInfo.absoluteFilePath())) {
+ qCritical("failed to remove archive %s", archiveInfo.absoluteFilePath().toUtf8().constData());
+ } else {
+ m_DirectoryStructure->removeFile(ToWString(archiveInfo.fileName()));
+ }
+ }
+
+ refreshBSAList();
+ }
+}
+
+
+void MainWindow::visitOnNexus_clicked()
+{
+ int modID = m_ModList.data(m_ModList.index(m_ContextRow, 0), Qt::UserRole).toInt();
+ if (modID > 0) {
+ nexusLinkActivated(QString("%1/downloads/file.php?id=%2").arg(ToQString(GameInfo::instance().getNexusPage())).arg(modID));
+ } else {
+ MessageDialog::showMessage(tr("Nexus ID for this Mod is unknown"), this);
+ }
+}
+
+void MainWindow::openExplorer_clicked()
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+
+ ::ShellExecuteW(NULL, L"explore", ToWString(modInfo->absolutePath()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+}
+
+
+void MainWindow::information_clicked()
+{
+ try {
+ displayModInformation(m_ContextRow);
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ }
+}
+
+
+void MainWindow::syncOverwrite()
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ SyncOverwriteDialog syncDialog(modInfo->absolutePath(), m_DirectoryStructure, this);
+ if (syncDialog.exec() == QDialog::Accepted) {
+ syncDialog.apply(QDir::fromNativeSeparators(m_Settings.getModDirectory()));
+ modInfo->testValid();
+ refreshDirectoryStructure();
+ }
+}
+
+
+void MainWindow::setPriorityMax()
+{
+ int newPriority = m_CurrentProfile->numMods() - 1;
+ m_CurrentProfile->setModPriority(m_ContextRow, newPriority);
+}
+
+
+void MainWindow::setPriorityManually()
+{
+// m_CurrentProfile->setModPriority(m_ContextRow, m_CurrentProfile->numMods() - 1);
+
+ int current = m_CurrentProfile->getModPriority(m_ContextRow);
+ int newPriority = QInputDialog::getInt(this, tr("Priority"), tr("Choose Priority"), current, 0, m_ModList.rowCount() - 1);
+ m_ModList.changeModPriority(m_ContextRow, newPriority);
+// m_CurrentProfile->setModPriority(m_ContextRow, newPriority);
+}
+
+
+void MainWindow::setPriorityMin()
+{
+ int newPriority = 0;
+ m_CurrentProfile->setModPriority(m_ContextRow, newPriority);
+}
+
+
+void MainWindow::cancelModListEditor()
+{
+ ui->modList->setEnabled(false);
+ ui->modList->setEnabled(true);
+}
+
+
+void MainWindow::on_modList_doubleClicked(const QModelIndex &index)
+{
+ try {
+ displayModInformation(m_ModListSortProxy->mapToSource(index).row());
+ // workaround to cancel the editor that might have opened because of
+ // selection-click
+ ui->modList->closePersistentEditor(index);
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ }
+}
+
+
+bool MainWindow::addCategories(QMenu *menu, int targetID)
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ const std::set<int> &categories = modInfo->getCategories();
+
+ bool childEnabled = false;
+
+ for (unsigned i = 1; i < m_CategoryFactory.numCategories(); ++i) {
+ if (m_CategoryFactory.getParentID(i) == targetID) {
+ QMenu *targetMenu = menu;
+ if (m_CategoryFactory.hasChildren(i)) {
+ targetMenu = menu->addMenu(
+ m_CategoryFactory.getCategoryName(i).replace('&', "&&"));
+ }
+
+ int id = m_CategoryFactory.getCategoryID(i);
+ QScopedPointer<QCheckBox> checkBox(new QCheckBox(targetMenu));
+ bool enabled = categories.find(id) != categories.end();
+ checkBox->setText(m_CategoryFactory.getCategoryName(i).replace('&', "&&"));
+ if (enabled) {
+ childEnabled = true;
+ }
+ checkBox->setChecked(enabled ? Qt::Checked : Qt::Unchecked);
+
+ QScopedPointer<QWidgetAction> checkableAction(new QWidgetAction(targetMenu));
+ checkableAction->setDefaultWidget(checkBox.take());
+ checkableAction->setData(id);
+ targetMenu->addAction(checkableAction.take());
+
+ if (m_CategoryFactory.hasChildren(i)) {
+ if (addCategories(targetMenu, m_CategoryFactory.getCategoryID(i)) || enabled) {
+ targetMenu->setIcon(QIcon(":/MO/gui/resources/check.png"));
+ }
+ }
+ }
+ }
+ return childEnabled;
+}
+
+
+void MainWindow::saveCategoriesFromMenu(QMenu *menu, int modRow)
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modRow);
+ foreach (QAction* action, menu->actions()) {
+ if (action->menu() != NULL) {
+ saveCategoriesFromMenu(action->menu(), modRow);
+ } else {
+ QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ QCheckBox *checkbox = qobject_cast<QCheckBox*>(widgetAction->defaultWidget());
+ modInfo->setCategory(widgetAction->data().toInt(), checkbox->isChecked());
+// m_ModList.setModCategory(modRow, widgetAction->data().toInt(), checkbox->isChecked());
+ }
+ }
+ }
+}
+
+
+void MainWindow::saveCategories()
+{
+ QMenu *menu = qobject_cast<QMenu*>(sender());
+ if (menu == NULL) {
+ qCritical("not a menu?");
+ return;
+ }
+// m_ModList.resetCategories(m_ContextRow);
+ saveCategoriesFromMenu(menu, m_ContextRow);
+
+ refreshFilters();
+}
+
+
+void MainWindow::savePrimaryCategory()
+{
+ QMenu *menu = qobject_cast<QMenu*>(sender());
+ if (menu == NULL) {
+ qCritical("not a menu?");
+ return;
+ }
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+ foreach (QAction* action, menu->actions()) {
+ QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ QRadioButton *btn = qobject_cast<QRadioButton*>(widgetAction->defaultWidget());
+ if (btn->isChecked()) {
+ modInfo->setPrimaryCategory(widgetAction->data().toInt());
+ break;
+ }
+ }
+ }
+}
+
+
+void MainWindow::checkModsForUpdates()
+{
+ if (NexusInterface::instance()->getAccessManager()->loggedIn()) {
+ m_ModsToUpdate = ModInfo::checkAllForUpdate(this);
+ statusBar()->show();
+ m_RefreshProgress->setRange(0, m_ModsToUpdate);
+ } else {
+ QString username, password;
+ if (m_Settings.getNexusLogin(username, password)) {
+ m_PostLoginTasks.push_back(boost::mem_fn(&MainWindow::checkModsForUpdates));
+ m_NexusDialog.login(username, password);
+ } else { // otherwise there will be no endorsement info
+ m_ModsToUpdate = ModInfo::checkAllForUpdate(this);
+ }
+ }
+}
+
+
+void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info)
+{
+ const std::set<int> &categories = info->getCategories();
+ foreach (int categoryID, categories) {
+ int catIdx = m_CategoryFactory.getCategoryIndex(categoryID);
+ QWidgetAction *action = new QWidgetAction(primaryCategoryMenu);
+ try {
+ QRadioButton *categoryBox = new QRadioButton(m_CategoryFactory.getCategoryName(catIdx).replace('&', "&&"),
+ primaryCategoryMenu);
+ categoryBox->setChecked(categoryID == info->getPrimaryCategory());
+ action->setDefaultWidget(categoryBox);
+ } catch (const std::exception &e) {
+ qCritical("failed to create category checkbox: %s", e.what());
+ }
+
+ action->setData(categoryID);
+ primaryCategoryMenu->addAction(action);
+ }
+}
+
+
+void MainWindow::addPrimaryCategoryCandidates()
+{
+ QMenu *menu = qobject_cast<QMenu*>(sender());
+ if (menu == NULL) {
+ qCritical("not a menu?");
+ return;
+ }
+ menu->clear();
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
+
+ addPrimaryCategoryCandidates(menu, modInfo);
+}
+
+
+void MainWindow::enableVisibleMods()
+{
+ if (QMessageBox::question(NULL, tr("Confirm"), tr("Really enable all visible mods?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ m_ModListSortProxy->enableAllVisible();
+ }
+}
+
+
+void MainWindow::disableVisibleMods()
+{
+ if (QMessageBox::question(NULL, tr("Confirm"), tr("Really disable all visible mods?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ m_ModListSortProxy->disableAllVisible();
+ }
+}
+
+
+void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
+{
+ try {
+ QTreeView *modList = findChild<QTreeView*>("modList");
+
+ m_ContextRow = m_ModListSortProxy->mapToSource(modList->indexAt(pos)).row();
+
+ QMenu menu;
+ menu.addAction(tr("Install Mod..."), this, SLOT(installMod_clicked()));
+
+ menu.addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods()));
+ menu.addAction(tr("Disable all visible"), this, SLOT(disableVisibleMods()));
+
+ menu.addAction(tr("Check all for update"), this, SLOT(checkModsForUpdates()));
+
+ menu.addAction(tr("Refresh"), this, SLOT(on_profileRefreshBtn_clicked()));
+
+ if (m_ContextRow != -1) {
+ menu.addSeparator();
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ std::vector<ModInfo::EFlag> flags = info->getFlags();
+ if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
+ menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite()));
+ } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) {
+ menu.addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked()));
+ menu.addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked()));
+ } else {
+ QMenu *addCategoryMenu = menu.addMenu(tr("Set Category"));
+ addCategories(addCategoryMenu, 0);
+ connect(addCategoryMenu, SIGNAL(aboutToHide()), this, SLOT(saveCategories()));
+
+ QMenu *primaryCategoryMenu = menu.addMenu(tr("Primary Category"));
+ connect(primaryCategoryMenu, SIGNAL(aboutToShow()), this, SLOT(addPrimaryCategoryCandidates()));
+ connect(primaryCategoryMenu, SIGNAL(aboutToHide()), this, SLOT(savePrimaryCategory()));
+
+ menu.addAction(tr("Rename Mod..."), this, SLOT(renameMod_clicked()));
+ menu.addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked()));
+ menu.addAction(tr("Reinstall Mod"), this, SLOT(reinstallMod_clicked()));
+ switch (info->endorsedState()) {
+ case ModInfo::ENDORSED_TRUE: {
+ menu.addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked()));
+ } break;
+ case ModInfo::ENDORSED_FALSE: {
+ menu.addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
+ } break;
+ default: {
+ QAction *action = new QAction(tr("Endorsement state unknown"), &menu);
+ action->setEnabled(false);
+ menu.addAction(action);
+ } break;
+ }
+
+ menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
+ menu.addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
+ }
+
+ QAction *infoAction = menu.addAction(tr("Information..."), this, SLOT(information_clicked()));
+ menu.setDefaultAction(infoAction);
+ }
+
+ menu.exec(modList->mapToGlobal(pos));
+ } catch (const std::exception &e) {
+ reportError(tr("Exception: ").arg(e.what()));
+ } catch (...) {
+ reportError(tr("Unknown exception"));
+ }
+}
+
+
+void MainWindow::on_categoriesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *)
+{
+ if (current != NULL) {
+ m_ModListSortProxy->setCategoryFilter(current->data(Qt::UserRole).toInt());
+ ui->currentCategoryLabel->setText(QString("(%1)").arg(current->text()));
+ }
+}
+
+
+void MainWindow::fixMods_clicked()
+{
+ QListWidgetItem *selectedItem = ui->savegameList->item(m_SelectedSaveGame);
+ if (selectedItem == NULL) {
+ return;
+ }
+
+ // if required, parse the save game
+ if (selectedItem->data(Qt::UserRole).isNull()) {
+ QVariant temp;
+ SaveGameGamebryo *save = getSaveGame(selectedItem->data(Qt::UserRole).toString());
+ save->setParent(selectedItem->listWidget());
+ temp.setValue(save);
+ selectedItem->setData(Qt::UserRole, temp);
+ }
+
+ const SaveGameGamebryo *save = qvariant_cast<SaveGameGamebryo*>(selectedItem->data(Qt::UserRole));
+
+ // collect the list of missing plugins
+ std::map<QString, std::vector<QString> > missingPlugins;
+
+ for (int i = 0; i < save->numPlugins(); ++i) {
+ const QString &pluginName = save->plugin(i);
+ if (!m_PluginList.isEnabled(pluginName)) {
+ missingPlugins[pluginName] = std::vector<QString>();
+ }
+ }
+
+ // figure out, for each esp/esm, which mod, if any, contains it
+ QStringList espFilter("*.esp");
+ espFilter.append("*.esm");
+
+ {
+ QDir dataDir(m_GamePath + "/data");
+ QStringList esps = dataDir.entryList(espFilter);
+ foreach (const QString &esp, esps) {
+ std::map<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp);
+ if (iter != missingPlugins.end()) {
+ iter->second.push_back("<data>");
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i < m_CurrentProfile->numRegularMods(); ++i) {
+ int modIndex = m_CurrentProfile->modIndexByPriority(i);
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+
+ QStringList esps = QDir(modInfo->absolutePath()).entryList(espFilter);
+ foreach (const QString &esp, esps) {
+ std::map<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp);
+ if (iter != missingPlugins.end()) {
+ iter->second.push_back(modInfo->name());
+ }
+ }
+ }
+
+ ActivateModsDialog dialog(missingPlugins, this);
+ if (dialog.exec() == QDialog::Accepted) {
+ // activate the required mods, then enable all esps
+ std::set<QString> modsToActivate = dialog.getModsToActivate();
+ for (std::set<QString>::iterator iter = modsToActivate.begin(); iter != modsToActivate.end(); ++iter) {
+ if (*iter != "<data>") {
+ unsigned int modIndex = ModInfo::getIndex(*iter);
+ m_CurrentProfile->setModEnabled(modIndex, true);
+ }
+ }
+
+ m_CurrentProfile->writeModlist();
+ refreshLists();
+
+ std::set<QString> espsToActivate = dialog.getESPsToActivate();
+ for (std::set<QString>::iterator iter = espsToActivate.begin(); iter != espsToActivate.end(); ++iter) {
+ m_PluginList.enableESP(*iter);
+ }
+ saveCurrentLists();
+ }
+}
+
+
+void MainWindow::on_savegameList_customContextMenuRequested(const QPoint &pos)
+{
+ QListWidgetItem *selectedItem = ui->savegameList->itemAt(pos);
+ if (selectedItem == NULL) {
+ return;
+ }
+
+ m_SelectedSaveGame = ui->savegameList->row(selectedItem);
+
+ QMenu menu;
+ menu.addAction(tr("Fix Mods..."), this, SLOT(fixMods_clicked()));
+
+ menu.exec(ui->savegameList->mapToGlobal(pos));
+}
+
+void MainWindow::linkDesktop()
+{
+ QComboBox* executablesList = findChild<QComboBox*>("executablesListBox");
+// QPushButton *linkButton = findChild<QPushButton*>("linkDesktopButton");
+
+ const Executable &selectedExecutable = executablesList->itemData(executablesList->currentIndex()).value<Executable>();
+ QString linkName = getDesktopDirectory() + "\\" + selectedExecutable.m_Title + ".lnk";
+
+ if (QFile::exists(linkName)) {
+ if (QFile::remove(linkName)) {
+ ui->linkButton->menu()->actions().at(0)->setIcon(QIcon(":/MO/gui/link"));
+ } else {
+ reportError(tr("failed to remove %1").arg(linkName));
+ }
+ } else {
+ QFileInfo exeInfo(m_ExeName);
+ // create link
+ std::wstring targetFile = ToWString(exeInfo.absoluteFilePath());
+ std::wstring parameter = ToWString(QString("\"") + selectedExecutable.m_BinaryInfo.absoluteFilePath() + "\" " + selectedExecutable.m_Arguments);
+ std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName());
+ std::wstring currentDirectory = ToWString(selectedExecutable.m_BinaryInfo.absolutePath());
+
+ if (CreateShortcut(targetFile.c_str(), parameter.c_str(),
+ linkName.toUtf8().constData(),
+ description.c_str(), currentDirectory.c_str()) != E_INVALIDARG) {
+ ui->linkButton->menu()->actions().at(0)->setIcon(QIcon(":/MO/gui/remove"));
+ } else {
+ reportError(tr("failed to create %1").arg(linkName));
+ }
+ }
+}
+
+void MainWindow::linkMenu()
+{
+ QComboBox* executablesList = findChild<QComboBox*>("executablesListBox");
+
+ const Executable &selectedExecutable = executablesList->itemData(executablesList->currentIndex()).value<Executable>();
+ QString linkName = getStartMenuDirectory() + "\\" + selectedExecutable.m_Title + ".lnk";
+
+ if (QFile::exists(linkName)) {
+ if (QFile::remove(linkName)) {
+ ui->linkButton->menu()->actions().at(1)->setIcon(QIcon(":/MO/gui/link"));
+ } else {
+ reportError(tr("failed to remove %1").arg(linkName));
+ }
+ } else {
+ QFileInfo exeInfo(m_ExeName);
+ // create link
+ std::wstring targetFile = ToWString(exeInfo.absoluteFilePath());
+ std::wstring parameter = ToWString(QString("\"") + selectedExecutable.m_BinaryInfo.absoluteFilePath() + "\" " + selectedExecutable.m_Arguments);
+ std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName());
+ std::wstring currentDirectory = ToWString(selectedExecutable.m_BinaryInfo.absolutePath());
+
+ if (CreateShortcut(targetFile.c_str(), parameter.c_str(),
+ linkName.toUtf8().constData(),
+ description.c_str(), currentDirectory.c_str()) != E_INVALIDARG) {
+ ui->linkButton->menu()->actions().at(1)->setIcon(QIcon(":/MO/gui/remove"));
+ } else {
+ reportError(tr("failed to create %1").arg(linkName));
+ }
+ }
+}
+
+void MainWindow::on_actionSettings_triggered()
+{
+ QString oldModDirectory(m_Settings.getModDirectory());
+ QString oldCacheDirectory(m_Settings.getCacheDirectory());
+ m_Settings.query(this);
+ fixCategories();
+ refreshFilters();
+ if (QDir::fromNativeSeparators(m_DownloadManager.getOutputDirectory()) != QDir::fromNativeSeparators(m_Settings.getDownloadDirectory())) {
+ if (m_DownloadManager.downloadsInProgress()) {
+ MessageDialog::showMessage(tr("Can't change download directory while downloads are in progress!"), this);
+ } else {
+ m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory());
+ }
+ }
+
+ if (m_Settings.getModDirectory() != oldModDirectory) {
+ refreshModList();
+ refreshLists();
+ }
+
+ if (m_Settings.getCacheDirectory() != oldCacheDirectory) {
+ NexusInterface::instance()->setCacheDirectory(m_Settings.getCacheDirectory());
+ }
+
+ NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion());
+}
+
+void MainWindow::on_actionNexus_triggered()
+{
+ QString username, password;
+ m_NexusDialog.openUrl(ToQString(GameInfo::instance().getNexusPage()));
+
+ if (m_Settings.getNexusLogin(username, password)) {
+ m_NexusDialog.login(username, password);
+ } else {
+ m_NexusDialog.loadNexus();
+ }
+ m_NexusDialog.show();
+ m_NexusDialog.activateWindow();
+
+ QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
+ tabWidget->setCurrentIndex(4);
+}
+
+
+void MainWindow::nexusLinkActivated(const QString &link)
+{
+ if (m_Settings.preferExternalBrowser()) {
+ ::ShellExecuteW(NULL, L"open", ToWString(link).c_str(), NULL, NULL, SW_SHOWNORMAL);
+ } else {
+ QString username, password;
+ m_NexusDialog.openUrl(link);
+ if (m_Settings.getNexusLogin(username, password)) {
+ m_NexusDialog.login(username, password);
+ m_LoginAttempted = true;
+ } else {
+ m_NexusDialog.loadNexus();
+ }
+ m_NexusDialog.show();
+
+ QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
+ tabWidget->setCurrentIndex(4);
+ }
+}
+
+
+void MainWindow::downloadRequestedNXM(const QString &url)
+{
+ QString username, password;
+
+ if (!m_LoginAttempted && !NexusInterface::instance()->getAccessManager()->loggedIn() &&
+ (m_Settings.getNexusLogin(username, password) ||
+ (m_AskForNexusPW && queryLogin(username, password)))) {
+ m_PendingDownloads.append(url);
+ NexusInterface::instance()->getAccessManager()->login(username, password);
+ m_LoginAttempted = true;
+ } else {
+ m_DownloadManager.addNXMDownload(url);
+ }
+}
+
+
+void MainWindow::downloadRequested(QNetworkReply *reply, int modID, const QString &fileName)
+{
+ try {
+ if (m_DownloadManager.addDownload(reply, fileName, modID)) {
+ MessageDialog::showMessage(tr("Download started"), this);
+ }
+ } catch (const std::exception &e) {
+ MessageDialog::showMessage(tr("Download failed"), this);
+ qCritical("exception starting download: %s", e.what());
+ }
+}
+
+
+void MainWindow::languageChange(const QString &newLanguage)
+{
+ if (m_Translator != NULL) {
+ QCoreApplication::removeTranslator(m_Translator);
+ delete m_Translator;
+ m_Translator = NULL;
+ }
+ if (m_TranslatorQt != NULL) {
+ QCoreApplication::removeTranslator(m_TranslatorQt);
+ delete m_TranslatorQt;
+ m_TranslatorQt = NULL;
+ }
+
+ if (newLanguage != "en_US") {
+ // add our own translations
+ m_Translator = new QTranslator(this);
+ QString locFile = ToQString(AppConfig::translationPrefix()) + "_" + newLanguage;
+ if (!m_Translator->load(locFile, QCoreApplication::applicationDirPath() + "/translations")) {
+ qDebug("localization %s not found", locFile.toUtf8().constData());
+ }
+ QCoreApplication::installTranslator(m_Translator);
+
+ // also add the translations for qt default strings
+ m_TranslatorQt = new QTranslator(this);
+ locFile = QString("qt_") + newLanguage;
+ if (!m_TranslatorQt->load(locFile, QCoreApplication::applicationDirPath() + "/translations")) {
+ qDebug("localization %s not found", locFile.toUtf8().constData());
+ }
+ QCoreApplication::installTranslator(m_TranslatorQt);
+ }
+ ui->retranslateUi(this);
+ ui->profileBox->setItemText(0, QObject::tr("<Manage...>"));
+// ui->toolBar->addWidget(createHelpWidget(ui->toolBar));
+
+ updateDownloadListDelegate();
+ updateProblemsButton();
+}
+
+
+void MainWindow::installDownload(int index)
+{
+ try {
+ QString fileName = m_DownloadManager.getFilePath(index);
+ int modID = m_DownloadManager.getModID(index);
+ QString modName;
+ // see if there already are mods with the specified mod id
+ if (modID != 0) {
+ ModInfo::Ptr modInfo = ModInfo::getByModID(modID, true);
+ if (!modInfo.isNull()) {
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+ if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end()) {
+ modName = modInfo->name();
+ modInfo->saveMeta();
+ }
+ }
+ // TODO there may be multiple mods with the same id!
+// modName = m_ModList.getModByModID(modID);
+ }
+
+ m_CurrentProfile->writeModlistNow();
+
+ bool hasIniTweaks = false;
+ if (m_InstallationManager.install(fileName, m_CurrentProfile->getPluginsFileName(), m_Settings.getModDirectory(), m_Settings.preferIntegratedInstallers(),
+ m_Settings.enableQuickInstaller(), modName, hasIniTweaks)) {
+ MessageDialog::showMessage(tr("Installation successful"), this);
+
+ refreshModList();
+
+ QModelIndexList posList = m_ModList.match(m_ModList.index(0, 0), Qt::DisplayRole, modName);
+ if (posList.count() == 1) {
+ ui->modList->scrollTo(posList.at(0));
+ }
+ int modIndex = ModInfo::getIndex(modName);
+ if (modIndex != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+
+ if (hasIniTweaks &&
+ (QMessageBox::question(this, tr("Configure Mod"),
+ tr("This mod contains ini tweaks. Do you want to configure them now?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
+ displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
+ }
+ testExtractBSA(modIndex);
+ } else {
+ reportError(tr("mod \"%1\" not found").arg(modName));
+ }
+
+ m_DownloadManager.markInstalled(index);
+
+ emit modInstalled();
+ } else if (m_InstallationManager.wasCancelled()) {
+ QMessageBox::information(this, tr("Installation cancelled"), tr("The mod was not installed completely."), QMessageBox::Ok);
+ }
+ } catch (const std::exception &e) {
+ reportError(e.what());
+ }
+}
+
+
+void MainWindow::writeDataToFile(QFile &file, const QString &directory, const DirectoryEntry &directoryEntry)
+{
+ { // list files
+// std::set<FileEntry>::const_iterator current, end;
+// directoryEntry.getFiles(current, end);
+// for (; current != end; ++current) {
+
+ std::vector<FileEntry*> files = directoryEntry.getFiles();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ FileEntry *current = *iter;
+ bool isArchive = false;
+ int origin = current->getOrigin(isArchive);
+ if (isArchive) {
+ // TODO: don't list files from archives. maybe make this an option?
+ continue;
+ }
+ QString fullName = directory;
+ fullName.append("\\").append(ToQString(current->getName()));
+ file.write(fullName.toUtf8());
+
+ file.write("\t(");
+ file.write(ToQString(m_DirectoryStructure->getOriginByID(origin).getName()).toUtf8());
+ file.write(")\r\n");
+ }
+ }
+
+ { // recurse into subdirectories
+ std::vector<DirectoryEntry*>::const_iterator current, end;
+ directoryEntry.getSubDirectories(current, end);
+ for (; current != end; ++current) {
+ writeDataToFile(file, directory.mid(0).append("\\").append(ToQString((*current)->getName())), **current);
+ }
+ }
+}
+
+
+void MainWindow::writeDataToFile()
+{
+ QString fileName = QFileDialog::getSaveFileName(this);
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ reportError(tr("failed to write to file %1").arg(fileName));
+ }
+
+ writeDataToFile(file, "data", *m_DirectoryStructure);
+ file.close();
+
+ MessageDialog::showMessage(tr("%1 written").arg(QDir::toNativeSeparators(fileName)), this);
+}
+
+
+int MainWindow::getBinaryExecuteInfo(const QFileInfo &targetInfo,
+ QFileInfo &binaryInfo, QString &arguments)
+{
+ QString extension = targetInfo.completeSuffix();
+ if ((extension == "exe") ||
+ (extension == "cmd") ||
+ (extension == "com") ||
+ (extension == "bat")) {
+ binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe");
+ arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ return 1;
+ } else if (extension == "jar") {
+ // types that need to be injected into
+ std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath());
+ QString binaryPath;
+
+ { // try to find java automatically
+ WCHAR buffer[MAX_PATH];
+ if (FindExecutableW(targetPathW.c_str(), NULL, buffer) > (HINSTANCE)32) {
+ DWORD binaryType = 0UL;
+ if (!::GetBinaryTypeW(targetPathW.c_str(), &binaryType)) {
+ qDebug("failed to determine binary type: %lu", ::GetLastError());
+ } else if (binaryType == SCS_32BIT_BINARY) {
+ binaryPath = ToQString(buffer);
+ }
+ }
+ }
+ if (binaryPath.isEmpty() && (extension == "jar")) {
+ QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat);
+ if (javaReg.contains("CurrentVersion")) {
+ QString currentVersion = javaReg.value("CurrentVersion").toString();
+ binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe");
+ }
+ }
+ if (binaryPath.isEmpty()) {
+ binaryPath = QFileDialog::getOpenFileName(this, tr("Select binary"), QString(), tr("Binary") + " (*.exe)");
+ }
+ if (binaryPath.isEmpty()) {
+ return 0;
+ }
+ binaryInfo = QFileInfo(binaryPath);
+ if (extension == "jar") {
+ arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ } else {
+ arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ }
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+
+void MainWindow::addAsExecutable()
+{
+ if (m_ContextItem != NULL) {
+ QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
+ QFileInfo binaryInfo;
+ QString arguments;
+ switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
+ case 1: {
+ QString name = QInputDialog::getText(this, tr("Enter Name"),
+ tr("Please enter a name for the executable"), QLineEdit::Normal,
+ targetInfo.baseName());
+ if (!name.isEmpty()) {
+ m_ExecutablesList.addExecutable(name, binaryInfo.absoluteFilePath(),
+ arguments, targetInfo.absolutePath(),
+ DEFAULT_STAY, QString());
+ refreshExecutablesList();
+ }
+ } break;
+ case 2: {
+ QMessageBox::information(this, tr("Not an executable"), tr("This is not a recognized executable."));
+ } break;
+ default: {
+ // nop
+ } break;
+ }
+ }
+}
+
+
+void MainWindow::originModified(int originID)
+{
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByID(originID);
+ origin.enable(false);
+ m_DirectoryStructure->addFromOrigin(origin.getName(), origin.getPath(), origin.getPriority());
+ DirectoryRefresher::cleanStructure(m_DirectoryStructure);
+}
+
+
+void MainWindow::hideFile()
+{
+ QString oldName = m_ContextItem->data(0, Qt::UserRole).toString();
+ QString newName = oldName + ModInfo::s_HiddenExt;
+
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a hidden version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+
+ if (QFile::rename(oldName, newName)) {
+ originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
+ refreshDataTree();
+ } else {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(oldName).arg(QDir::toNativeSeparators(newName)));
+ }
+}
+
+
+void MainWindow::unhideFile()
+{
+ QString oldName = m_ContextItem->data(0, Qt::UserRole).toString();
+ QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length());
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a visible version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+ if (QFile::rename(oldName, newName)) {
+ originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
+ refreshDataTree();
+ } else {
+ reportError(tr("failed to rename \"%1\" to \"%2\"").arg(QDir::toNativeSeparators(oldName)).arg(QDir::toNativeSeparators(newName)));
+ }
+}
+
+
+void MainWindow::openDataFile()
+{
+ if (m_ContextItem != NULL) {
+ QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
+ QFileInfo binaryInfo;
+ QString arguments;
+ switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
+ case 1: {
+ spawnBinaryDirect(binaryInfo, arguments, m_CurrentProfile->getName(), targetInfo.absolutePath(), "");
+ } break;
+ case 2: {
+ ::ShellExecuteW(NULL, L"open", ToWString(targetInfo.absoluteFilePath()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+ } break;
+ default: {
+ // nop
+ } break;
+ }
+ }
+}
+
+
+void MainWindow::updateAvailable()
+{
+ QToolBar *toolBar = findChild<QToolBar*>("toolBar");
+ foreach (QAction *action, toolBar->actions()) {
+ if (action->text() == tr("Update")) {
+ action->setEnabled(true);
+ action->setToolTip(tr("Update available"));
+ break;
+ }
+ }
+}
+
+
+void MainWindow::motdReceived(const QString &motd)
+{
+ // don't show motd after 5 seconds, may be annoying. Hopefully the user's
+ // internet connection is faster next time
+ if (m_StartTime.secsTo(QTime::currentTime()) < 5) {
+ uint hash = qHash(motd);
+ if (hash != m_Settings.getMotDHash()) {
+ MotDDialog dialog(motd);
+ dialog.exec();
+ m_Settings.setMotDHash(hash);
+ }
+ }
+
+ ui->actionEndorseMO->setVisible(false);
+}
+
+
+void MainWindow::notEndorsedYet()
+{
+ ui->actionEndorseMO->setVisible(true);
+}
+
+
+void MainWindow::on_dataTree_customContextMenuRequested(const QPoint &pos)
+{
+ QTreeWidget *dataTree = findChild<QTreeWidget*>("dataTree");
+ m_ContextItem = dataTree->itemAt(pos.x(), pos.y());
+
+ QMenu menu;
+ if ((m_ContextItem != NULL) && (m_ContextItem->childCount() == 0)) {
+ menu.addAction(tr("Open/Execute"), this, SLOT(openDataFile()));
+ menu.addAction(tr("Add as Executable"), this, SLOT(addAsExecutable()));
+ // offer to hide/unhide file, but not for files from archives
+ if (!m_ContextItem->data(0, Qt::UserRole + 1).toBool()) {
+ if (m_ContextItem->text(0).endsWith(ModInfo::s_HiddenExt)) {
+ menu.addAction(tr("Un-Hide"), this, SLOT(unhideFile()));
+ } else {
+ menu.addAction(tr("Hide"), this, SLOT(hideFile()));
+ }
+ }
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Write To File..."), this, SLOT(writeDataToFile()));
+ menu.addAction(tr("Refresh"), this, SLOT(on_btnRefreshData_clicked()));
+
+ menu.exec(dataTree->mapToGlobal(pos));
+}
+
+void MainWindow::on_conflictsCheckBox_toggled(bool)
+{
+ refreshDataTree();
+}
+
+
+void MainWindow::on_actionUpdate_triggered()
+{
+ QString username, password;
+
+ if (!m_LoginAttempted && !NexusInterface::instance()->getAccessManager()->loggedIn() &&
+ (m_Settings.getNexusLogin(username, password) ||
+ (m_AskForNexusPW && queryLogin(username, password)))) {
+ NexusInterface::instance()->getAccessManager()->login(username, password);
+ m_LoginAttempted = true;
+ } else {
+ m_Updater.startUpdate();
+ }
+}
+
+
+void MainWindow::on_actionEndorseMO_triggered()
+{
+ if (QMessageBox::question(this, tr("Endorse Mod Organizer"),
+ tr("Do you want to endorse Mod Organizer on %1 now?").arg(ToQString(GameInfo::instance().getNexusPage())),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ NexusInterface::instance()->requestToggleEndorsement(GameInfo::instance().getNexusModID(), true, this, QVariant());
+ }
+}
+
+
+void MainWindow::updateDownloadListDelegate()
+{
+ if (ui->compactBox->isChecked()) {
+ ui->downloadView->setItemDelegate(new DownloadListWidgetCompactDelegate(&m_DownloadManager, ui->downloadView));
+ } else {
+ ui->downloadView->setItemDelegate(new DownloadListWidgetDelegate(&m_DownloadManager, ui->downloadView));
+ }
+
+ DownloadListSortProxy *sortProxy = new DownloadListSortProxy(&m_DownloadManager, ui->downloadView);
+ sortProxy->setSourceModel(new DownloadList(&m_DownloadManager, ui->downloadView));
+ connect(ui->downloadFilterEdit, SIGNAL(textChanged(QString)), sortProxy, SLOT(updateFilter(QString)));
+
+ ui->downloadView->setModel(sortProxy);
+ ui->downloadView->sortByColumn(1, Qt::AscendingOrder);
+ ui->downloadView->header()->resizeSections(QHeaderView::Fixed);
+// ui->downloadView->setFirstColumnSpanned(0, QModelIndex(), true);
+
+ connect(ui->downloadView->itemDelegate(), SIGNAL(installDownload(int)), this, SLOT(installDownload(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(queryInfo(int)), &m_DownloadManager, SLOT(queryInfo(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(removeDownload(int, bool)), &m_DownloadManager, SLOT(removeDownload(int, bool)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(cancelDownload(int)), &m_DownloadManager, SLOT(cancelDownload(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(pauseDownload(int)), &m_DownloadManager, SLOT(pauseDownload(int)));
+ connect(ui->downloadView->itemDelegate(), SIGNAL(resumeDownload(int)), &m_DownloadManager, SLOT(resumeDownload(int)));
+}
+
+
+void MainWindow::on_compactBox_toggled(bool)
+{
+ updateDownloadListDelegate();
+}
+
+
+void MainWindow::modDetailsUpdated(bool)
+{
+ --m_ModsToUpdate;
+ if (m_ModsToUpdate == 0) {
+ statusBar()->hide();
+ m_ModListSortProxy->setCategoryFilter(CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE);
+ for (int i = 0; i < ui->categoriesList->count(); ++i) {
+ if (ui->categoriesList->item(i)->data(Qt::UserRole) == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE) {
+ ui->categoriesList->setCurrentRow(i);
+ break;
+ }
+ }
+// m_RefreshProgress->setVisible(false);
+ } else {
+ m_RefreshProgress->setValue(m_RefreshProgress->maximum() - m_ModsToUpdate);
+ }
+}
+
+void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int)
+{
+ m_ModsToUpdate -= modIDs.size();
+
+ QVariantList resultList = resultData.toList();
+ for (auto iter = resultList.begin(); iter != resultList.end(); ++iter) {
+ QVariantMap result = iter->toMap();
+ if (result["id"].toInt() == GameInfo::instance().getNexusModID()) {
+ if (!result["voted_by_user"].toBool()) {
+ ui->actionEndorseMO->setVisible(true);
+ }
+ } else {
+ ModInfo::Ptr info = ModInfo::getByModID(result["id"].toInt(), true);
+ if (!info.isNull()) {
+ info->setNewestVersion(VersionInfo(result["version"].toString()));
+ info->setNexusDescription(result["description"].toString());
+ if (NexusInterface::instance()->getAccessManager()->loggedIn()) {
+ // don't use endorsement info if we're not logged in
+ info->setIsEndorsed(result["voted_by_user"].toBool());
+ }
+ }
+ }
+ }
+
+ if (m_ModsToUpdate <= 0) {
+ statusBar()->hide();
+ m_ModListSortProxy->setCategoryFilter(CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE);
+ for (int i = 0; i < ui->categoriesList->count(); ++i) {
+ if (ui->categoriesList->item(i)->data(Qt::UserRole) == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE) {
+ ui->categoriesList->setCurrentRow(i);
+ break;
+ }
+ }
+ } else {
+ m_RefreshProgress->setValue(m_RefreshProgress->maximum() - m_ModsToUpdate);
+ }
+}
+
+
+void MainWindow::nxmEndorsementToggled(int, QVariant, QVariant resultData, int)
+{
+ if (resultData.toBool()) {
+ ui->actionEndorseMO->setVisible(false);
+ QMessageBox::question(this, tr("Thank you!"), tr("Thank you for your endorsement!"));
+ }
+
+ if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(int, QVariant, QVariant, int)),
+ this, SLOT(nxmEndorsementToggled(int, QVariant, QVariant, int)))) {
+ qCritical("failed to disconnect endorsement slot");
+ }
+}
+
+
+void MainWindow::nxmRequestFailed(int modID, QVariant, int, const QString &errorString)
+{
+ if (modID == -1) {
+ // must be the update-check that failed
+ m_ModsToUpdate = 0;
+ statusBar()->hide();
+ }
+ MessageDialog::showMessage(tr("Request to Nexus failed: %1").arg(errorString), this);
+}
+
+
+void MainWindow::loginSuccessful(bool necessary)
+{
+ if (necessary) {
+ MessageDialog::showMessage(tr("login successful"), this);
+ }
+ foreach (QString url, m_PendingDownloads) {
+ downloadRequestedNXM(url);
+ }
+ m_PendingDownloads.clear();
+ foreach (auto task, m_PostLoginTasks) {
+ task(this);
+ }
+
+ m_PostLoginTasks.clear();
+}
+
+
+void MainWindow::loginSuccessfulUpdate(bool necessary)
+{
+ if (necessary) {
+ MessageDialog::showMessage(tr("login successful"), this);
+ }
+ m_Updater.startUpdate();
+}
+
+
+void MainWindow::loginFailed(const QString &message)
+{
+ if (!m_PendingDownloads.isEmpty()) {
+ MessageDialog::showMessage(tr("login failed: %1. Trying to download anyway").arg(message), this);
+ foreach (QString url, m_PendingDownloads) {
+ downloadRequestedNXM(url);
+ }
+ }
+ m_PendingDownloads.clear();
+}
+
+
+void MainWindow::loginFailedUpdate(const QString &message)
+{
+ MessageDialog::showMessage(tr("login failed: %1. You need to log-in with Nexus to update MO.").arg(message), this);
+}
+
+
+void MainWindow::windowTutorialFinished(const QString &windowName)
+{
+ m_Settings.directInterface().setValue(QString("CompletedWindowTutorials/") + windowName, true);
+}
+
+
+BSA::EErrorCode MainWindow::extractBSA(BSA::Archive &archive, BSA::Folder::Ptr folder, const QString &destination,
+ QProgressDialog &progress)
+{
+ QDir().mkdir(destination);
+ BSA::EErrorCode result = BSA::ERROR_NONE;
+ QString errorFile;
+
+ for (unsigned int i = 0; i < folder->getNumFiles(); ++i) {
+ BSA::File::Ptr file = folder->getFile(i);
+ BSA::EErrorCode res = archive.extract(file, destination.toUtf8().constData());
+ if (res != BSA::ERROR_NONE) {
+ reportError(tr("failed to read %1: %2").arg(file->getName().c_str()).arg(res));
+ result = res;
+ }
+ progress.setLabelText(file->getName().c_str());
+ progress.setValue(progress.value() + 1);
+ QCoreApplication::processEvents();
+ if (progress.wasCanceled()) {
+ result = BSA::ERROR_CANCELED;
+ }
+ }
+
+ if (result != BSA::ERROR_NONE) {
+ if (QMessageBox::critical(this, tr("Error"), tr("failed to extract %1 (errorcode %2)").arg(errorFile).arg(result),
+ QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
+ return result;
+ }
+ }
+
+ for (unsigned int i = 0; i < folder->getNumSubFolders(); ++i) {
+ BSA::Folder::Ptr subFolder = folder->getSubFolder(i);
+ BSA::EErrorCode res = extractBSA(archive, subFolder,
+ destination.mid(0).append("/").append(subFolder->getName().c_str()), progress);
+ if (res != BSA::ERROR_NONE) {
+ return res;
+ }
+ }
+ return BSA::ERROR_NONE;
+}
+
+
+bool MainWindow::extractProgress(QProgressDialog &progress, int percentage, std::string fileName)
+{
+ progress.setLabelText(fileName.c_str());
+ progress.setValue(percentage);
+ QCoreApplication::processEvents();
+ return !progress.wasCanceled();
+}
+
+
+void MainWindow::extractBSATriggered()
+{
+ QTreeWidgetItem *item = ui->bsaList->topLevelItem(m_ContextRow);
+
+ QString targetFolder = FileDialogMemory::getExistingDirectory("extractBSA", this, tr("Extract BSA"));
+
+ if (!targetFolder.isEmpty()) {
+ BSA::Archive archive;
+ QString originPath = QDir::fromNativeSeparators(ToQString(m_DirectoryStructure->getOriginByName(ToWString(item->text(1))).getPath()));
+ QString archivePath = QString("%1\\%2").arg(originPath).arg(item->text(0));
+
+ BSA::EErrorCode result = archive.read(archivePath.toLocal8Bit().constData());
+ if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) {
+ reportError(tr("failed to read %1: %2").arg(archivePath).arg(result));
+ return;
+ }
+
+ QProgressDialog progress(this);
+ progress.setMaximum(100);
+ progress.setValue(0);
+ progress.show();
+
+ archive.extractAll(QDir::toNativeSeparators(targetFolder).toUtf8().constData(),
+ boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2));
+
+ if (result == BSA::ERROR_INVALIDHASHES) {
+ reportError(tr("This archive contains invalid hashes. Some files may be broken."));
+ }
+ }
+}
+
+
+void MainWindow::displayColumnSelection(const QPoint &pos)
+{
+ QMenu menu;
+
+ // display a list of all headers as checkboxes
+ QAbstractItemModel *model = ui->modList->header()->model();
+ for (int i = 0; i < model->columnCount(); ++i) {
+ QString columnName = model->headerData(i, Qt::Horizontal).toString();
+ QCheckBox *checkBox = new QCheckBox(&menu);
+ checkBox->setText(columnName);
+ checkBox->setChecked(!ui->modList->header()->isSectionHidden(i));
+ QWidgetAction *checkableAction = new QWidgetAction(&menu);
+ checkableAction->setDefaultWidget(checkBox);
+ menu.addAction(checkableAction);
+ }
+ menu.exec(pos);
+
+ // view/hide columns depending on check-state
+ int i = 0;
+ foreach (const QAction *action, menu.actions()) {
+ const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(widgetAction->defaultWidget());
+ if (checkBox != NULL) {
+ ui->modList->header()->setSectionHidden(i, !checkBox->isChecked());
+ }
+ }
+ ++i;
+ }
+}
+
+
+void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos)
+{
+ m_ContextRow = ui->bsaList->indexOfTopLevelItem(ui->bsaList->itemAt(pos));
+
+ QMenu menu;
+ menu.addAction(tr("Extract..."), this, SLOT(extractBSATriggered()));
+
+ menu.exec(ui->bsaList->mapToGlobal(pos));
+}
+
+void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
+{
+ checkBSAList();
+}
+
+void MainWindow::on_actionProblems_triggered()
+{
+ QString problemDescription;
+ checkForProblems(problemDescription);
+ QMessageBox::information(this, tr("Problems"), problemDescription);
+}
+
+void MainWindow::setCategoryListVisible(bool visible)
+{
+ if (visible) {
+ ui->categoriesGroup->show();
+ ui->displayCategoriesBtn->setText(ToQString(L"\u00ab"));
+ } else {
+ ui->categoriesGroup->hide();
+ ui->displayCategoriesBtn->setText(ToQString(L"\u00bb"));
+ }
+}
+
+void MainWindow::on_displayCategoriesBtn_toggled(bool checked)
+{
+ setCategoryListVisible(checked);
+}
+
+void MainWindow::editCategories()
+{
+ CategoriesDialog dialog(this);
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.commitChanges();
+ }
+}
+
+void MainWindow::on_categoriesList_customContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ menu.addAction(tr("Edit Categories..."), this, SLOT(editCategories()));
+
+ menu.exec(ui->categoriesList->mapToGlobal(pos));
+}
+
+
+void MainWindow::lockESPIndex()
+{
+ m_PluginList.lockESPIndex(m_ContextRow, true);
+}
+
+void MainWindow::unlockESPIndex()
+{
+ m_PluginList.lockESPIndex(m_ContextRow, false);
+}
+
+
+void MainWindow::on_espList_customContextMenuRequested(const QPoint &pos)
+{
+ m_ContextRow = m_PluginListSortProxy->mapToSource(ui->espList->indexAt(pos)).row();
+
+ QMenu menu;
+ menu.addAction(tr("Enable all"), &m_PluginList, SLOT(enableAll()));
+ menu.addAction(tr("Disable all"), &m_PluginList, SLOT(disableAll()));
+
+ if ((m_ContextRow != -1) && m_PluginList.isEnabled(m_ContextRow)) {
+ if (m_PluginList.isESPLocked(m_ContextRow)) {
+ menu.addAction(tr("Unlock index"), this, SLOT(unlockESPIndex()));
+ } else {
+ menu.addAction(tr("Lock index"), this, SLOT(lockESPIndex()));
+ }
+ }
+
+ try {
+ menu.exec(ui->espList->mapToGlobal(pos));
+ } catch (const std::exception &e) {
+ reportError(tr("Exception: ").arg(e.what()));
+ } catch (...) {
+ reportError(tr("Unknown exception"));
+ }
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 00000000..7aaa5dc3 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,423 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QFileInfo>
+#include <QDir>
+#include <QTreeWidget>
+#include <QListWidgetItem>
+#include <QProcess>
+#include <QThread>
+#include <QProgressBar>
+#include <QTranslator>
+#include <directoryentry.h>
+#include "executableslist.h"
+#include "modlist.h"
+#include "pluginlist.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <archive.h>
+#include "directoryrefresher.h"
+#include <imoinfo.h>
+#include <iplugintool.h>
+#include <iplugindiagnose.h>
+#include "settings.h"
+#include "nexusdialog.h"
+#include "downloadmanager.h"
+#include "installationmanager.h"
+#include "selfupdater.h"
+#include "savegamegamebyro.h"
+#include "modlistsortproxy.h"
+#include "pluginlistsortproxy.h"
+#include "tutorialcontrol.h"
+#include "savegameinfowidgetgamebryo.h"
+
+namespace Ui {
+ class MainWindow;
+}
+
+class QToolButton;
+
+class MainWindow : public QMainWindow, public IOrganizer
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent = 0);
+ ~MainWindow();
+
+ void readSettings();
+
+ bool addProfile();
+ void refreshLists();
+ void refreshESPList();
+ void refreshBSAList();
+ void refreshDataTree();
+ void refreshSaveList();
+ void refreshModList();
+
+ void setExecutablesList(const ExecutablesList &executablesList);
+
+ void setModListSorting(int index);
+ void setESPListSorting(int index);
+ void setCompactDownloads(bool compact);
+
+ bool setCurrentProfile(int index);
+ bool setCurrentProfile(const QString &name);
+
+ void createFirstProfile();
+
+ void spawnProgram(const QString &fileName, const QString &argumentsArg,
+ const QString &profileName, const QDir ¤tDirectory);
+
+ void loadPlugins();
+
+ virtual IGameInfo &gameInfo() const;
+ virtual QString profileName() const;
+ virtual QString profilePath() const;
+ virtual VersionInfo appVersion() const;
+ virtual IModInterface *getMod(const QString &name);
+ virtual IModInterface *createMod(const QString &name);
+ virtual bool removeMod(IModInterface *mod);
+ virtual void modDataChanged(IModInterface *mod);
+ virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const;
+
+ void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
+
+public slots:
+
+ void displayColumnSelection(const QPoint &pos);
+
+ void externalMessage(const QString &message);
+ void modorder_changed();
+ void esplist_changed();
+ void refresher_progress(int percent);
+ void directory_refreshed();
+
+ void toolPluginInvoke();
+
+signals:
+
+ /**
+ * @brief emitted after a mod has been installed
+ * @node this is currently only used for tutorials
+ */
+ void modInstalled();
+
+ /**
+ * @brief emitted after the information dialog has been closed
+ */
+ void modInfoDisplayed();
+
+ /**
+ * @brief emitted when the selected style changes
+ */
+ void styleChanged(const QString &styleFile);
+
+protected:
+
+ virtual void showEvent(QShowEvent *event);
+ virtual void closeEvent(QCloseEvent *event);
+ virtual bool eventFilter(QObject *obj, QEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
+
+private:
+
+ void actionToToolButton(QAction *&sourceAction);
+ bool verifyPlugin(IPlugin *plugin);
+ void registerPluginTool(IPluginTool *tool);
+ bool registerPlugin(QObject *pluginObj);
+
+ void updateToolBar();
+ void activateSelectedProfile();
+
+ void setBrowserGeometry(const QByteArray &geometry);
+ void setExecutableIndex(int index);
+
+ bool nexusLogin();
+
+ void saveCurrentESPList();
+
+ bool testForSteam();
+ void startSteam();
+
+ HANDLE spawnBinaryDirect(const QFileInfo &binary, const QString &arguments, const QString &profileName, const QDir ¤tDirectory, const QString &steamAppID);
+ void spawnBinary(const QFileInfo &binary, const QString &arguments = "", const QDir ¤tDirectory = QDir(), bool closeAfterStart = true, const QString &steamAppID = "");
+
+ void updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const DirectoryEntry &directoryEntry, bool conflictsOnly);
+ void refreshDirectoryStructure();
+ bool refreshProfiles(bool selectProfile = true);
+ void refreshExecutablesList();
+ void installMod(const QString &fileName);
+ void installMod();
+ bool modifyExecutablesDialog();
+ void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab);
+ void displayModInformation(int row, int tab = 0);
+ void testExtractBSA(int modIndex);
+
+ void writeDataToFile(QFile &file, const QString &directory, const DirectoryEntry &directoryEntry);
+
+ void renameModInList(QFile &modList, const QString &oldName, const QString &newName);
+
+ void refreshFilters();
+
+ void saveCategoriesFromMenu(QMenu *menu, int modRow);
+
+ bool addCategories(QMenu *menu, int targetID);
+
+ void updateDownloadListDelegate();
+
+ // remove invalid category-references from mods
+ void fixCategories();
+
+ void storeSettings();
+
+ bool queryLogin(QString &username, QString &password);
+
+ void createHelpWidget();
+
+ bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName);
+
+ void checkBSAList();
+
+ bool checkForProblems(QString &problemDescription);
+
+ int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments);
+ void addFilterItem(const QString &name, int categoryID);
+
+ void setCategoryListVisible(bool visible);
+
+ void updateProblemsButton();
+
+ SaveGameGamebryo *getSaveGame(const QString &name);
+ SaveGameGamebryo *getSaveGame(QListWidgetItem *item);
+
+ void displaySaveGameInfo(const SaveGameGamebryo *save, QPoint pos);
+
+ HANDLE nextChildProcess();
+
+ bool errorReported(QString &logFile);
+
+private:
+
+ Ui::MainWindow *ui;
+
+ TutorialControl m_Tutorial;
+
+ QString m_ExeName;
+
+ int m_OldProfileIndex;
+
+ QThread m_RefresherThread;
+ DirectoryRefresher m_DirectoryRefresher;
+ DirectoryEntry *m_DirectoryStructure;
+ std::vector<QString> m_ModNameList; // the mod-list to go with the directory structure
+ QProgressBar *m_RefreshProgress;
+ bool m_Refreshing;
+
+ ModList m_ModList;
+ ModListSortProxy *m_ModListSortProxy;
+ PluginList m_PluginList;
+ PluginListSortProxy *m_PluginListSortProxy;
+
+ ExecutablesList m_ExecutablesList;
+ int m_OldExecutableIndex;
+
+ QString m_GamePath;
+
+ int m_ContextRow;
+ QTreeWidgetItem *m_ContextItem;
+ int m_SelectedSaveGame;
+
+ Settings m_Settings;
+
+ NexusDialog m_NexusDialog;
+ DownloadManager m_DownloadManager;
+ InstallationManager m_InstallationManager;
+
+ QTranslator *m_Translator;
+ QTranslator *m_TranslatorQt;
+
+ SelfUpdater m_Updater;
+
+ CategoryFactory &m_CategoryFactory;
+
+ Profile *m_CurrentProfile;
+
+ int m_ModsToUpdate;
+
+ QStringList m_PendingDownloads;
+ QList<boost::function<void (MainWindow*)> > m_PostLoginTasks;
+ bool m_AskForNexusPW;
+ bool m_LoginAttempted;
+
+ QStringList m_DefaultArchives;
+ QStringList m_ActiveArchives;
+ bool m_DirectoryUpdate;
+ bool m_ArchivesInit;
+
+ QTime m_StartTime;
+ SaveGameInfoWidget *m_CurrentSaveView;
+
+ IGameInfo *m_GameInfo;
+
+ std::vector<IPluginDiagnose*> m_DiagnosisPlugins;
+
+private slots:
+
+ void showMessage(const QString &message);
+ void showError(const QString &message);
+
+ // main window actions
+ void helpTriggered();
+ void issueTriggered();
+ void wikiTriggered();
+ void tutorialTriggered();
+ void extractBSATriggered();
+
+ // modlist context menu
+ void installMod_clicked();
+ void restoreBackup_clicked();
+ void renameMod_clicked();
+ void removeMod_clicked();
+ void reinstallMod_clicked();
+ void endorse_clicked();
+ void unendorse_clicked();
+ void visitOnNexus_clicked();
+ void openExplorer_clicked();
+ void information_clicked();
+ // savegame context menu
+ void fixMods_clicked();
+ // data-tree context menu
+ void writeDataToFile();
+ void openDataFile();
+ void addAsExecutable();
+ void hideFile();
+ void unhideFile();
+
+ void linkDesktop();
+ void linkMenu();
+
+ void languageChange(const QString &newLanguage);
+ void modStatusChanged(unsigned int index);
+ void saveSelectionChanged(QListWidgetItem *newItem);
+
+ bool saveCurrentLists();
+
+ void windowTutorialFinished(const QString &windowName);
+
+ BSA::EErrorCode extractBSA(BSA::Archive &archive, BSA::Folder::Ptr folder, const QString &destination, QProgressDialog &extractProgress);
+
+ void syncOverwrite();
+
+ void removeOrigin(const QString &name);
+
+ void setPriorityMax();
+ void setPriorityManually();
+ void setPriorityMin();
+
+ void procError(QProcess::ProcessError error);
+ void procFinished(int exitCode, QProcess::ExitStatus exitStatus);
+
+ // nexus related
+ void checkModsForUpdates();
+ void nexusLinkActivated(const QString &link);
+
+ void loginSuccessful(bool necessary);
+ void loginSuccessfulUpdate(bool necessary);
+ void loginFailed(const QString &message);
+ void loginFailedUpdate(const QString &message);
+
+ void downloadRequestedNXM(const QString &url);
+ void downloadRequested(QNetworkReply *reply, int modID, const QString &fileName);
+
+ void installDownload(int index);
+ void updateAvailable();
+
+ void motdReceived(const QString &motd);
+ void notEndorsedYet();
+
+ void originModified(int originID);
+
+ void saveCategories();
+ void savePrimaryCategory();
+ void addPrimaryCategoryCandidates();
+
+ void modDetailsUpdated(bool success);
+
+ void nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int requestID);
+ void nxmEndorsementToggled(int, QVariant, QVariant resultData, int);
+ void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorString);
+
+ void editCategories();
+
+ void displayModInformation(const QString &modName, int tab);
+
+ void modRenamed(const QString &oldName, const QString &newName);
+
+ void hideSaveGameInfo();
+
+ void hookUpWindowTutorials();
+
+ void endorseMod(ModInfo::Ptr mod);
+ void cancelModListEditor();
+
+ void lockESPIndex();
+ void unlockESPIndex();
+
+ void enableVisibleMods();
+ void disableVisibleMods();
+
+private slots: // ui slots
+ // actions
+ void on_actionAdd_Profile_triggered();
+ void on_actionInstallMod_triggered();
+ void on_actionModify_Executables_triggered();
+ void on_actionNexus_triggered();
+ void on_actionProblems_triggered();
+ void on_actionSettings_triggered();
+ void on_actionUpdate_triggered();
+ void on_actionEndorseMO_triggered();
+
+ void on_bsaList_customContextMenuRequested(const QPoint &pos);
+ void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
+ void on_btnRefreshData_clicked();
+ void on_btnSave_clicked();
+ void on_categoriesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void on_categoriesList_customContextMenuRequested(const QPoint &pos);
+ void on_compactBox_toggled(bool checked);
+ void on_conflictsCheckBox_toggled(bool checked);
+ void on_dataTree_customContextMenuRequested(const QPoint &pos);
+ void on_executablesListBox_currentIndexChanged(int index);
+ void on_modList_customContextMenuRequested(const QPoint &pos);
+ void on_modList_doubleClicked(const QModelIndex &index);
+ void on_profileBox_currentIndexChanged(int index);
+ void on_profileRefreshBtn_clicked();
+ void on_savegameList_customContextMenuRequested(const QPoint &pos);
+ void on_startButton_clicked();
+ void on_tabWidget_currentChanged(int index);
+
+ void on_espList_customContextMenuRequested(const QPoint &pos);
+ void on_displayCategoriesBtn_toggled(bool checked);
+};
+
+#endif // MAINWINDOW_H
diff --git a/src/mainwindow.ui b/src/mainwindow.ui new file mode 100644 index 00000000..c6742dfd --- /dev/null +++ b/src/mainwindow.ui @@ -0,0 +1,1209 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>868</width>
+ <height>701</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Mod Organizer</string>
+ </property>
+ <property name="windowIcon">
+ <iconset>
+ <normaloff>mo_icon.ico</normaloff>mo_icon.ico</iconset>
+ </property>
+ <property name="documentMode">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_8" stretch="0,1">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <widget class="QGroupBox" name="categoriesGroup">
+ <property name="title">
+ <string>Categories</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_10">
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>7</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="categoriesList">
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>161</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QWidget" name="layoutWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Profile</string>
+ </property>
+ <property name="buddy">
+ <cstring>profileBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="profileBox">
+ <property name="toolTip">
+ <string>Pick a module collection</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="profileRefreshBtn">
+ <property name="maximumSize">
+ <size>
+ <width>24</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Refresh list</string>
+ </property>
+ <property name="whatsThis">
+ <string>Refresh list. This is usually not necessary unless you modified data outside the program.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/view-refresh.png</normaloff>:/MO/gui/resources/view-refresh.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Installed Mods</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_11">
+ <property name="margin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QTreeView" name="modList">
+ <property name="minimumSize">
+ <size>
+ <width>330</width>
+ <height>400</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>64</red>
+ <green>64</green>
+ <blue>64</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Link">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="LinkVisited">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>170</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>64</red>
+ <green>64</green>
+ <blue>64</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Link">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="LinkVisited">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>170</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Link">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="LinkVisited">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>170</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>List of available mods.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</string>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>true</bool>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>10</number>
+ </attribute>
+ <attribute name="headerShowSortIndicator" stdset="0">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="headerStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,0,1,1">
+ <item>
+ <widget class="QPushButton" name="displayCategoriesBtn">
+ <property name="maximumSize">
+ <size>
+ <width>20</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true">x</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="currentCategoryLabel">
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="LineEditClear" name="modFilterEdit">
+ <property name="placeholderText">
+ <string>Name filter</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget_2">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="startGroup">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Start</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
+ <item>
+ <widget class="QComboBox" name="executablesListBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>40</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>9</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Pick a program to run.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="frame">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_12" stretch="0,0">
+ <item>
+ <widget class="QPushButton" name="startButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Run program</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></string>
+ </property>
+ <property name="locale">
+ <locale language="English" country="UnitedStates"/>
+ </property>
+ <property name="text">
+ <string>Run</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/run</normaloff>:/MO/gui/run</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>36</width>
+ <height>36</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="linkButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Create a shortcut in your start menu or on the desktop to the specified program</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></string>
+ </property>
+ <property name="text">
+ <string>Shortcut</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/link</normaloff>:/MO/gui/link</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="minimumSize">
+ <size>
+ <width>340</width>
+ <height>250</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="tabShape">
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="espTab">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <attribute name="title">
+ <string notr="true">ESPs</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="btnSave">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>save esp list and load order.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></string>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/document-save.png</normaloff>:/MO/gui/resources/document-save.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="espList">
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>250</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>64</red>
+ <green>64</green>
+ <blue>64</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>64</red>
+ <green>64</green>
+ <blue>64</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>List of available esp/esm files</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></string>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="bsaTab">
+ <attribute name="title">
+ <string notr="true">BSAs</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="bsaList">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</string>
+ </property>
+ <property name="whatsThis">
+ <string>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded.
+By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored!
+
+BSAs checked here are loaded in such a way that your installation order is obeyed properly.</string>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::IgnoreAction</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Mod</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="dataTab">
+ <attribute name="title">
+ <string>Data</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="btnRefreshData">
+ <property name="toolTip">
+ <string>refresh data-directory overview</string>
+ </property>
+ <property name="whatsThis">
+ <string>Refresh the overview. This may take a moment.</string>
+ </property>
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/view-refresh.png</normaloff>:/MO/gui/resources/view-refresh.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QTreeWidget" name="dataTree">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="whatsThis">
+ <string>This is an overview of your data directory as visible to the game (and tools). </string>
+ </property>
+ <property name="animated">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Mod</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="conflictsCheckBox">
+ <property name="toolTip">
+ <string>Filter the above list so that only conflicts are displayed.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Filter the above list so that only conflicts are displayed.</string>
+ </property>
+ <property name="text">
+ <string>Show only conflicts</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="savesTab">
+ <attribute name="title">
+ <string>Saves</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="savegameList">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string notr="true"/>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="downloadTab">
+ <attribute name="title">
+ <string>Downloads</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="downloadLayout">
+ <item>
+ <widget class="LineEditClear" name="downloadFilterEdit">
+ <property name="placeholderText">
+ <string>Filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="downloadView">
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::PreventContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="whatsThis">
+ <string>This is a list of mods you downloaded from Nexus. Double click one to install it.</string>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOn</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="verticalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>100</number>
+ </attribute>
+ <attribute name="headerStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1">
+ <item>
+ <widget class="QCheckBox" name="compactBox">
+ <property name="text">
+ <string>Compact</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QToolBar" name="toolBar">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::PreventContextMenu</enum>
+ </property>
+ <property name="windowTitle">
+ <string>Tool Bar</string>
+ </property>
+ <property name="movable">
+ <bool>false</bool>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>42</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonIconOnly</enum>
+ </property>
+ <property name="floatable">
+ <bool>false</bool>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionInstallMod"/>
+ <addaction name="actionNexus"/>
+ <addaction name="actionAdd_Profile"/>
+ <addaction name="actionModify_Executables"/>
+ <addaction name="actionTool"/>
+ <addaction name="actionSettings"/>
+ <addaction name="separator"/>
+ <addaction name="actionEndorseMO"/>
+ <addaction name="actionProblems"/>
+ <addaction name="actionUpdate"/>
+ <addaction name="actionHelp"/>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="actionInstallMod">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/system-installer.png</normaloff>:/MO/gui/resources/system-installer.png</iconset>
+ </property>
+ <property name="text">
+ <string>Install Mod</string>
+ </property>
+ <property name="iconText">
+ <string>Install &Mod</string>
+ </property>
+ <property name="toolTip">
+ <string>Install a new mod from an archive</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+M</string>
+ </property>
+ </action>
+ <action name="actionAdd_Profile">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/profiles</normaloff>:/MO/gui/profiles</iconset>
+ </property>
+ <property name="text">
+ <string>Profiles</string>
+ </property>
+ <property name="iconText">
+ <string>&Profiles</string>
+ </property>
+ <property name="toolTip">
+ <string>Configure Profiles</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+P</string>
+ </property>
+ </action>
+ <action name="actionModify_Executables">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/icon_executable</normaloff>:/MO/gui/icon_executable</iconset>
+ </property>
+ <property name="text">
+ <string>Executables</string>
+ </property>
+ <property name="iconText">
+ <string>&Executables</string>
+ </property>
+ <property name="toolTip">
+ <string>Configure the executables that can be started through Mod Organizer</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+E</string>
+ </property>
+ </action>
+ <action name="actionTool">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/plugins</normaloff>:/MO/gui/plugins</iconset>
+ </property>
+ <property name="text">
+ <string>Tools</string>
+ </property>
+ <property name="iconText">
+ <string>&Tools</string>
+ </property>
+ <property name="toolTip">
+ <string>Tools</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+I</string>
+ </property>
+ </action>
+ <action name="actionSettings">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/settings</normaloff>:/MO/gui/settings</iconset>
+ </property>
+ <property name="text">
+ <string>Settings</string>
+ </property>
+ <property name="iconText">
+ <string>&Settings</string>
+ </property>
+ <property name="toolTip">
+ <string>Configure settings and workarounds</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="actionNexus">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/internet-web-browser.png</normaloff>:/MO/gui/resources/internet-web-browser.png</iconset>
+ </property>
+ <property name="text">
+ <string>Nexus</string>
+ </property>
+ <property name="toolTip">
+ <string>Search nexus network for more mods</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionUpdate">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/update</normaloff>:/MO/gui/update</iconset>
+ </property>
+ <property name="text">
+ <string>Update</string>
+ </property>
+ <property name="toolTip">
+ <string>Mod Organizer is up-to-date</string>
+ </property>
+ </action>
+ <action name="actionProblems">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/dialog-warning.png</normaloff>:/MO/gui/resources/dialog-warning.png</iconset>
+ </property>
+ <property name="text">
+ <string>No Problems</string>
+ </property>
+ <property name="whatsThis">
+ <string>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them.
+
+!Work in progress!
+Right now this has very limited functionality</string>
+ </property>
+ </action>
+ <action name="actionHelp">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/help</normaloff>:/MO/gui/help</iconset>
+ </property>
+ <property name="text">
+ <string>Help</string>
+ </property>
+ <property name="toolTip">
+ <string>Help</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+H</string>
+ </property>
+ </action>
+ <action name="actionEndorseMO">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/icon_favorite</normaloff>:/MO/gui/icon_favorite</iconset>
+ </property>
+ <property name="text">
+ <string>Endorse MO</string>
+ </property>
+ <property name="toolTip">
+ <string>Endorse Mod Organizer</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+ <customwidget>
+ <class>LineEditClear</class>
+ <extends>QLineEdit</extends>
+ <header>lineeditclear.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/messagedialog.cpp b/src/messagedialog.cpp new file mode 100644 index 00000000..af89ee8d --- /dev/null +++ b/src/messagedialog.cpp @@ -0,0 +1,70 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "messagedialog.h"
+#include "ui_messagedialog.h"
+#include <QTimer>
+#include <QResizeEvent>
+#include <Windows.h>
+
+MessageDialog::MessageDialog(const QString &text, QWidget *reference) :
+ QDialog(reference),
+ ui(new Ui::MessageDialog)
+{
+ ui->setupUi(this);
+ findChild<QLabel*>("message")->setText(text);
+ this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
+ this->setFocusPolicy(Qt::NoFocus);
+ this->setAttribute(Qt::WA_ShowWithoutActivating);
+ QTimer::singleShot(1000 + (text.length() * 40), this, SLOT(hide()));
+ if (reference != NULL) {
+ QPoint position = reference->mapToGlobal(QPoint(reference->width() / 2, reference->height()));
+ position.rx() -= this->width() / 2;
+ position.ry() -= this->height() + 5;
+ move(position);
+ }
+}
+
+
+MessageDialog::~MessageDialog()
+{
+ delete ui;
+}
+
+
+void MessageDialog::resizeEvent(QResizeEvent *event)
+{
+ QWidget *par = parentWidget();
+ if (par != NULL) {
+ QPoint position = par->mapToGlobal(QPoint(par->width() / 2, par->height()));
+ position.rx() -= event->size().width() / 2;
+ position.ry() -= event->size().height() + 5;
+ move(position);
+ }
+}
+
+
+void MessageDialog::showMessage(const QString &text, QWidget *reference)
+{
+ if (reference != NULL) {
+ MessageDialog *dialog = new MessageDialog(text, reference);
+ dialog->show();
+ reference->activateWindow();
+ }
+}
diff --git a/src/messagedialog.h b/src/messagedialog.h new file mode 100644 index 00000000..846448d6 --- /dev/null +++ b/src/messagedialog.h @@ -0,0 +1,66 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MESSAGEDIALOG_H
+#define MESSAGEDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class MessageDialog;
+}
+
+/**
+ * borderless dialog used to display short messages that will automatically
+ * vanish after a moment
+ **/
+class MessageDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief constructor
+ *
+ * @param text the message to display
+ * @param reference parent widget. This will also be used to position the message at the bottom center of the dialog
+ **/
+
+ explicit MessageDialog(const QString &text, QWidget *reference);
+
+ ~MessageDialog();
+
+ /**
+ * factory function for message dialogs. This can be used as a fire-and-forget. The message
+ * will automatically positioned to the reference dialog and get a reasonable view time
+ *
+ * @param text the text to display. The length of this text is used to determine how long the dialog is to be shown
+ * @param reference the reference widget on top of which the message should be displayed
+ **/
+ static void showMessage(const QString &text, QWidget *reference);
+
+protected:
+
+ virtual void resizeEvent(QResizeEvent *event);
+
+private:
+ Ui::MessageDialog *ui;
+};
+
+#endif // MESSAGEDIALOG_H
diff --git a/src/messagedialog.ui b/src/messagedialog.ui new file mode 100644 index 00000000..9e0f145e --- /dev/null +++ b/src/messagedialog.ui @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MessageDialog</class>
+ <widget class="QDialog" name="MessageDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>106</width>
+ <height>35</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>220</red>
+ <green>220</green>
+ <blue>220</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>221</red>
+ <green>221</green>
+ <blue>221</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>67</red>
+ <green>67</green>
+ <blue>67</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>220</red>
+ <green>220</green>
+ <blue>220</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>221</red>
+ <green>221</green>
+ <blue>221</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>67</red>
+ <green>67</green>
+ <blue>67</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>67</red>
+ <green>67</green>
+ <blue>67</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>67</red>
+ <green>67</green>
+ <blue>67</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="windowTitle">
+ <string>Placeholder</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="message">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>300</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="text">
+ <string>Placeholder</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/mo_icon.ico b/src/mo_icon.ico Binary files differnew file mode 100644 index 00000000..b1105bb2 --- /dev/null +++ b/src/mo_icon.ico diff --git a/src/mo_icon.psd b/src/mo_icon.psd Binary files differnew file mode 100644 index 00000000..1f7b40c9 --- /dev/null +++ b/src/mo_icon.psd diff --git a/src/moapplication.cpp b/src/moapplication.cpp new file mode 100644 index 00000000..aaae77c0 --- /dev/null +++ b/src/moapplication.cpp @@ -0,0 +1,80 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "moapplication.h"
+#include "report.h"
+#include "utility.h"
+#include <appconfig.h>
+#include <QFile>
+#include <QStringList>
+
+
+MOApplication::MOApplication(int argc, char **argv)
+ : QApplication(argc, argv)
+{
+ connect(&m_StyleWatcher, SIGNAL(fileChanged(QString)), SLOT(updateStyle(QString)));
+}
+
+
+void MOApplication::setStyleFile(const QString &styleName)
+{
+ // remove all files from watch
+ QStringList currentWatch = m_StyleWatcher.files();
+ if (currentWatch.count() != 0) {
+ m_StyleWatcher.removePaths(currentWatch);
+ }
+ // set new stylesheet or clear it
+ if (styleName.length() != 0) {
+ QString styleSheetName = applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()) + "/" + styleName;
+ m_StyleWatcher.addPath(styleSheetName);
+ updateStyle(styleSheetName);
+ } else {
+ setStyleSheet("");
+ }
+}
+
+
+bool MOApplication::notify(QObject *receiver, QEvent *event)
+{
+ try {
+ return QApplication::notify(receiver, event);
+ } catch (const std::exception &e) {
+ qCritical("uncaught exception in handler (object %s, eventtype %d): %s",
+ receiver->objectName().toUtf8().constData(), event->type(), e.what());
+ reportError(tr("an error occured: %1").arg(e.what()));
+ return false;
+ } catch (...) {
+ qCritical("uncaught non-std exception in handler (object %s, eventtype %d)",
+ receiver->objectName().toUtf8().constData(), event->type());
+ reportError(tr("an error occured"));
+ return false;
+ }
+}
+
+
+void MOApplication::updateStyle(const QString &fileName)
+{
+ QFile file(fileName);
+ if (file.open(QFile::ReadOnly)) {
+ setStyleSheet(file.readAll());
+ } else {
+ qDebug("no stylesheet");
+ }
+ file.close();
+}
diff --git a/src/moapplication.h b/src/moapplication.h new file mode 100644 index 00000000..3d74031d --- /dev/null +++ b/src/moapplication.h @@ -0,0 +1,49 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MOAPPLICATION_H
+#define MOAPPLICATION_H
+
+#include <QApplication>
+#include <QFileSystemWatcher>
+
+
+class MOApplication : public QApplication {
+Q_OBJECT
+public:
+
+ MOApplication(int argc, char **argv);
+
+ virtual bool notify (QObject *receiver, QEvent *event);
+
+public slots:
+
+ void setStyleFile(const QString &style);
+
+private slots:
+
+ void updateStyle(const QString &fileName);
+
+private:
+
+ QFileSystemWatcher m_StyleWatcher;
+};
+
+
+#endif // MOAPPLICATION_H
diff --git a/src/modinfo.cpp b/src/modinfo.cpp new file mode 100644 index 00000000..a46774c2 --- /dev/null +++ b/src/modinfo.cpp @@ -0,0 +1,844 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "modinfo.h"
+#include "utility.h"
+#include "installationtester.h"
+#include "categories.h"
+#include "report.h"
+#include "modinfodialog.h"
+#include "overwriteinfodialog.h"
+#include "json.h"
+#include "messagedialog.h"
+
+#include <gameinfo.h>
+#include <versioninfo.h>
+
+#include <QApplication>
+
+#include <QDirIterator>
+#include <QMutexLocker>
+#include <QSettings>
+#include <sstream>
+
+
+std::vector<ModInfo::Ptr> ModInfo::s_Collection;
+std::map<QString, unsigned int> ModInfo::s_ModsByName;
+std::map<int, unsigned int> ModInfo::s_ModsByModID;
+int ModInfo::s_NextID;
+QMutex ModInfo::s_Mutex(QMutex::Recursive);
+
+QString ModInfo::s_HiddenExt(".mohidden");
+
+
+static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS)
+{
+ return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0;
+}
+
+ModInfo::NexusFileInfo::NexusFileInfo(const QString &data)
+{
+ QVariantList result = QtJson::Json::parse(data).toList();
+
+ while (result.length() < 7) {
+ result.append(QVariant());
+ }
+ id = result.at(0).toInt();
+ name = result.at(1).toString();
+ url = result.at(2).toString();
+ version = result.at(3).toString();
+ description = result.at(4).toString();
+ category = result.at(5).toInt();
+ size = result.at(6).toInt();
+}
+
+
+QString ModInfo::NexusFileInfo::toString() const
+{
+ return QString("[ %1,\"%2\",\"%3\",\"%4\",\"%5\",%6,%7 ]")
+ .arg(id)
+ .arg(name)
+ .arg(url)
+ .arg(version)
+ .arg(description.mid(0).replace("\"", "'"))
+ .arg(category)
+ .arg(size);
+}
+
+
+ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStructure)
+{
+ QMutexLocker locker(&s_Mutex);
+// int id = s_NextID++;
+ static QRegExp backupExp(".*backup[0-9]*");
+ ModInfo::Ptr result;
+ if (backupExp.exactMatch(dir.dirName())) {
+ result = ModInfo::Ptr(new ModInfoBackup(dir, directoryStructure));
+ } else {
+ result = ModInfo::Ptr(new ModInfoRegular(dir, directoryStructure));
+ }
+ s_Collection.push_back(result);
+ return result;
+}
+
+
+void ModInfo::createFromOverwrite()
+{
+ QMutexLocker locker(&s_Mutex);
+
+ s_Collection.push_back(ModInfo::Ptr(new ModInfoOverwrite));
+}
+
+
+unsigned int ModInfo::getNumMods()
+{
+ QMutexLocker locker(&s_Mutex);
+ return s_Collection.size();
+}
+
+
+ModInfo::Ptr ModInfo::getByIndex(unsigned int index)
+{
+ QMutexLocker locker(&s_Mutex);
+
+ if (index >= s_Collection.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+ return s_Collection[index];
+}
+
+
+ModInfo::Ptr ModInfo::getByModID(int modID, bool missingAcceptable)
+{
+ QMutexLocker locker(&s_Mutex);
+
+ std::map<int, unsigned int>::iterator iter = s_ModsByModID.find(modID);
+ if (iter == s_ModsByModID.end()) {
+ if (missingAcceptable) {
+ return ModInfo::Ptr();
+ } else {
+ throw MyException(tr("invalid mod id %1").arg(modID));
+ }
+ }
+
+ return getByIndex(iter->second);
+}
+
+
+bool ModInfo::removeMod(unsigned int index)
+{
+ QMutexLocker locker(&s_Mutex);
+
+ if (index >= s_Collection.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+
+ // update the indices first
+ ModInfo::Ptr modInfo = s_Collection[index];
+ s_ModsByName.erase(s_ModsByName.find(modInfo->name()));
+
+ //TODO this is a bit more complicated since multiple mods may have the
+ // same mod id but only one appears in the index
+ std::map<int, unsigned int>::iterator iter = s_ModsByModID.find(modInfo->getNexusID()) ;
+ if ((iter != s_ModsByModID.end()) &&
+ (iter->second == index)) {
+ s_ModsByModID.erase(iter);
+ }
+
+ // physically remove the mod directory
+ //TODO the return value is ignored because the indices were already removed here, so stopping
+ // would cause data inconsistencies. Instead we go through with the removal but the mod will show up
+ // again if the user refreshes
+ modInfo->remove();
+
+ // finally, remove the mod from the collection
+ s_Collection.erase(s_Collection.begin() + index);
+
+ // and update the indices
+ updateIndices();
+ return true;
+}
+
+
+unsigned int ModInfo::getIndex(const QString &name)
+{
+ QMutexLocker locker(&s_Mutex);
+
+ std::map<QString, unsigned int>::iterator iter = s_ModsByName.find(name);
+ if (iter == s_ModsByName.end()) {
+ return UINT_MAX;
+ }
+
+ return iter->second;
+}
+
+unsigned int ModInfo::findMod(const boost::function<bool (ModInfo::Ptr)> &filter)
+{
+ for (unsigned int i = 0U; i < s_Collection.size(); ++i) {
+ if (filter(s_Collection[i])) {
+ return i;
+ }
+ }
+ return UINT_MAX;
+}
+
+
+void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure)
+{
+ QMutexLocker lock(&s_Mutex);
+ s_Collection.clear();
+ s_NextID = 0;
+ // list all directories in the mod directory and make a mod out of each
+ QDir mods(QDir::fromNativeSeparators(modDirectory));
+ mods.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ QDirIterator modIter(mods);
+ while (modIter.hasNext()) {
+ createFrom(QDir(modIter.next()), directoryStructure);
+ }
+
+ createFromOverwrite();
+
+ std::sort(s_Collection.begin(), s_Collection.end(), ByName);
+
+ updateIndices();
+}
+
+
+void ModInfo::updateIndices()
+{
+ s_ModsByName.clear();
+ s_ModsByModID.clear();
+ QRegExp backupRegEx(".*backup[0-9]*$");
+
+ for (unsigned int i = 0; i < s_Collection.size(); ++i) {
+ QString modName = s_Collection[i]->name();
+ int modID = s_Collection[i]->getNexusID();
+ s_ModsByName[modName] = i;
+
+ // don't overwrite a modid-entry with a backup entry. This is a bit of a workaround
+ if ((s_ModsByModID.find(modID) == s_ModsByModID.end()) ||
+ !backupRegEx.exactMatch(modName)) {
+ s_ModsByModID[modID] = i;
+ }
+ }
+}
+
+
+ModInfo::ModInfo()
+ : m_Valid(false), m_PrimaryCategory(-1)
+{
+}
+
+
+void ModInfo::checkChunkForUpdate(const std::vector<int> &modIDs, QObject *receiver)
+{
+ if (modIDs.size() != 0) {
+ NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant());
+ }
+}
+
+
+int ModInfo::checkAllForUpdate(QObject *receiver)
+{
+ int result = 0;
+ std::vector<int> modIDs;
+
+ modIDs.push_back(GameInfo::instance().getNexusModID());
+
+ for (std::vector<ModInfo::Ptr>::iterator iter = s_Collection.begin();
+ iter != s_Collection.end(); ++iter) {
+ if ((*iter)->canBeUpdated()) {
+ modIDs.push_back((*iter)->getNexusID());
+ if (modIDs.size() >= 255) {
+ checkChunkForUpdate(modIDs, receiver);
+ modIDs.clear();
+ }
+ }
+ }
+
+ checkChunkForUpdate(modIDs, receiver);
+
+ return result;
+}
+
+void ModInfo::setVersion(const VersionInfo &version)
+{
+ m_Version = version;
+}
+
+
+bool ModInfo::categorySet(int categoryID) const
+{
+ for (std::set<int>::const_iterator iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) {
+ if ((*iter == categoryID) ||
+ (CategoryFactory::instance().isDecendantOf(*iter, categoryID))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void ModInfo::testValid()
+{
+ m_Valid = false;
+ QDirIterator dirIter(absolutePath());
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ if (dirIter.fileInfo().isDir()) {
+ if (InstallationTester::isTopLevelDirectory(dirIter.fileName())) {
+ m_Valid = true;
+ break;
+ }
+ } else {
+ if (InstallationTester::isTopLevelSuffix(dirIter.fileName())) {
+ m_Valid = true;
+ break;
+ }
+ }
+ }
+
+ // NOTE: in Qt 4.7 it seems that QDirIterator leaves a file handle open if it is not iterated to the
+ // end
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ }
+}
+
+
+ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure)
+ : ModInfo(), m_Name(path.dirName()), m_Path(path.absolutePath()), m_MetaInfoChanged(false),
+ m_EndorsedState(ENDORSED_UNKNOWN), m_DirectoryStructure(directoryStructure)
+{
+ testValid();
+
+ // read out the meta-file for information
+ QString metaFileName = path.absoluteFilePath("meta.ini");
+ QSettings metaFile(metaFileName, QSettings::IniFormat);
+
+ m_Notes = metaFile.value("notes", "").toString();
+ m_NexusID = metaFile.value("modid", -1).toInt();
+ m_Version.parse(metaFile.value("version", "").toString());
+ m_NewestVersion = metaFile.value("newestVersion", "").toString();
+ m_InstallationFile = metaFile.value("installationFile", "").toString();
+ m_NexusDescription = metaFile.value("nexusDescription", "").toString();
+ m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate);
+ if (metaFile.contains("endorsed")) {
+ m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ }
+
+ int numNexusFiles = metaFile.beginReadArray("nexusFiles");
+ for (int i = 0; i < numNexusFiles; ++i) {
+ metaFile.setArrayIndex(i);
+ QString infoString = metaFile.value("info", "").toString();
+ NexusFileInfo info(infoString);
+ m_NexusFileInfos.push_back(info);
+ }
+ metaFile.endArray();
+
+ QString categoriesString = metaFile.value("category", "").toString();
+
+ QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
+ for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
+ bool ok = false;
+ int categoryID = iter->toInt(&ok);
+ if (categoryID < 0) {
+ // ignore invalid id
+ continue;
+ }
+ if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) {
+ m_Categories.insert(categoryID);
+ if (iter == categories.begin()) {
+ m_PrimaryCategory = categoryID;
+ }
+ }
+ }
+
+ connect(&m_NexusBridge, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant)), this, SLOT(nxmFilesAvailable(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(nxmEndorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(nxmRequestFailed(int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,QVariant,QString)));
+}
+
+
+ModInfoRegular::~ModInfoRegular()
+{
+ try {
+ //TODO this may cause the meta-file and the directory to be
+ // re-created after a remove
+ saveMeta();
+ } catch (const std::exception &e) {
+ qCritical("failed to save meta information for \"%s\": %s",
+ m_Name.toUtf8().constData(), e.what());
+ }
+}
+
+
+void ModInfoRegular::saveMeta()
+{
+ if (m_MetaInfoChanged) {
+ if (QFile::exists(absolutePath().append("/meta.ini"))) {
+ QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat);
+ if (metaFile.status() == QSettings::NoError) {
+ std::set<int> temp = m_Categories;
+ temp.erase(m_PrimaryCategory);
+ metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ","));
+ metaFile.setValue("newestVersion", m_NewestVersion.canonicalString());
+ metaFile.setValue("version", m_Version.canonicalString());
+ metaFile.setValue("modid", m_NexusID);
+ metaFile.setValue("notes", m_Notes);
+ metaFile.setValue("nexusDescription", m_NexusDescription);
+ metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate));
+ if (m_EndorsedState != ENDORSED_UNKNOWN) {
+ metaFile.setValue("endorsed", m_EndorsedState == ENDORSED_TRUE ? true : false);
+ }
+
+ metaFile.beginWriteArray("nexusFiles");
+ for (int i = 0; i < m_NexusFileInfos.size(); ++i) {
+ metaFile.setArrayIndex(i);
+ metaFile.setValue("info", m_NexusFileInfos.at(i).toString());
+ }
+ metaFile.endArray();
+ } else {
+ reportError(tr("failed to write %1/meta.ini: %2").arg(absolutePath()).arg(metaFile.status()));
+ }
+ } else {
+ qWarning("mod %s has no meta.ini at %s/meta.ini", m_Name.toUtf8().constData(), absolutePath().toUtf8().constData());
+ }
+ m_MetaInfoChanged = false;
+ }
+}
+
+
+bool ModInfoRegular::updateAvailable() const
+{
+ return m_NewestVersion.isValid() && (m_Version < m_NewestVersion);
+}
+
+
+void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData)
+{
+ QVariantMap result = resultData.toMap();
+ m_NewestVersion.parse(result["version"].toString());
+ m_NexusDescription = result["description"].toString();
+ m_EndorsedState = result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ m_NexusBridge.requestFiles(m_NexusID, QVariant());
+}
+
+
+void ModInfoRegular::nxmFilesAvailable(int, QVariant, QVariant resultData)
+{
+ m_NexusFileInfos.clear();
+
+ QVariantList result = resultData.toList();
+
+ foreach(QVariant file, result) {
+ QVariantMap fileInfo = file.toMap();
+
+ m_NexusFileInfos.push_back(NexusFileInfo(fileInfo["id"].toInt(),
+ fileInfo["name"].toString(),
+ fileInfo["uri"].toString(),
+ fileInfo["version"].toString(),
+ fileInfo["description"].toString(),
+ fileInfo["category_id"].toInt(),
+ fileInfo["size"].toInt()));
+ }
+
+ m_LastNexusQuery = QDateTime::currentDateTime();
+ m_MetaInfoChanged = true;
+ saveMeta();
+ emit modDetailsUpdated(true);
+}
+
+
+void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData)
+{
+ m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ m_MetaInfoChanged = true;
+ saveMeta();
+ emit modDetailsUpdated(true);
+}
+
+
+void ModInfoRegular::nxmRequestFailed(int, QVariant userData, const QString &errorMessage)
+{
+ QString fullMessage = errorMessage;
+ if (userData.canConvert<int>() && (userData.toInt() == 1)) {
+ fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading.";
+ }
+ if (QApplication::activeWindow() != NULL) {
+ MessageDialog::showMessage(fullMessage, QApplication::activeWindow());
+ }
+ emit modDetailsUpdated(false);
+}
+
+
+bool ModInfoRegular::updateNXMInfo()
+{
+ if (m_NexusID > 0) {
+ m_NexusBridge.requestDescription(m_NexusID, QVariant());
+ return true;
+ }
+ return false;
+}
+
+
+void ModInfoRegular::setCategory(int categoryID, bool active)
+{
+ m_MetaInfoChanged = true;
+
+ if (active) {
+ m_Categories.insert(categoryID);
+ if (m_PrimaryCategory == -1) {
+ m_PrimaryCategory = categoryID;
+ }
+ } else {
+ std::set<int>::iterator iter = m_Categories.find(categoryID);
+ if (iter != m_Categories.end()) {
+ m_Categories.erase(iter);
+ }
+ if (categoryID == m_PrimaryCategory) {
+ if (m_Categories.size() == 0) {
+ m_PrimaryCategory = -1;
+ } else {
+ m_PrimaryCategory = *(m_Categories.begin());
+ }
+ }
+ }
+}
+
+
+bool ModInfoRegular::setName(const QString &name)
+{
+ if (name.contains('/') || name.contains('\\')) {
+ return false;
+ }
+
+ QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name);
+ QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length()));
+ if (m_Name.compare(name, Qt::CaseInsensitive) == 0) {
+ QString tempName = name;
+ tempName.append("_temp");
+ while (modDir.exists(tempName)) {
+ tempName.append("_");
+ }
+ if (!modDir.rename(m_Name, tempName)) {
+ return false;
+ }
+ if (!modDir.rename(tempName, name)) {
+ qCritical("rename to final name failed after successful rename to intermediate name");
+ modDir.rename(tempName, m_Name);
+ return false;
+ }
+ } else {
+ if (!modDir.rename(m_Name, name)) {
+ return false;
+ }
+ }
+
+ std::map<QString, unsigned int>::iterator nameIter = s_ModsByName.find(m_Name);
+ unsigned int index = nameIter->second;
+ s_ModsByName.erase(nameIter);
+
+ m_Name = name;
+ m_Path = newPath;
+
+ s_ModsByName[m_Name] = index;
+
+ std::sort(s_Collection.begin(), s_Collection.end(), ByName);
+
+ updateIndices();
+
+ return true;
+}
+
+void ModInfoRegular::setNotes(const QString ¬es)
+{
+ m_Notes = notes;
+}
+
+void ModInfoRegular::setVersion(const VersionInfo &version)
+{
+ m_Version = version;
+ m_MetaInfoChanged = true;
+}
+
+void ModInfoRegular::setNexusDescription(const QString &description)
+{
+ m_NexusDescription = description;
+ m_MetaInfoChanged = true;
+}
+
+
+void ModInfoRegular::setIsEndorsed(bool endorsed)
+{
+ m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE;
+ m_MetaInfoChanged = true;
+}
+
+
+bool ModInfoRegular::remove()
+{
+ m_MetaInfoChanged = false;
+ return removeDir(absolutePath());
+}
+
+void ModInfoRegular::endorse(bool doEndorse)
+{
+ if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) {
+ m_NexusBridge.requestToggleEndorsement(getNexusID(), doEndorse, QVariant(1));
+ }
+}
+
+
+QString ModInfoRegular::absolutePath() const
+{
+ return m_Path;
+}
+
+
+std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
+{
+ std::vector<ModInfo::EFlag> result;
+ if (!isValid()) {
+ result.push_back(ModInfo::FLAG_INVALID);
+ }
+ if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) {
+ result.push_back(ModInfo::FLAG_NOTENDORSED);
+ }
+ switch (isConflicted()) {
+ case CONFLICT_MIXED: {
+ result.push_back(ModInfo::FLAG_CONFLICT_MIXED);
+ } break;
+ case CONFLICT_OVERWRITE: {
+ result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE);
+ } break;
+ case CONFLICT_OVERWRITTEN: {
+ result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN);
+ } break;
+ case CONFLICT_REDUNDANT: {
+ result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT);
+ } break;
+ default: { /* NOP */ }
+ }
+ if (m_Notes.length() != 0) {
+ result.push_back(ModInfo::FLAG_NOTES);
+ }
+ return result;
+}
+
+
+int ModInfoRegular::getHighlight() const
+{
+ return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID;
+}
+
+
+QString ModInfoRegular::getDescription() const
+{
+ if (!isValid()) {
+ return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name());
+ } else {
+ const std::set<int> &categories = getCategories();
+ std::wostringstream categoryString;
+ categoryString << ToWString(tr("Categories: <br>"));
+ CategoryFactory &categoryFactory = CategoryFactory::instance();
+ for (std::set<int>::const_iterator catIter = categories.begin();
+ catIter != categories.end(); ++catIter) {
+ if (catIter != categories.begin()) {
+ categoryString << " , ";
+ }
+ categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>";
+ }
+
+ return ToQString(categoryString.str());
+ }
+}
+
+QString ModInfoRegular::notes() const
+{
+ return m_Notes;
+}
+
+void ModInfoRegular::getNexusFiles(QList<ModInfo::NexusFileInfo>::const_iterator &begin, QList<ModInfo::NexusFileInfo>::const_iterator &end)
+{
+ begin = m_NexusFileInfos.begin();
+ end = m_NexusFileInfos.end();
+}
+
+QString ModInfoRegular::getNexusDescription() const
+{
+ return m_NexusDescription;
+}
+
+
+ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const
+{
+ return m_EndorsedState;
+}
+
+
+ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const
+{
+ bool overwrite = false;
+ bool overwritten = false;
+ bool regular = false;
+
+ int dataID = 0;
+ if ((*m_DirectoryStructure)->originExists(L"data")) {
+ dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID();
+ }
+
+ std::wstring name = ToWString(m_Name);
+ if ((*m_DirectoryStructure)->originExists(name)) {
+ FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
+ std::vector<FileEntry*> files = origin.getFiles();
+ for (auto iter = files.begin(); iter != files.end() && (!overwrite || !overwritten || !regular); ++iter) {
+ const std::vector<int> &alternatives = (*iter)->getAlternatives();
+ if (alternatives.size() == 0) {
+ regular = true;
+ } else {
+ for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) {
+ // don't treat files overwritten in data as "conflict"+
+ if (*altIter != dataID) {
+ bool ignore = false;
+ if ((*iter)->getOrigin(ignore) == origin.getID()) {
+ overwrite = true;
+ break;
+ } else {
+ overwritten = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (overwrite && overwritten) return CONFLICT_MIXED;
+ else if (overwrite) return CONFLICT_OVERWRITE;
+ else if (overwritten) {
+ if (!regular) {
+ return CONFLICT_REDUNDANT;
+ } else {
+ return CONFLICT_OVERWRITTEN;
+ }
+ }
+ else return CONFLICT_NONE;
+}
+
+
+bool ModInfoRegular::isRedundant() const
+{
+ std::wstring name = ToWString(m_Name);
+ if ((*m_DirectoryStructure)->originExists(name)) {
+ FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
+ std::vector<FileEntry*> files = origin.getFiles();
+ bool ignore = false;
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ if ((*iter)->getOrigin(ignore) == origin.getID()) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+QDateTime ModInfoRegular::getLastNexusQuery() const
+{
+ return m_LastNexusQuery;
+}
+
+std::vector<QString> ModInfoRegular::getIniTweaks() const
+{
+ QString metaFileName = absolutePath().append("/meta.ini");
+ QSettings metaFile(metaFileName, QSettings::IniFormat);
+
+ std::vector<QString> result;
+
+ int numTweaks = metaFile.beginReadArray("INI Tweaks");
+
+ if (numTweaks != 0) {
+ qDebug("%d active ini tweaks in %s",
+ numTweaks, metaFileName.toUtf8().constData());
+ }
+
+ for (int i = 0; i < numTweaks; ++i) {
+ metaFile.setArrayIndex(i);
+ QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString());
+ result.push_back(filename);
+ }
+ metaFile.endArray();
+ return result;
+}
+
+std::vector<ModInfo::EFlag> ModInfoBackup::getFlags() const
+{
+ std::vector<ModInfo::EFlag> result = ModInfoRegular::getFlags();
+ result.insert(result.begin(), ModInfo::FLAG_BACKUP);
+ return result;
+}
+
+
+QString ModInfoBackup::getDescription() const
+{
+ return tr("This is the backup of a mod");
+}
+
+
+ModInfoBackup::ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructure)
+ : ModInfoRegular(path, directoryStructure)
+{
+}
+
+
+ModInfoOverwrite::ModInfoOverwrite()
+{
+ testValid();
+
+}
+
+
+QString ModInfoOverwrite::absolutePath() const
+{
+ return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOverwriteDir()));
+}
+
+std::vector<ModInfo::EFlag> ModInfoOverwrite::getFlags() const
+{
+ std::vector<ModInfo::EFlag> result;
+ result.push_back(FLAG_OVERWRITE);
+ return result;
+}
+
+int ModInfoOverwrite::getHighlight() const
+{
+ return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER;
+}
+
+
+QString ModInfoOverwrite::getDescription() const
+{
+ return tr("This pseudo mod contains files from the virtual data tree that got "
+ "modified (i.e. by the construction kit)");
+}
diff --git a/src/modinfo.h b/src/modinfo.h new file mode 100644 index 00000000..0e5367e4 --- /dev/null +++ b/src/modinfo.h @@ -0,0 +1,824 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MODINFO_H
+#define MODINFO_H
+
+#include "nexusinterface.h"
+#include <directoryentry.h>
+#include <versioninfo.h>
+#include <imodinterface.h>
+
+#include <QString>
+#include <QMutex>
+#include <QIcon>
+#include <QDir>
+#include <QSharedPointer>
+#include <QDateTime>
+#include <map>
+#include <set>
+#include <vector>
+
+
+/**
+ * @brief Represents meta information about a single mod.
+ *
+ * Represents meta information about a single mod. The class interface is used
+ * to manage the mod collection
+ *
+ **/
+class ModInfo : public QObject, public IModInterface
+{
+
+ Q_OBJECT
+
+public:
+
+ typedef QSharedPointer<ModInfo> Ptr;
+
+ static QString s_HiddenExt;
+
+ enum EFlag {
+ FLAG_INVALID,
+ FLAG_BACKUP,
+ FLAG_OVERWRITE,
+ FLAG_NOTENDORSED,
+ FLAG_NOTES,
+ FLAG_CONFLICT_OVERWRITE,
+ FLAG_CONFLICT_OVERWRITTEN,
+ FLAG_CONFLICT_MIXED,
+ FLAG_CONFLICT_REDUNDANT
+ };
+
+ enum EHighlight {
+ HIGHLIGHT_NONE = 0,
+ HIGHLIGHT_INVALID = 1,
+ HIGHLIGHT_CENTER = 2,
+ HIGHLIGHT_IMPORTANT = 4
+ };
+
+ enum EEndorsedState {
+ ENDORSED_FALSE,
+ ENDORSED_TRUE,
+ ENDORSED_UNKNOWN
+ };
+
+ struct NexusFileInfo {
+ NexusFileInfo(const QString &data);
+ NexusFileInfo(int id, const QString &name, const QString &url, const QString &version,
+ const QString &description, int category, int size)
+ : id(id), name(name), url(url), version(version), description(description),
+ category(category), size(size) {}
+ int id;
+ QString name;
+ QString url;
+ QString version;
+ QString description;
+ int category;
+ int size;
+
+ QString toString() const;
+ };
+
+public:
+
+ /**
+ * @brief read the mod directory and Mod ModInfo objects for all subdirectories
+ **/
+ static void updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure);
+
+ static void clear() { s_Collection.clear(); s_ModsByName.clear(); s_ModsByModID.clear(); }
+
+ /**
+ * @brief retrieve the number of mods
+ *
+ * @return number of mods
+ **/
+ static unsigned int getNumMods();
+
+ /**
+ * @brief retrieve a ModInfo object based on its index
+ *
+ * @param index the index to look up. the maximum is getNumMods() - 1
+ * @return a reference counting pointer to the mod info.
+ * @note since the pointer is reference counting, the pointer remains valid even if the collection is refreshed in a different thread
+ **/
+ static ModInfo::Ptr getByIndex(unsigned int index);
+
+ /**
+ * @brief retrieve a ModInfo object based on its nexus mod id
+ *
+ * @param modID the nexus mod id to look up
+ * @param missingAcceptable if true, this function will return a null-pointer if no mod has the specified mod id, otherwise an exception is thrown
+ * @return a reference counting pointer to the mod info
+ * @todo in its current form, this function is broken! There may be multiple mods with the same nexus id,
+ * this function will return only one of them
+ **/
+ static ModInfo::Ptr getByModID(int modID, bool missingAcceptable);
+
+ /**
+ * @brief remove a mod by index
+ *
+ * this physically deletes the specified mod from the disc and updates the ModInfo collection
+ * but not other structures that reference mods
+ * @param index index of the mod to delete
+ * @return true if removal was successful, fals otherwise
+ **/
+ static bool removeMod(unsigned int index);
+
+ /**
+ * @brief retrieve the mod index by the mod name
+ *
+ * @param name name of the mod to look up
+ * @return the index of the mod. If the mod doesn't exist, UINT_MAX is returned
+ **/
+ static unsigned int getIndex(const QString &name);
+
+ /**
+ * @brief find the first mod that fulfills the filter function (after no particular order)
+ * @param filter a function to filter by. should return true for a match
+ * @return index of the matching mod or UINT_MAX if there wasn't a match
+ */
+ static unsigned int findMod(const boost::function<bool (ModInfo::Ptr)> &filter);
+
+ /**
+ * @brief check a bunch of mods for updates
+ * @param modIDs list of mods (Nexus Mod IDs) to check for updates
+ * @return
+ */
+ static void checkChunkForUpdate(const std::vector<int> &modIDs, QObject *receiver);
+
+ /**
+ * @brief query nexus information for every mod and update the "newest version" information
+ **/
+ static int checkAllForUpdate(QObject *receiver);
+
+ /**
+ * @brief create a new mod from the specified directory and add it to the collection
+ * @param dir directory to create from
+ * @return pointer to the info-structure of the newly created/added mod
+ */
+ static ModInfo::Ptr createFrom(const QDir &dir, DirectoryEntry **directoryStructure);
+
+ /**
+ * @brief test if there is a newer version of the mod
+ *
+ * test if there is a newer version of the mod. This does NOT cause
+ * information to be retrieved from the nexus, it will only test version information already
+ * available locally. Use checkAllForUpdate() to update this version information
+ *
+ * @return true if there is a newer version
+ **/
+ virtual bool updateAvailable() const = 0;
+
+ /**
+ * @brief request an update of nexus description for this mod.
+ *
+ * This requests mod information from the nexus. This is an asynchronous request,
+ * so there is no immediate effect of this call.
+ * Right now, Mod Organizer interprets the "newest version" and "description" from the
+ * response, though the description is only stored in memory
+ *
+ **/
+ virtual bool updateNXMInfo() = 0;
+
+ /**
+ * @brief assign or unassign the specified category
+ *
+ * Every mod can have an arbitrary number of categories assigned to it
+ *
+ * @param categoryID id of the category to set
+ * @param active determines wheter the category is assigned or unassigned
+ * @note this function does not test whether categoryID actually identifies a valid category
+ **/
+ virtual void setCategory(int categoryID, bool active) = 0;
+
+ /**
+ * @brief set the name of this mod
+ *
+ * set the name of this mod. This will also update the name of the
+ * directory that contains this mod
+ *
+ * @param name new name of the mod
+ * @return true on success, false if the new name can't be used (i.e. because the new
+ * directory name wouldn't be valid)
+ **/
+ virtual bool setName(const QString &name) = 0;
+
+ /**
+ * @brief change the notes (manually set information) for this mod
+ * @param notes new notes
+ */
+ virtual void setNotes(const QString ¬es) = 0;
+
+ /**
+ * @brief set/change the nexus mod id of this mod
+ *
+ * @param modID the nexus mod id
+ **/
+ virtual void setNexusID(int modID) = 0;
+
+ /**
+ * @brief set/change the version of this mod
+ * @param version new version of the mod
+ */
+ virtual void setVersion(const VersionInfo &version);
+
+ /**
+ * @brief set the newest version of this mod on the nexus
+ *
+ * this can be used to overwrite the version of a mod without actually
+ * updating the mod
+ *
+ * @param version the new version to use
+ * @todo this function should be made obsolete. All queries for mod information should go through
+ * this class so no public function for this change is required
+ **/
+ virtual void setNewestVersion(const VersionInfo &version) = 0;
+
+ /**
+ * @brief changes/updates the nexus description text
+ * @param description the current description text
+ */
+ virtual void setNexusDescription(const QString &description) = 0;
+
+ /**
+ * update the endorsement state for the mod. This only changes the
+ * buffered state, it does not sync with Nexus
+ * @param endorsed the new endorsement state
+ */
+ virtual void setIsEndorsed(bool endorsed) = 0;
+
+ /**
+ * @brief delete the mod from the disc. This does not update the global ModInfo structure or indices
+ * @return true if the mod was successfully removed
+ **/
+ virtual bool remove() = 0;
+
+ /**
+ * @brief endorse or un-endorse the mod. This will sync with nexus!
+ * @param doEndorse if true, the mod is endorsed, if false, it's un-endorsed.
+ * @note if doEndorse doesn't differ from the current value, nothing happens.
+ */
+ virtual void endorse(bool doEndorse) = 0;
+
+ /**
+ * @brief getter for the mod name
+ *
+ * @return the mod name
+ **/
+ virtual QString name() const = 0;
+
+ /**
+ * @brief getter for the mod path
+ *
+ * @return the (absolute) path to the mod
+ **/
+ virtual QString absolutePath() const = 0;
+
+ /**
+ * @brief getter for the installation file
+ *
+ * @return file used to install this mod from
+ */
+ virtual QString getInstallationFile() const = 0;
+
+ /**
+ * @return version object for machine based comparisons
+ **/
+ virtual VersionInfo getVersion() const { return m_Version; }
+
+ /**
+ * @brief getter for the newest version number of this mod
+ *
+ * @return newest version of the mod
+ **/
+ virtual VersionInfo getNewestVersion() const = 0;
+
+ /**
+ * @brief getter for the nexus mod id
+ *
+ * @return the nexus mod id. may be 0 if the mod id isn't known or doesn't exist
+ **/
+ virtual int getNexusID() const = 0;
+
+ /**
+ * @return the fixed priority of mods of this type or INT_MIN if the priority of mods
+ * needs to be user-modifiable. Can be < 0 to force a priority below user-modifable mods
+ * or INT_MAX to force priority above all user-modifiables
+ */
+ virtual int getFixedPriority() const = 0;
+
+ /**
+ * @return true if the mod can be updated
+ */
+ virtual bool canBeUpdated() const { return false; }
+
+ /**
+ * @return true if the mod can be enabled/disabled
+ */
+ virtual bool canBeEnabled() const { return false; }
+
+ /**
+ * @return a list of flags for this mod
+ */
+ virtual std::vector<EFlag> getFlags() const = 0;
+
+ /**
+ * @return an indicator if and how this mod should be highlighted by the UI
+ */
+ virtual int getHighlight() const { return HIGHLIGHT_NONE; }
+
+ /**
+ * @return list of names of ini tweaks
+ **/
+ virtual std::vector<QString> getIniTweaks() const = 0;
+
+ /**
+ * @return a description about the mod, to be displayed in the ui
+ */
+ virtual QString getDescription() const = 0;
+
+ /**
+ * @return manually set notes for this mod
+ */
+ virtual QString notes() const = 0;
+
+ /**
+ * @brief return the list of files on nexus related to this mod in the form of iterators
+ * @note this is valid only after querying the files
+ * @param begin iterator to the first file
+ * @param end iterator to one past the last file
+ */
+ virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator &begin, QList<NexusFileInfo>::const_iterator &end) = 0;
+
+ /**
+ * @return nexus description of the mod (html)
+ */
+ virtual QString getNexusDescription() const = 0;
+
+ /**
+ * @return last time nexus was queried for infos on this mod
+ */
+ virtual QDateTime getLastNexusQuery() const = 0;
+
+ /**
+ * @brief test if the mod belongs to the specified category
+ *
+ * @param categoryID the category to test for.
+ * @return true if the mod belongs to the specified category
+ * @note this does not verify the id actually identifies a category
+ **/
+ bool categorySet(int categoryID) const;
+
+ /**
+ * @brief retrive the whole list of categories this mod belongs to
+ *
+ * @return list of categories
+ **/
+ const std::set<int> &getCategories() const { return m_Categories; }
+
+ /**
+ * @return the primary category of this mod
+ */
+ int getPrimaryCategory() const { return m_PrimaryCategory; }
+
+ /**
+ * @brief sets the new primary category of the mod
+ * @param categoryID the category to set
+ */
+ void setPrimaryCategory(int categoryID) { m_PrimaryCategory = categoryID; }
+
+ /**
+ * @return true if this mod is considered "valid", that is: it contains data used by the game
+ **/
+ bool isValid() const { return m_Valid; }
+
+ /**
+ * @return true if the file has been endorsed on nexus
+ */
+ virtual EEndorsedState endorsedState() const { return ENDORSED_UNKNOWN; }
+
+ /**
+ * @brief updates the valid-flag for this mod
+ */
+ void testValid();
+
+ /**
+ * @brief stores meta information back to disk
+ */
+ virtual void saveMeta() {}
+
+signals:
+
+ /**
+ * @brief emitted whenever the information of a mod changes
+ *
+ * @param success true if the mod details were updated successfully, false if not
+ **/
+ void modDetailsUpdated(bool success);
+
+protected:
+
+ ModInfo();
+
+ static void updateIndices();
+
+private:
+
+ static void createFromOverwrite();
+
+protected:
+
+ static std::vector<ModInfo::Ptr> s_Collection;
+ static std::map<QString, unsigned int> s_ModsByName;
+
+ int m_PrimaryCategory;
+ std::set<int> m_Categories;
+
+ VersionInfo m_Version;
+
+private:
+
+ static QMutex s_Mutex;
+ static std::map<int, unsigned int> s_ModsByModID;
+ static int s_NextID;
+
+ bool m_Valid;
+
+};
+
+
+
+/**
+ * @brief Represents meta information about a single mod.
+ *
+ * Represents meta information about a single mod. The class interface is used
+ * to manage the mod collection
+ *
+ **/
+class ModInfoRegular : public ModInfo
+{
+
+ Q_OBJECT
+
+ friend class ModInfo;
+
+public:
+
+ ~ModInfoRegular();
+
+ virtual bool isRegular() const { return true; }
+
+ /**
+ * @brief test if there is a newer version of the mod
+ *
+ * test if there is a newer version of the mod. This does NOT cause
+ * information to be retrieved from the nexus, it will only test version information already
+ * available locally. Use checkAllForUpdate() to update this version information
+ *
+ * @return true if there is a newer version
+ **/
+ bool updateAvailable() const;
+
+ /**
+ * @brief request an update of nexus description for this mod.
+ *
+ * This requests mod information from the nexus. This is an asynchronous request,
+ * so there is no immediate effect of this call.
+ *
+ * @return returns true if information for this mod will be updated, false if there is no nexus mod id to use
+ **/
+ bool updateNXMInfo();
+
+ /**
+ * @brief assign or unassign the specified category
+ *
+ * Every mod can have an arbitrary number of categories assigned to it
+ *
+ * @param categoryID id of the category to set
+ * @param active determines wheter the category is assigned or unassigned
+ * @note this function does not test whether categoryID actually identifies a valid category
+ **/
+ void setCategory(int categoryID, bool active);
+
+ /**
+ * @brief set the name of this mod
+ *
+ * set the name of this mod. This will also update the name of the
+ * directory that contains this mod
+ *
+ * @param name new name of the mod
+ * @return true on success, false if the new name can't be used (i.e. because the new
+ * directory name wouldn't be valid)
+ **/
+ bool setName(const QString &name);
+
+ /**
+ * @brief change the notes (manually set information) for this mod
+ * @param notes new notes
+ */
+ void setNotes(const QString ¬es);
+
+ /**
+ * @brief set/change the nexus mod id of this mod
+ *
+ * @param modID the nexus mod id
+ **/
+ void setNexusID(int modID) { m_NexusID = modID; }
+
+ /**
+ * @brief set the version of this mod
+ *
+ * this can be used to overwrite the version of a mod without actually
+ * updating the mod
+ *
+ * @param version the new version to use
+ **/
+ void setVersion(const VersionInfo &version);
+
+ /**
+ * @brief set the newest version of this mod on the nexus
+ *
+ * this can be used to overwrite the version of a mod without actually
+ * updating the mod
+ *
+ * @param version the new version to use
+ * @todo this function should be made obsolete. All queries for mod information should go through
+ * this class so no public function for this change is required
+ **/
+ void setNewestVersion(const VersionInfo &version) { m_NewestVersion = version; }
+
+ /**
+ * @brief changes/updates the nexus description text
+ * @param description the current description text
+ */
+ virtual void setNexusDescription(const QString &description);
+
+ /**
+ * update the endorsement state for the mod. This only changes the
+ * buffered state, it does not sync with Nexus
+ * @param endorsed the new endorsement state
+ */
+ virtual void setIsEndorsed(bool endorsed);
+
+ /**
+ * @brief delete the mod from the disc. This does not update the global ModInfo structure or indices
+ * @return true if the mod was successfully removed
+ **/
+ bool remove();
+
+ /**
+ * @brief endorse or un-endorse the mod
+ * @param doEndorse if true, the mod is endorsed, if false, it's un-endorsed.
+ * @note if doEndorse doesn't differ from the current value, nothing happens.
+ */
+ virtual void endorse(bool doEndorse);
+
+ /**
+ * @brief getter for the mod name
+ *
+ * @return the mod name
+ **/
+ QString name() const { return m_Name; }
+
+ /**
+ * @brief getter for the mod path
+ *
+ * @return the (absolute) path to the mod
+ **/
+ QString absolutePath() const;
+
+ /**
+ * @brief getter for the newest version number of this mod
+ *
+ * @return newest version of the mod
+ **/
+ VersionInfo getNewestVersion() const { return m_NewestVersion; }
+
+ /**
+ * @brief getter for the installation file
+ *
+ * @return file used to install this mod from
+ */
+ virtual QString getInstallationFile() const { return m_InstallationFile; }
+ /**
+ * @brief getter for the nexus mod id
+ *
+ * @return the nexus mod id. may be 0 if the mod id isn't known or doesn't exist
+ **/
+ int getNexusID() const { return m_NexusID; }
+
+ /**
+ * @return the fixed priority of mods of this type or INT_MIN if the priority of mods
+ * needs to be user-modifiable
+ */
+ virtual int getFixedPriority() const { return INT_MIN; }
+
+ /**
+ * @return true if the mod can be updated
+ */
+ virtual bool canBeUpdated() const { return m_NexusID >= 0; }
+
+ /**
+ * @return true if the mod can be enabled/disabled
+ */
+ virtual bool canBeEnabled() const { return true; }
+
+ /**
+ * @return a list of flags for this mod
+ */
+ virtual std::vector<EFlag> getFlags() const;
+
+ /**
+ * @return an indicator if and how this mod should be highlighted by the UI
+ */
+ virtual int getHighlight() const;
+
+ /**
+ * @return list of names of ini tweaks
+ **/
+ std::vector<QString> getIniTweaks() const;
+
+ /**
+ * @return a description about the mod, to be displayed in the ui
+ */
+ virtual QString getDescription() const;
+
+ /**
+ * @return manually set notes for this mod
+ */
+ virtual QString notes() const;
+
+ /**
+ * @brief return the list of files on nexus related to this mod in the form of iterators
+ * @note this is valid only after querying the files
+ * @param begin iterator to the first file
+ * @param end iterator to one past the last file
+ */
+ virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator &begin, QList<NexusFileInfo>::const_iterator &end);
+
+ /**
+ * @return nexus description of the mod (html)
+ */
+ QString getNexusDescription() const;
+
+ /**
+ * @return true if the file has been endorsed on nexus
+ */
+ virtual EEndorsedState endorsedState() const;
+
+ /**
+ * @return last time nexus was queried for infos on this mod
+ */
+ QDateTime getLastNexusQuery() const;
+
+ /**
+ * @brief stores meta information back to disk
+ */
+ virtual void saveMeta();
+
+private:
+
+ enum EConflictType {
+ CONFLICT_NONE,
+ CONFLICT_OVERWRITE,
+ CONFLICT_OVERWRITTEN,
+ CONFLICT_MIXED,
+ CONFLICT_REDUNDANT
+ };
+
+private slots:
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData);
+ void nxmFilesAvailable(int, QVariant, QVariant resultData);
+ void nxmEndorsementToggled(int, QVariant userData, QVariant resultData);
+ void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage);
+
+private:
+
+ /**
+ * @return true if there is a conflict for files in this mod
+ */
+ EConflictType isConflicted() const;
+
+ /**
+ * @return true if this mod is completely replaced by others
+ */
+ bool isRedundant() const;
+
+protected:
+
+ ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure);
+
+private:
+
+ QString m_Name;
+ QString m_Path;
+ QString m_InstallationFile;
+ QString m_Notes;
+ QString m_NexusDescription;
+ QList<NexusFileInfo> m_NexusFileInfos;
+
+ QDateTime m_LastNexusQuery;
+
+ int m_NexusID;
+
+ bool m_MetaInfoChanged;
+ VersionInfo m_NewestVersion;
+
+ EEndorsedState m_EndorsedState;
+
+ NexusBridge m_NexusBridge;
+
+ DirectoryEntry **m_DirectoryStructure;
+
+};
+
+
+class ModInfoBackup : public ModInfoRegular
+{
+
+ friend class ModInfo;
+
+public:
+
+ virtual bool updateAvailable() const { return false; }
+ virtual bool updateNXMInfo() { return false; }
+ virtual void setNexusID(int) {}
+ virtual void endorse(bool) {}
+ virtual int getFixedPriority() const { return -1; }
+ virtual bool canBeUpdated() const { return false; }
+ virtual bool canBeEnabled() const { return false; }
+ virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); }
+ virtual std::vector<EFlag> getFlags() const;
+ virtual QString getDescription() const;
+ virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
+ virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator&, QList<NexusFileInfo>::const_iterator&) {}
+ virtual QString getNexusDescription() const { return QString(); }
+
+private:
+
+ ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructure);
+
+};
+
+
+class ModInfoOverwrite : public ModInfo
+{
+
+ Q_OBJECT
+
+ friend class ModInfo;
+
+public:
+
+ virtual bool updateAvailable() const { return false; }
+ virtual bool updateNXMInfo() { return false; }
+ virtual void setCategory(int, bool) {}
+ virtual bool setName(const QString&) { return false; }
+ virtual void setNotes(const QString&) {}
+ virtual void setNexusID(int) {}
+ virtual void setNewestVersion(const VersionInfo&) {}
+ virtual void setNexusDescription(const QString&) {}
+ virtual void setIsEndorsed(bool) {}
+ virtual bool remove() { return false; }
+ virtual void endorse(bool) {}
+ virtual QString name() const { return tr("Overwrite"); }
+ virtual QString notes() const { return ""; }
+ virtual QString absolutePath() const;
+ virtual VersionInfo getNewestVersion() const { return ""; }
+ virtual QString getInstallationFile() const { return ""; }
+ virtual int getFixedPriority() const { return INT_MAX; }
+ virtual int getNexusID() const { return -1; }
+ virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); }
+ virtual std::vector<ModInfo::EFlag> getFlags() const;
+ virtual int getHighlight() const;
+ virtual QString getDescription() const;
+ virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
+ virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator&, QList<NexusFileInfo>::const_iterator&) {}
+ virtual QString getNexusDescription() const { return QString(); }
+
+private:
+
+ ModInfoOverwrite();
+
+};
+
+#endif // MODINFO_H
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp new file mode 100644 index 00000000..88440d99 --- /dev/null +++ b/src/modinfodialog.cpp @@ -0,0 +1,1218 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "modinfodialog.h"
+#include "ui_modinfodialog.h"
+
+#include "report.h"
+#include "utility.h"
+#include "json.h"
+#include "messagedialog.h"
+#include "bbcode.h"
+#include "questionboxmemory.h"
+#include "settings.h"
+#include <gameinfo.h>
+
+#include <QDir>
+#include <QDirIterator>
+#include <QPushButton>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QMenu>
+#include <QFileSystemModel>
+#include <Shlwapi.h>
+#include <sstream>
+
+
+using QtJson::Json;
+
+
+class ModFileListWidget : public QListWidgetItem {
+ friend bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS);
+public:
+ ModFileListWidget(const QString &text, int sortValue, QListWidget *parent = 0)
+ : QListWidgetItem(text, parent, QListWidgetItem::UserType + 1), m_SortValue(sortValue) {}
+private:
+ int m_SortValue;
+};
+
+
+bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS)
+{
+ return LHS.m_SortValue < RHS.m_SortValue;
+}
+
+
+ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, QWidget *parent)
+ : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo),
+ m_ThumbnailMapper(this), m_RequestStarted(false),
+ m_DeleteAction(NULL), m_RenameAction(NULL), m_OpenAction(NULL),
+ m_Directory(directory), m_Origin(NULL)
+{
+ ui->setupUi(this);
+ this->setWindowTitle(modInfo->name());
+
+ m_UTF8Codec = QTextCodec::codecForName("utf-8");
+
+ QListWidget *textFileList = findChild<QListWidget*>("textFileList");
+ QListWidget *iniFileList = findChild<QListWidget*>("iniFileList");
+ QListWidget *iniTweaksList = findChild<QListWidget*>("iniTweaksList");
+ QListWidget *activeESPList = findChild<QListWidget*>("activeESPList");
+ QListWidget *inactiveESPList = findChild<QListWidget*>("inactiveESPList");
+ QTreeWidget *categoriesTree = findChild<QTreeWidget*>("categoriesTree");
+ QHBoxLayout *thumbnailArea = findChild<QHBoxLayout*>("thumbnailArea");
+
+ m_FileTree = findChild<QTreeView*>("fileTree");
+
+ m_RootPath = modInfo->absolutePath();
+
+ QString metaFileName = m_RootPath.mid(0).append("/meta.ini");
+ m_Settings = new QSettings(metaFileName, QSettings::IniFormat);
+
+ QLineEdit *modIDEdit = findChild<QLineEdit*>("modIDEdit");
+ modIDEdit->setValidator(new QIntValidator(modIDEdit));
+ modIDEdit->setText(QString("%1").arg(modInfo->getNexusID()));
+
+ ui->notesEdit->setText(modInfo->notes());
+
+ m_FileSystemModel = new QFileSystemModel(this);
+ m_FileSystemModel->setReadOnly(false);
+ m_FileSystemModel->setRootPath(m_RootPath);
+ m_FileTree->setModel(m_FileSystemModel);
+ m_FileTree->setRootIndex(m_FileSystemModel->index(m_RootPath));
+ m_FileTree->setColumnWidth(0, 300);
+
+ connect(&m_ThumbnailMapper, SIGNAL(mapped(const QString&)), this, SIGNAL(thumbnailClickedSignal(const QString&)));
+ connect(this, SIGNAL(thumbnailClickedSignal(const QString&)), this, SLOT(thumbnailClicked(const QString&)));
+
+ m_DeleteAction = new QAction(tr("&Delete"), m_FileTree);
+ m_RenameAction = new QAction(tr("&Rename"), m_FileTree);
+ m_HideAction = new QAction(tr("&Hide"), m_FileTree);
+ m_UnhideAction = new QAction(tr("&Unhide"), m_FileTree);
+ m_OpenAction = new QAction(tr("&Open"), m_FileTree);
+ m_NewFolderAction = new QAction(tr("&New Folder"), m_FileTree);
+ QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered()));
+ QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered()));
+ QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered()));
+ QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered()));
+ QObject::connect(m_HideAction, SIGNAL(triggered()), this, SLOT(hideTriggered()));
+ connect(m_UnhideAction, SIGNAL(triggered()), this, SLOT(unhideTriggered()));
+ connect(m_ModInfo.data(), SIGNAL(modDetailsUpdated(bool)), this, SLOT(modDetailsUpdated(bool)));
+
+ ui->descriptionView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
+ QObject::connect(ui->descriptionView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl)));
+
+ if (directory->originExists(ToWString(modInfo->name()))) {
+ m_Origin = &directory->getOriginByName(ToWString(modInfo->name()));
+ if (m_Origin->isDisabled()) {
+ m_Origin = NULL;
+ }
+ }
+
+ addCategories(CategoryFactory::instance(), modInfo->getCategories(), categoriesTree->invisibleRootItem(), 0);
+ refreshPrimaryCategoriesBox();
+ refreshLists();
+
+ int numTweaks = m_Settings->beginReadArray("INI Tweaks");
+ for (int i = 0; i < numTweaks; ++i) {
+ m_Settings->setArrayIndex(i);
+ QList<QListWidgetItem*> items = iniTweaksList->findItems(m_Settings->value("name").toString(), Qt::MatchFixedString);
+ if (items.size() != 0) {
+ items.at(0)->setCheckState(Qt::Checked);
+ }
+ }
+ m_Settings->endArray();
+
+ QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
+ tabWidget->setTabEnabled(TAB_TEXTFILES, textFileList->count() != 0);
+ tabWidget->setTabEnabled(TAB_INIFILES, (iniFileList->count() != 0) || (iniTweaksList->count() != 0));
+ tabWidget->setTabEnabled(TAB_IMAGES, thumbnailArea->count() != 0);
+ tabWidget->setTabEnabled(TAB_ESPS, (inactiveESPList->count() != 0) || (activeESPList->count() != 0));
+ tabWidget->setTabEnabled(TAB_CONFLICTS, m_Origin != NULL);
+
+ if (tabWidget->currentIndex() == TAB_NEXUS) {
+ activateNexusTab();
+ }
+
+ ui->endorseBtn->setEnabled(m_ModInfo->endorsedState() == ModInfo::ENDORSED_FALSE);
+}
+
+
+ModInfoDialog::~ModInfoDialog()
+{
+ m_ModInfo->setNotes(ui->notesEdit->toPlainText());
+ saveIniTweaks();
+ saveCategories(ui->categoriesTree->invisibleRootItem());
+
+ delete ui;
+ delete m_Settings;
+}
+
+
+void ModInfoDialog::refreshLists()
+{
+ int numNonConflicting = 0;
+ int numOverwrite = 0;
+ int numOverwritten = 0;
+
+ ui->overwriteTree->clear();
+ ui->overwrittenTree->clear();
+
+ if (m_Origin != NULL) {
+ std::vector<FileEntry*> files = m_Origin->getFiles();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ QString relativeName = QDir::fromNativeSeparators(ToQString((*iter)->getRelativePath()));
+ QString fileName = relativeName.mid(0).prepend(m_RootPath);
+ bool ignore;
+ if ((*iter)->getOrigin(ignore) == m_Origin->getID()) {
+ std::vector<int> alternatives = (*iter)->getAlternatives();
+ if (!alternatives.empty()) {
+ std::wostringstream altString;
+ for (std::vector<int>::iterator altIter = alternatives.begin();
+ altIter != alternatives.end(); ++altIter) {
+ if (altIter != alternatives.begin()) {
+ altString << ", ";
+ }
+ altString << m_Directory->getOriginByID(*altIter).getName();
+ }
+ QStringList fields(relativeName.prepend("..."));
+ fields.append(ToQString(altString.str()));
+ QTreeWidgetItem *item = new QTreeWidgetItem(fields);
+ item->setData(0, Qt::UserRole, fileName);
+ item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives[0]).getName()));
+ item->setData(1, Qt::UserRole + 1, alternatives[0]);
+ ui->overwriteTree->addTopLevelItem(item);
+ ++numOverwrite;
+ } else {// otherwise don't display the file
+ ++numNonConflicting;
+ }
+ } else {
+ FilesOrigin &realOrigin = m_Directory->getOriginByID((*iter)->getOrigin(ignore));
+ QStringList fields(relativeName);
+ fields.append(ToQString(realOrigin.getName()));
+ QTreeWidgetItem *item = new QTreeWidgetItem(fields);
+ item->setData(1, Qt::UserRole, ToQString(realOrigin.getName()));
+ ui->overwrittenTree->addTopLevelItem(item);
+ ++numOverwritten;
+ }
+ }
+ }
+
+
+ QDirIterator dirIterator(m_RootPath, QDir::Files, QDirIterator::Subdirectories);
+ while (dirIterator.hasNext()) {
+ QString fileName = dirIterator.next();
+
+ if (fileName.endsWith(".txt", Qt::CaseInsensitive)) {
+ ui->textFileList->addItem(fileName.mid(m_RootPath.length() + 1));
+ } else if ((fileName.endsWith(".ini", Qt::CaseInsensitive) || fileName.endsWith(".cfg", Qt::CaseInsensitive)) &&
+ !fileName.endsWith("meta.ini")) {
+ QString namePart = fileName.mid(m_RootPath.length() + 1);
+ if (namePart.startsWith("INI Tweaks", Qt::CaseInsensitive)) {
+ QListWidgetItem *newItem = new QListWidgetItem(namePart.mid(11), ui->iniTweaksList);
+ newItem->setData(Qt::UserRole, namePart);
+ newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable);
+ newItem->setCheckState(Qt::Unchecked);
+ ui->iniTweaksList->addItem(newItem);
+ } else {
+ ui->iniFileList->addItem(namePart);
+ }
+ } else if (fileName.endsWith(".esp", Qt::CaseInsensitive) ||
+ fileName.endsWith(".esm", Qt::CaseInsensitive)) {
+ QString relativePath = fileName.mid(m_RootPath.length() + 1);
+ if (relativePath.contains('/')) {
+ QFileInfo fileInfo(fileName);
+ QListWidgetItem *newItem = new QListWidgetItem(fileInfo.fileName());
+ newItem->setData(Qt::UserRole, relativePath);
+ ui->inactiveESPList->addItem(newItem);
+ } else {
+ ui->activeESPList->addItem(relativePath);
+ }
+ } else if ((fileName.endsWith(".png", Qt::CaseInsensitive)) ||
+ (fileName.endsWith(".jpg", Qt::CaseInsensitive))) {
+ QImage image = QImage(fileName);
+ if (static_cast<float>(image.width()) / static_cast<float>(image.height()) > 1.34) {
+ image = image.scaledToWidth(128);
+ } else {
+ image = image.scaledToHeight(96);
+ }
+
+ QPushButton *thumbnailButton = new QPushButton(QPixmap::fromImage(image), "");
+ thumbnailButton->setIconSize(QSize(image.width(), image.height()));
+ connect(thumbnailButton, SIGNAL(clicked()), &m_ThumbnailMapper, SLOT(map()));
+ m_ThumbnailMapper.setMapping(thumbnailButton, fileName);
+ ui->thumbnailArea->addWidget(thumbnailButton);
+ }
+ }
+
+ ui->overwriteCount->display(numOverwrite);
+ ui->overwrittenCount->display(numOverwritten);
+ ui->noConflictCount->display(numNonConflicting);
+}
+
+
+void ModInfoDialog::addCategories(const CategoryFactory &factory, const std::set<int> &enabledCategories, QTreeWidgetItem *root, int rootLevel)
+{
+ for (unsigned int i = 0; i < factory.numCategories(); ++i) {
+ if (factory.getParentID(i) != rootLevel) {
+ continue;
+ }
+ int categoryID = factory.getCategoryID(i);
+ QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(factory.getCategoryName(i)));
+ newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable);
+ newItem->setCheckState(0, enabledCategories.find(categoryID) != enabledCategories.end() ? Qt::Checked : Qt::Unchecked);
+ newItem->setData(0, Qt::UserRole, categoryID);
+ if (factory.hasChildren(i)) {
+ addCategories(factory, enabledCategories, newItem, categoryID);
+ }
+ root->addChild(newItem);
+ }
+}
+
+
+void ModInfoDialog::saveCategories(QTreeWidgetItem *currentNode)
+{
+ for (int i = 0; i < currentNode->childCount(); ++i) {
+ QTreeWidgetItem *childNode = currentNode->child(i);
+ m_ModInfo->setCategory(childNode->data(0, Qt::UserRole).toInt(), childNode->checkState(0));
+ saveCategories(childNode);
+ }
+}
+
+
+void ModInfoDialog::on_closeButton_clicked()
+{
+ if (allowNavigateFromTXT() && allowNavigateFromINI()) {
+ this->close();
+ }
+}
+
+
+
+QString ModInfoDialog::getModVersion() const
+{
+ return m_Settings->value("version", "").toString();
+}
+
+
+const int ModInfoDialog::getModID() const
+{
+ return m_Settings->value("modid", 0).toInt();
+}
+
+
+void ModInfoDialog::openTab(int tab)
+{
+ QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
+ if (tabWidget->isTabEnabled(tab)) {
+ tabWidget->setCurrentIndex(tab);
+ }
+}
+
+
+void ModInfoDialog::thumbnailClicked(const QString &fileName)
+{
+ QLabel *imageLabel = findChild<QLabel*>("imageLabel");
+ QImage image(fileName);
+ if (static_cast<float>(image.width()) / static_cast<float>(image.height()) > 1.34) {
+ image = image.scaledToWidth(imageLabel->width());
+ } else {
+ image = image.scaledToHeight(imageLabel->height());
+ }
+ imageLabel->setPixmap(QPixmap::fromImage(image));
+}
+
+
+bool ModInfoDialog::allowNavigateFromTXT()
+{
+ if (ui->saveTXTButton->isEnabled()) {
+ int res = QMessageBox::question(this, tr("Save changes?"), tr("Save changes to \"%1\"?").arg(ui->textFileView->property("currentFile").toString()),
+ QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
+ if (res == QMessageBox::Cancel) {
+ return false;
+ } else if (res == QMessageBox::Yes) {
+ saveCurrentTextFile();
+ }
+ }
+ return true;
+}
+
+
+bool ModInfoDialog::allowNavigateFromINI()
+{
+ if (ui->saveButton->isEnabled()) {
+ int res = QMessageBox::question(this, tr("Save changes?"), tr("Save changes to \"%1\"?").arg(ui->iniFileView->property("currentFile").toString()),
+ QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
+ if (res == QMessageBox::Cancel) {
+ return false;
+ } else if (res == QMessageBox::Yes) {
+ saveCurrentIniFile();
+ }
+ }
+ return true;
+}
+
+
+void ModInfoDialog::on_textFileList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ QString fullPath = m_RootPath + "/" + current->text();
+
+ QVariant currentFile = ui->textFileView->property("currentFile");
+ if (currentFile.isValid() && (currentFile.toString() == fullPath)) {
+ // the new file is the same as the currently displayed file. May be the result of a cancelation
+ return;
+ }
+
+ if (allowNavigateFromTXT()) {
+ openTextFile(fullPath);
+ } else {
+ ui->textFileList->setCurrentItem(previous, QItemSelectionModel::Current);
+ }
+}
+
+
+void ModInfoDialog::openTextFile(const QString &fileName)
+{
+ QFile textFile(fileName);
+ textFile.open(QIODevice::ReadOnly);
+ QByteArray buffer = textFile.readAll();
+ QTextCodec *codec = QTextCodec::codecForUtfText(buffer, m_UTF8Codec);
+ ui->textFileView->setText(codec->toUnicode(buffer));
+ ui->textFileView->setProperty("currentFile", fileName);
+ ui->textFileView->setProperty("encoding", codec->name());
+ ui->saveTXTButton->setEnabled(false);
+}
+
+
+void ModInfoDialog::openIniFile(const QString &fileName)
+{
+ QPushButton* saveButton = findChild<QPushButton*>("saveButton");
+
+ QFile iniFile(fileName);
+ iniFile.open(QIODevice::ReadOnly);
+ QByteArray buffer = iniFile.readAll();
+ QTextCodec *codec = QTextCodec::codecForUtfText(buffer, m_UTF8Codec);
+ QTextEdit *iniFileView = findChild<QTextEdit*>("iniFileView");
+ iniFileView->setText(codec->toUnicode(buffer));
+ iniFileView->setProperty("currentFile", fileName);
+ iniFileView->setProperty("encoding", codec->name());
+ iniFile.close();
+
+ saveButton->setEnabled(false);
+}
+
+
+void ModInfoDialog::saveIniTweaks()
+{
+ QListWidget *iniTweaksList = findChild<QListWidget*>("iniTweaksList");
+
+ m_Settings->beginWriteArray("INI Tweaks");
+
+ int countEnabled = 0;
+ for (int i = 0; i < iniTweaksList->count(); ++i) {
+ if (iniTweaksList->item(i)->checkState() == Qt::Checked) {
+ m_Settings->setArrayIndex(countEnabled++);
+ m_Settings->setValue("name", iniTweaksList->item(i)->text());
+ }
+ }
+
+ m_Settings->endArray();
+}
+
+
+void ModInfoDialog::on_iniFileList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ QString fullPath = m_RootPath + "/" + current->text();
+
+ QVariant currentFile = ui->iniFileView->property("currentFile");
+ if (currentFile.isValid() && (currentFile.toString() == fullPath)) {
+ // the new file is the same as the currently displayed file. May be the result of a cancelation
+ return;
+ }
+
+ if (allowNavigateFromINI()) {
+ openIniFile(fullPath);
+ } else {
+ ui->iniFileList->setCurrentItem(previous, QItemSelectionModel::Current);
+ }
+}
+
+
+void ModInfoDialog::on_iniTweaksList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ QString fullPath = m_RootPath + "/" + current->data(Qt::UserRole).toString();
+
+ QVariant currentFile = ui->iniFileView->property("currentFile");
+ if (currentFile.isValid() && (currentFile.toString() == fullPath)) {
+ // the new file is the same as the currently displayed file. May be the result of a cancelation
+ return;
+ }
+
+ if (allowNavigateFromINI()) {
+ openIniFile(fullPath);
+ } else {
+ ui->iniFileList->setCurrentItem(previous, QItemSelectionModel::Current);
+ }
+
+}
+
+
+void ModInfoDialog::on_saveButton_clicked()
+{
+ saveCurrentIniFile();
+}
+
+
+void ModInfoDialog::on_saveTXTButton_clicked()
+{
+ saveCurrentTextFile();
+}
+
+
+void ModInfoDialog::saveCurrentTextFile()
+{
+ QVariant fileNameVar = ui->textFileView->property("currentFile");
+ QVariant encodingVar = ui->textFileView->property("encoding");
+ if (fileNameVar.isValid() && encodingVar.isValid()) {
+ QString fileName = fileNameVar.toString();
+ QFile txtFile(fileName);
+ txtFile.open(QIODevice::WriteOnly);
+ txtFile.resize(0);
+ QTextCodec *codec = QTextCodec::codecForName(encodingVar.toString().toUtf8());
+ QString data = ui->textFileView->toPlainText().replace("\n", "\r\n");
+ txtFile.write(codec->fromUnicode(data));
+ } else {
+ reportError("no file selected");
+ }
+ ui->saveTXTButton->setEnabled(false);
+}
+
+
+void ModInfoDialog::saveCurrentIniFile()
+{
+ QVariant fileNameVar = ui->iniFileView->property("currentFile");
+ QVariant encodingVar = ui->iniFileView->property("encoding");
+ if (fileNameVar.isValid()) {
+ QString fileName = fileNameVar.toString();
+ QFile txtFile(fileName);
+ txtFile.open(QIODevice::WriteOnly);
+ txtFile.resize(0);
+ QTextCodec *codec = QTextCodec::codecForName(encodingVar.toString().toUtf8());
+ QString data = ui->iniFileView->toPlainText().replace("\n", "\r\n");
+ txtFile.write(codec->fromUnicode(data));
+ } else {
+ reportError("no file selected");
+ }
+ ui->saveButton->setEnabled(false);
+}
+
+
+void ModInfoDialog::on_iniFileView_textChanged()
+{
+ QPushButton* saveButton = findChild<QPushButton*>("saveButton");
+ saveButton->setEnabled(true);
+}
+
+
+void ModInfoDialog::on_textFileView_textChanged()
+{
+ ui->saveTXTButton->setEnabled(true);
+}
+
+
+void ModInfoDialog::on_activateESP_clicked()
+{
+ QListWidget *activeESPList = findChild<QListWidget*>("activeESPList");
+ QListWidget *inactiveESPList = findChild<QListWidget*>("inactiveESPList");
+
+ int selectedRow = inactiveESPList->currentRow();
+ if (selectedRow < 0) {
+ return;
+ }
+
+ QListWidgetItem *selectedItem = inactiveESPList->takeItem(selectedRow);
+
+ QDir root(m_RootPath);
+ bool renamed = false;
+
+ while (root.exists(selectedItem->text())) {
+ bool okClicked = false;
+ QString newName = QInputDialog::getText(this, tr("File Exists"), tr("A file with that name exists, please enter a new one"), QLineEdit::Normal, selectedItem->text(), &okClicked);
+ if (!okClicked) {
+ inactiveESPList->insertItem(selectedRow, selectedItem);
+ return;
+ } else if (newName.size() > 0) {
+ selectedItem->setText(newName);
+ renamed = true;
+ }
+ }
+
+ if (root.rename(selectedItem->data(Qt::UserRole).toString(), selectedItem->text())) {
+ activeESPList->addItem(selectedItem);
+ if (renamed) {
+ selectedItem->setData(Qt::UserRole, QVariant());
+ }
+ } else {
+ inactiveESPList->insertItem(selectedRow, selectedItem);
+ reportError(tr("failed to move file"));
+ }
+}
+
+
+void ModInfoDialog::on_deactivateESP_clicked()
+{
+ QListWidget *activeESPList = findChild<QListWidget*>("activeESPList");
+ QListWidget *inactiveESPList = findChild<QListWidget*>("inactiveESPList");
+
+ int selectedRow = activeESPList->currentRow();
+ if (selectedRow < 0) {
+ return;
+ }
+
+ QDir root(m_RootPath);
+
+ QListWidgetItem *selectedItem = activeESPList->takeItem(selectedRow);
+
+ // if we moved the file from optional to active in this session, we move the file back to
+ // where it came from. Otherwise, it is moved to the new folder "optional"
+ if (selectedItem->data(Qt::UserRole).isNull()) {
+ selectedItem->setData(Qt::UserRole, QString("optional/") + selectedItem->text());
+ if (!root.exists("optional")) {
+ if (!root.mkdir("optional")) {
+ reportError(tr("failed to create directory \"optional\""));
+ activeESPList->insertItem(selectedRow, selectedItem);
+ return;
+ }
+ }
+ }
+
+ if (root.rename(selectedItem->text(), selectedItem->data(Qt::UserRole).toString())) {
+ inactiveESPList->addItem(selectedItem);
+ } else {
+ activeESPList->insertItem(selectedRow, selectedItem);
+ }
+}
+
+void ModInfoDialog::on_visitNexusLabel_linkActivated(const QString &link)
+{
+ this->close();
+ emit nexusLinkActivated(link);
+}
+
+void ModInfoDialog::linkClicked(const QUrl &url)
+{
+ if (url.toString().startsWith(ToQString(GameInfo::instance().getNexusPage()))) {
+ this->close();
+ emit nexusLinkActivated(url.toString());
+ } else {
+ ::ShellExecuteW(NULL, L"open", ToWString(url.toString()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+ }
+}
+
+
+void ModInfoDialog::refreshNexusData(int modID)
+{
+ if ((!m_RequestStarted) && (modID > 0)) {
+ m_RequestStarted = true;
+
+ m_ModInfo->updateNXMInfo();
+
+ MessageDialog::showMessage(tr("Info requested, please wait"), this);
+ }
+}
+
+
+/*void ModInfoDialog::nxmDescriptionAvailable(int, QVariant, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
+ if (idIter == m_RequestIDs.end()) {
+ return;
+ } else {
+ m_RequestIDs.erase(idIter);
+ }
+
+ QVariantMap result = resultData.toMap();
+
+ if (!result["description"].isNull()) {
+ QString descriptionAsHTML =
+ QString("<html>"
+ "<head><style>body {background: #707070; } a { color: #5EA2E5; }</style></head>"
+ "<body>%1</body>"
+ "</html>").arg(BBCode::convertToHTML(result["description"].toString()));
+
+// QString descriptionAsHTML = BBCode::convertToHTML(result["description"].toString());
+ ui->descriptionView->setHtml(descriptionAsHTML);
+ } else {
+ ui->descriptionView->setHtml(result["summary"].toString().append(QString("\r\n") + tr("(description incomplete, please visit nexus)")));
+ }
+
+ QLineEdit *versionEdit = findChild<QLineEdit*>("versionEdit");
+ QString version = result["version"].toString();
+
+ if (!version.isEmpty()) {
+ m_ModInfo->setNewestVersion(version);
+
+ VersionInfo currentVersion(versionEdit->text());
+ VersionInfo newestVersion(version);
+
+ QPalette versionColor;
+ if (currentVersion < newestVersion) {
+ versionColor.setColor(QPalette::Text, Qt::red);
+ versionEdit->setToolTip(tr("Current Version: %1").arg(version));
+ } else {
+ versionColor.setColor(QPalette::Text, Qt::green);
+ versionEdit->setToolTip(tr("No update available"));
+ }
+ versionEdit->setPalette(versionColor);
+ }
+}*/
+
+
+QString ModInfoDialog::getFileCategory(int categoryID)
+{
+ switch (categoryID) {
+ case 1: return tr("Main");
+ case 2: return tr("Update");
+ case 3: return tr("Optional");
+ case 4: return tr("Old");
+ case 5: return tr("Misc");
+ default: return tr("Unknown");
+ }
+}
+
+
+void ModInfoDialog::updateVersionColor()
+{
+ QPalette versionColor;
+ if (m_ModInfo->getVersion() < m_ModInfo->getNewestVersion()) {
+ versionColor.setColor(QPalette::Text, Qt::red);
+ ui->versionEdit->setToolTip(tr("Current Version: %1").arg(m_ModInfo->getNewestVersion().canonicalString()));
+ } else {
+ versionColor.setColor(QPalette::Text, Qt::green);
+ ui->versionEdit->setToolTip(tr("No update available"));
+ }
+ ui->versionEdit->setPalette(versionColor);
+}
+
+
+void ModInfoDialog::modDetailsUpdated(bool success)
+{
+ if (success) {
+ QString nexusDescription = m_ModInfo->getNexusDescription();
+ if (!nexusDescription.isEmpty()) {
+ /* QString input =
+ "[size=20]sizetest[/size]\r\n"
+ "[COLOR=yellow]colortest[/COLOR]\r\n"
+ "[center]centertest[/center]\r\n"
+ "[quote]quotetest 1[/quote]\r\n"
+ "[quote=bla]quotetest 2[/quote]\r\n"
+ "[url]www.skyrimnexus.com[/url]\r\n"
+ "[url=www.skyrimnexus.com]urltest 2[/url]\r\n"
+ "[ol]\r\n"
+ "[li]item 2[/li]"
+ "[*]item 1\r\n"
+ "[/ol]\r\n"
+ "[img]http://www.bbcode.org/images/bbcode_logo.png[/img]\r\n"
+ "[table][tr][th]headertest1[/th]"
+ "[th]headertest2[/th][/tr]"
+ "[tr][td]rowtest11[/td][td]rowtest12[/td][/tr]"
+ "[tr][td]rowtest21[/td][td]rowtest22[/td][/tr][/table]"
+ "[email=\"sherb@gmx.net\"]mail me[/email]";
+ ui->descriptionView->setHtml(BBCode::convertToHTML(input));*/
+
+ QString descriptionAsHTML =
+ QString("<html>"
+ "<head><style>body {background: #707070; } a { color: #5EA2E5; }</style></head>"
+ "<body>%1</body>"
+ "</html>").arg(BBCode::convertToHTML(nexusDescription));
+
+ // QString descriptionAsHTML = BBCode::convertToHTML(result["description"].toString());
+ ui->descriptionView->setHtml(descriptionAsHTML);
+ } else {
+ // ui->descriptionView->setHtml(result["summary"].toString().append(QString("\r\n") + tr("(description incomplete, please visit nexus)")));
+ ui->descriptionView->setHtml(tr("(description incomplete, please visit nexus)"));
+ }
+
+ QString version = m_ModInfo->getNewestVersion().canonicalString();
+
+ if (!version.isEmpty()) {
+ m_ModInfo->setNewestVersion(version);
+
+ updateVersionColor();
+ }
+
+ QTableWidget *filesWidget = findChild<QTableWidget*>("filesWidget");
+ filesWidget->clearContents();
+ filesWidget->setRowCount(0);
+ filesWidget->setColumnCount(5);
+#if QT_VERSION >= 0x050000
+ filesWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
+#else
+ filesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
+#endif
+ filesWidget->horizontalHeader()->setVisible(true);
+ filesWidget->setColumnHidden(4, true);
+
+
+ // prevent sorting while we change the table
+ filesWidget->setSortingEnabled(false);
+ int row = 0;
+ QList<ModInfo::NexusFileInfo>::const_iterator current, end;
+ m_ModInfo->getNexusFiles(current, end);
+ for (; current != end; ++current) {
+ filesWidget->insertRow(row);
+ int type = current->category;
+ filesWidget->setItem(row, 4, new QTableWidgetItem(QString("%1").arg(type)));
+ filesWidget->setItem(row, 0, new QTableWidgetItem(getFileCategory(type)));
+ QTableWidgetItem *nameItem = new QTableWidgetItem(current->name);
+ nameItem->setToolTip(current->description);
+ nameItem->setData(Qt::UserRole, current->id);
+ filesWidget->setItem(row, 1, nameItem);
+ filesWidget->setItem(row, 2, new QTableWidgetItem(current->version));
+ QTableWidgetItem *sizeItem = new QTableWidgetItem();
+ sizeItem->setData(Qt::DisplayRole, current->size);
+ filesWidget->setItem(row, 3, sizeItem);
+ ++row;
+ }
+ filesWidget->setSortingEnabled(true);
+ filesWidget->sortItems(4);
+ }
+}
+
+
+void ModInfoDialog::activateNexusTab()
+{
+ QLineEdit *modIDEdit = findChild<QLineEdit*>("modIDEdit");
+ int modID = modIDEdit->text().toInt();
+ if (modID != 0) {
+ QString nexusLink = QString("%1/downloads/file.php?id=%2").arg(ToQString(GameInfo::instance().getNexusPage())).arg(modID);
+ QLabel *visitNexusLabel = findChild<QLabel*>("visitNexusLabel");
+ visitNexusLabel->setText(tr("<a href=\"%1\">Visit on Nexus</a>").arg(nexusLink));
+ visitNexusLabel->setToolTip(nexusLink);
+
+
+ if (m_ModInfo->getNexusDescription().isEmpty() ||
+ QDateTime::currentDateTime() > m_ModInfo->getLastNexusQuery().addDays(1)) {
+ refreshNexusData(modID);
+ } else {
+ this->modDetailsUpdated(true);
+ }
+ }
+ QLineEdit *versionEdit = findChild<QLineEdit*>("versionEdit");
+ QString currentVersion = m_Settings->value("version", "0.0").toString();
+ versionEdit->setText(currentVersion);
+}
+
+
+void ModInfoDialog::on_tabWidget_currentChanged(int index)
+{
+ if (index == TAB_NEXUS) {
+ activateNexusTab();
+ }
+}
+
+
+void ModInfoDialog::on_modIDEdit_editingFinished()
+{
+ int oldID = m_Settings->value("modid", 0).toInt();
+ int modID = ui->modIDEdit->text().toInt();
+ if (oldID != modID){
+ m_ModInfo->setNexusID(modID);
+
+ ui->descriptionView->setHtml("");
+ if (modID != 0) {
+ m_RequestStarted = false;
+ refreshNexusData(modID);
+ }
+ }
+}
+
+void ModInfoDialog::on_versionEdit_editingFinished()
+{
+ VersionInfo version(ui->versionEdit->text());
+ m_ModInfo->setVersion(version);
+ updateVersionColor();
+}
+
+void ModInfoDialog::on_filesWidget_doubleClicked(const QModelIndex &index)
+{
+ QTableWidget *filesWidget = findChild<QTableWidget*>("filesWidget");
+
+ QTableWidgetItem *selectedItem = filesWidget->item(index.row(), 1);
+ if (selectedItem == NULL) {
+ qDebug("no item in row %d", index.row());
+ return;
+ }
+
+ QString nexusLink = QString("nxm://%1/mods/%2/files/%3")
+ .arg(ToQString(GameInfo::instance().getGameName()))
+ .arg(m_Settings->value("modid").toInt())
+ .arg(selectedItem->data(Qt::UserRole).toInt());
+
+ try {
+ if (QuestionBoxMemory::query(this, Settings::instance().directInterface(), "confirmNexusDownload",
+ tr("Confirm"), tr("Download \"%1\"?").arg(selectedItem->text()),
+ QDialogButtonBox::Yes | QDialogButtonBox::No) == QDialogButtonBox::Yes) {
+ emit downloadRequest(nexusLink);
+ MessageDialog::showMessage(tr("Download started"), this);
+ }
+ } catch (const std::exception &e) {
+ reportError(tr("Exception: %1").arg(e.what()));
+ }
+}
+
+
+bool ModInfoDialog::recursiveDelete(const QModelIndex &index)
+{
+ for (int childRow = 0; childRow < m_FileSystemModel->rowCount(index); ++childRow) {
+ QModelIndex childIndex = m_FileSystemModel->index(childRow, 0, index);
+ if (m_FileSystemModel->isDir(childIndex)) {
+ if (!recursiveDelete(childIndex)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData());
+ return false;
+ }
+ } else {
+ if (!m_FileSystemModel->remove(childIndex)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData());
+ return false;
+ }
+ }
+ }
+ if (!m_FileSystemModel->remove(index)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(index).toUtf8().constData());
+ return false;
+ }
+ return true;
+}
+
+
+void ModInfoDialog::deleteFile(const QModelIndex &index)
+{
+
+ bool res = m_FileSystemModel->isDir(index) ? recursiveDelete(index)
+ : m_FileSystemModel->remove(index);
+ if (!res) {
+ QString fileName = m_FileSystemModel->fileName(index);
+ reportError(tr("Failed to delete %1").arg(fileName));
+ }
+}
+
+
+void ModInfoDialog::deleteTriggered()
+{
+ if (m_FileSelection.count() == 0) {
+ return;
+ } else if (m_FileSelection.count() == 1) {
+ QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0));
+ if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName),
+ QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
+ return;
+ }
+ } else {
+ if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"),
+ QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
+ return;
+ }
+ }
+
+ foreach(QModelIndex index, m_FileSelection) {
+ deleteFile(index);
+ }
+}
+
+
+void ModInfoDialog::renameTriggered()
+{
+ QModelIndex selection = m_FileSelection.at(0);
+ QModelIndex index = selection.sibling(selection.row(), 0);
+ if (!index.isValid() || m_FileSystemModel->isReadOnly()) {
+ return;
+ }
+
+ m_FileTree->edit(index);
+}
+
+
+void ModInfoDialog::hideTriggered()
+{
+ for (QModelIndexList::const_iterator iter = m_FileSelection.constBegin();
+ iter != m_FileSelection.constEnd(); ++iter) {
+ QString path = m_FileSystemModel->filePath(*iter);
+ if (!path.endsWith(ModInfo::s_HiddenExt)) {
+ hideFile(path);
+ }
+ }
+}
+
+
+void ModInfoDialog::unhideTriggered()
+{
+ for (QModelIndexList::const_iterator iter = m_FileSelection.constBegin();
+ iter != m_FileSelection.constEnd(); ++iter) {
+ QString path = m_FileSystemModel->filePath(*iter);
+ if (path.endsWith(ModInfo::s_HiddenExt)) {
+ unhideFile(path);
+ }
+ }
+}
+
+
+void ModInfoDialog::openFile(const QModelIndex &index)
+{
+ QString fileName = m_FileSystemModel->filePath(index);
+
+ HINSTANCE res = ::ShellExecuteW(NULL, L"open", ToWString(fileName).c_str(), NULL, NULL, SW_SHOW);
+ if ((int)res <= 32) {
+ qCritical("failed to invoke %s: %d", fileName.toUtf8().constData(), res);
+ }
+}
+
+
+void ModInfoDialog::openTriggered()
+{
+ foreach(QModelIndex idx, m_FileSelection) {
+ openFile(idx);
+ }
+}
+
+void ModInfoDialog::createDirectoryTriggered()
+{
+ QModelIndex selection = m_FileSelection.at(0);
+
+ QModelIndex index = m_FileSystemModel->isDir(selection) ? selection
+ : selection.parent();
+ index = index.sibling(index.row(), 0);
+
+ QString name = tr("New Folder");
+ QString path = m_FileSystemModel->filePath(index).append("/");
+
+ QModelIndex existingIndex = m_FileSystemModel->index(path + name);
+ int suffix = 1;
+ while (existingIndex.isValid()) {
+ name = tr("New Folder") + QString::number(suffix++);
+ existingIndex = m_FileSystemModel->index(path + name);
+ }
+
+ QModelIndex newIndex = m_FileSystemModel->mkdir(index, name);
+ if (!newIndex.isValid()) {
+ reportError(tr("Failed to create \"%1\"").arg(name));
+ return;
+ }
+
+ m_FileTree->setCurrentIndex(newIndex);
+ m_FileTree->edit(newIndex);
+}
+
+
+void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos)
+{
+ QItemSelectionModel *selectionModel = m_FileTree->selectionModel();
+ m_FileSelection = selectionModel->selectedRows(0);
+
+// m_FileSelection = m_FileTree->indexAt(pos);
+ QMenu menu(m_FileTree);
+
+ menu.addAction(m_NewFolderAction);
+
+ bool hasFiles = false;
+
+ foreach(QModelIndex idx, m_FileSelection) {
+ if (m_FileSystemModel->fileInfo(idx).isFile()) {
+ hasFiles = true;
+ break;
+ }
+ }
+
+ if (selectionModel->hasSelection()) {
+ if (hasFiles) {
+ menu.addAction(m_OpenAction);
+ }
+ menu.addAction(m_RenameAction);
+ menu.addAction(m_DeleteAction);
+ if (m_FileSystemModel->fileName(m_FileSelection.at(0)).endsWith(ModInfo::s_HiddenExt)) {
+ menu.addAction(m_UnhideAction);
+ } else {
+ menu.addAction(m_HideAction);
+ }
+ } else {
+ m_FileSelection.clear();
+ m_FileSelection.append(m_FileSystemModel->index(m_FileSystemModel->rootPath(), 0));
+ }
+ menu.exec(m_FileTree->mapToGlobal(pos));
+}
+
+
+void ModInfoDialog::on_categoriesTree_itemChanged(QTreeWidgetItem *item, int)
+{
+ QTreeWidgetItem *parent = item->parent();
+ while ((parent != NULL) && ((parent->flags() & Qt::ItemIsUserCheckable) != 0) && (parent->checkState(0) == Qt::Unchecked)) {
+ parent->setCheckState(0, Qt::Checked);
+ parent = parent->parent();
+ }
+ refreshPrimaryCategoriesBox();
+}
+
+
+void ModInfoDialog::addCheckedCategories(QTreeWidgetItem *tree)
+{
+ for (int i = 0; i < tree->childCount(); ++i) {
+ QTreeWidgetItem *child = tree->child(i);
+ if (child->checkState(0) == Qt::Checked) {
+ ui->primaryCategoryBox->addItem(child->text(0), child->data(0, Qt::UserRole));
+ addCheckedCategories(child);
+ }
+ }
+}
+
+
+void ModInfoDialog::refreshPrimaryCategoriesBox()
+{
+ ui->primaryCategoryBox->clear();
+ int primaryCategory = m_ModInfo->getPrimaryCategory();
+ addCheckedCategories(ui->categoriesTree->invisibleRootItem());
+ for (int i = 0; i < ui->primaryCategoryBox->count(); ++i) {
+ if (ui->primaryCategoryBox->itemData(i).toInt() == primaryCategory) {
+ ui->primaryCategoryBox->setCurrentIndex(i);
+ break;
+ }
+ }
+}
+
+
+void ModInfoDialog::on_primaryCategoryBox_currentIndexChanged(int index)
+{
+ if (index != -1) {
+ m_ModInfo->setPrimaryCategory(ui->primaryCategoryBox->itemData(index).toInt());
+ }
+}
+
+
+void ModInfoDialog::on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int)
+{
+ this->close();
+ emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS);
+}
+
+
+bool ModInfoDialog::hideFile(const QString &oldName)
+{
+ QString newName = oldName + ModInfo::s_HiddenExt;
+
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a hidden version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ if (QFile::rename(oldName, newName)) {
+ return true;
+ } else {
+ reportError(tr("failed to rename %1 to %2").arg(oldName).arg(QDir::toNativeSeparators(newName)));
+ return false;
+ }
+}
+
+
+bool ModInfoDialog::unhideFile(const QString &oldName)
+{
+ QString newName = oldName.left(oldName.length() - ModInfo::s_HiddenExt.length());
+ if (QFileInfo(newName).exists()) {
+ if (QMessageBox::question(this, tr("Replace file?"), tr("There already is a visible version of this file. Replace it?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ if (!QFile(newName).remove()) {
+ QMessageBox::critical(this, tr("File operation failed"), tr("Failed to remove \"%1\". Maybe you lack the required file permissions?").arg(newName));
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (QFile::rename(oldName, newName)) {
+ return true;
+ } else {
+ reportError(tr("failed to rename %1 to %2").arg(QDir::toNativeSeparators(oldName)).arg(QDir::toNativeSeparators(newName)));
+ return false;
+ }
+}
+
+
+void ModInfoDialog::hideConflictFile()
+{
+ if (hideFile(m_ConflictsContextItem->data(0, Qt::UserRole).toString())) {
+ int originID = m_ConflictsContextItem->data(1, Qt::UserRole + 1).toInt();
+ emit originModified(originID);
+ refreshLists();
+ }
+}
+
+
+void ModInfoDialog::unhideConflictFile()
+{
+ if (unhideFile(m_ConflictsContextItem->data(0, Qt::UserRole).toString())) {
+ int originID = m_ConflictsContextItem->data(1, Qt::UserRole + 1).toInt();
+ emit originModified(originID);
+ refreshLists();
+ }
+}
+
+
+void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos)
+{
+ m_ConflictsContextItem = ui->overwriteTree->itemAt(pos.x(), pos.y());
+
+ QMenu menu;
+ if (m_ConflictsContextItem != NULL) {
+ // offer to hide/unhide file, but not for files from archives
+// if (!m_ConflictsContextItem->data(0, Qt::UserRole + 1).toBool()) {
+ if (true) {
+ if (m_ConflictsContextItem->text(0).endsWith(ModInfo::s_HiddenExt)) {
+ menu.addAction(tr("Un-Hide"), this, SLOT(unhideConflictFile()));
+ } else {
+ menu.addAction(tr("Hide"), this, SLOT(hideConflictFile()));
+ }
+ }
+ }
+
+ menu.exec(ui->overwriteTree->mapToGlobal(pos));
+}
+
+
+void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int)
+{
+ this->close();
+ emit modOpen(item->data(1, Qt::UserRole).toString(), TAB_CONFLICTS);
+}
+
+void ModInfoDialog::on_refreshButton_clicked()
+{
+ m_ModInfo->updateNXMInfo();
+
+ MessageDialog::showMessage(tr("Info requested, please wait"), this);
+}
+
+void ModInfoDialog::on_endorseBtn_clicked()
+{
+ emit endorseMod(m_ModInfo);
+}
diff --git a/src/modinfodialog.h b/src/modinfodialog.h new file mode 100644 index 00000000..8c91b74d --- /dev/null +++ b/src/modinfodialog.h @@ -0,0 +1,217 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MODINFODIALOG_H
+#define MODINFODIALOG_H
+
+
+#include "modinfo.h"
+#include "categories.h"
+#include "tutorabledialog.h"
+#include <directoryentry.h>
+
+#include <QDialog>
+#include <QSignalMapper>
+#include <QSettings>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QModelIndex>
+#include <QAction>
+#include <QListWidgetItem>
+#include <QTreeWidgetItem>
+#include <QTextCodec>
+#include <set>
+
+
+namespace Ui {
+ class ModInfoDialog;
+}
+
+class QFileSystemModel;
+class QTreeView;
+
+
+/**
+ * this is a larger dialog used to visualise information abount the mod.
+ * @todo this would probably a good place for a plugin-system
+ **/
+class ModInfoDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+
+ enum ETabs {
+ TAB_TEXTFILES,
+ TAB_INIFILES,
+ TAB_IMAGES,
+ TAB_ESPS,
+ TAB_CONFLICTS,
+ TAB_CATEGORIES,
+ TAB_NEXUS,
+ TAB_FILETREE
+ };
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param modInfo info structure about the mod to display
+ * @param parent parend widget
+ **/
+ explicit ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, QWidget *parent = 0);
+ ~ModInfoDialog();
+
+ /**
+ * @brief retrieve the (user-modified) version of the mod
+ *
+ * @return the (user-modified) version of the mod
+ **/
+ QString getModVersion() const;
+
+ /**
+ * @brief retrieve the (user-modified) mod id
+ *
+ * @return the (user-modified) id of the mod
+ **/
+ const int getModID() const;
+
+ /**
+ * @brief open the specified tab in the dialog if it's enabled
+ *
+ * @param tab the tab to activate
+ **/
+ void openTab(int tab);
+
+signals:
+
+ void thumbnailClickedSignal(const QString &filename);
+ void nexusLinkActivated(const QString &link);
+ void downloadRequest(const QString &link);
+ void modOpen(const QString &modName, int tab);
+ void originModified(int originID);
+ void endorseMod(ModInfo::Ptr nexusID);
+
+public slots:
+
+ void modDetailsUpdated(bool success);
+
+private:
+
+ void refreshLists();
+
+ void addCategories(const CategoryFactory &factory, const std::set<int> &enabledCategories, QTreeWidgetItem *root, int rootLevel);
+
+ void updateVersionColor();
+
+ void refreshNexusData(int modID);
+ void activateNexusTab();
+ QString getFileCategory(int categoryID);
+ bool recursiveDelete(const QModelIndex &index);
+ void deleteFile(const QModelIndex &index);
+ void openFile(const QModelIndex &index);
+ void saveIniTweaks();
+ void saveCategories(QTreeWidgetItem *currentNode);
+ void saveCurrentTextFile();
+ void saveCurrentIniFile();
+ void openTextFile(const QString &fileName);
+ void openIniFile(const QString &fileName);
+ bool allowNavigateFromTXT();
+ bool allowNavigateFromINI();
+ bool hideFile(const QString &oldName);
+ bool unhideFile(const QString &oldName);
+ void addCheckedCategories(QTreeWidgetItem *tree);
+ void refreshPrimaryCategoriesBox();
+
+private slots:
+
+ void hideConflictFile();
+ void unhideConflictFile();
+
+ void thumbnailClicked(const QString &fileName);
+ void linkClicked(const QUrl &url);
+
+ void deleteTriggered();
+ void renameTriggered();
+ void openTriggered();
+ void createDirectoryTriggered();
+ void hideTriggered();
+ void unhideTriggered();
+
+ void on_closeButton_clicked();
+ void on_saveButton_clicked();
+ void on_activateESP_clicked();
+ void on_deactivateESP_clicked();
+ void on_saveTXTButton_clicked();
+ void on_filesWidget_doubleClicked(const QModelIndex &index);
+ void on_visitNexusLabel_linkActivated(const QString &link);
+ void on_modIDEdit_editingFinished();
+ void on_versionEdit_editingFinished();
+ void on_iniFileView_textChanged();
+ void on_textFileView_textChanged();
+ void on_tabWidget_currentChanged(int index);
+ void on_primaryCategoryBox_currentIndexChanged(int index);
+ void on_categoriesTree_itemChanged(QTreeWidgetItem *item, int column);
+ void on_textFileList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void on_iniFileList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void on_iniTweaksList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int column);
+ void on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int column);
+ void on_overwriteTree_customContextMenuRequested(const QPoint &pos);
+ void on_fileTree_customContextMenuRequested(const QPoint &pos);
+
+ void on_refreshButton_clicked();
+
+ void on_endorseBtn_clicked();
+
+private:
+
+ Ui::ModInfoDialog *ui;
+
+ ModInfo::Ptr m_ModInfo;
+
+ QSignalMapper m_ThumbnailMapper;
+ QString m_RootPath;
+
+ QFileSystemModel *m_FileSystemModel;
+ QTreeView *m_FileTree;
+ QModelIndexList m_FileSelection;
+
+ QSettings *m_Settings;
+
+ std::set<int> m_RequestIDs;
+ bool m_RequestStarted;
+
+ QAction *m_DeleteAction;
+ QAction *m_RenameAction;
+ QAction *m_OpenAction;
+ QAction *m_NewFolderAction;
+ QAction *m_HideAction;
+ QAction *m_UnhideAction;
+
+ QTreeWidgetItem *m_ConflictsContextItem;
+
+ const DirectoryEntry *m_Directory;
+ FilesOrigin *m_Origin;
+ QTextCodec *m_UTF8Codec;
+
+};
+
+#endif // MODINFODIALOG_H
diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui new file mode 100644 index 00000000..faf08213 --- /dev/null +++ b/src/modinfodialog.ui @@ -0,0 +1,841 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ModInfoDialog</class>
+ <widget class="QDialog" name="ModInfoDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>720</width>
+ <height>648</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Mod Info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="tabShape">
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tabText">
+ <attribute name="title">
+ <string>Textfiles</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QListWidget" name="textFileList">
+ <property name="maximumSize">
+ <size>
+ <width>192</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>A list of text-files in the mod directory.</string>
+ </property>
+ <property name="whatsThis">
+ <string>A list of text-files in the mod directory like readmes. </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <item>
+ <widget class="QTextEdit" name="textFileView">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveTXTButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabIni">
+ <attribute name="title">
+ <string>INI-Files</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_5" stretch="0,0">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <widget class="QListWidget" name="iniFileList">
+ <property name="maximumSize">
+ <size>
+ <width>228</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>This is a list of .ini files in the mod.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="iniTweaksList">
+ <property name="maximumSize">
+ <size>
+ <width>228</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0">
+ <item>
+ <widget class="QTextBrowser" name="iniFileView">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="undoRedoEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ <property name="acceptRichText">
+ <bool>false</bool>
+ </property>
+ <property name="openLinks">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Save changes to the file.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Save changes to the file. This overwrites the original. There is no automatic backup!</string>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabImages">
+ <attribute name="title">
+ <string>Images</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="imageLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>676</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>Images located in the mod.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="thumbnailArea">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabESPs">
+ <attribute name="title">
+ <string>Optional ESPs</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="1" column="1">
+ <widget class="QListWidget" name="inactiveESPList">
+ <property name="toolTip">
+ <string>List of esps and esms that can not be loaded by the game.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Optional ESPs</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QToolButton" name="deactivateESP">
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Make the selected mod in the lower list unavailable.</string>
+ </property>
+ <property name="whatsThis">
+ <string>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/go-up.png</normaloff>:/MO/gui/resources/go-up.png</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="activateESP">
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Move a file to the data directory.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/go-down.png</normaloff>:/MO/gui/resources/go-down.png</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="1">
+ <widget class="QListWidget" name="activeESPList">
+ <property name="toolTip">
+ <string>ESPs in the data directory and thus visible to the game.</string>
+ </property>
+ <property name="whatsThis">
+ <string>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Available ESPs</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabConflicts">
+ <attribute name="title">
+ <string>Conflicts</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0">
+ <item>
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>The following conflicted files are provided by this mod</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLCDNumber" name="overwriteCount">
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="segmentStyle">
+ <enum>QLCDNumber::Flat</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="overwriteTree">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideLeft</enum>
+ </property>
+ <property name="animated">
+ <bool>true</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>false</bool>
+ </property>
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>500</number>
+ </attribute>
+ <attribute name="headerHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerMinimumSectionSize">
+ <number>300</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Overwritten Mods</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="1,0">
+ <item>
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>The following conflicted files are provided by other mods</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLCDNumber" name="overwrittenCount">
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="segmentStyle">
+ <enum>QLCDNumber::Flat</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="overwrittenTree">
+ <property name="textElideMode">
+ <enum>Qt::ElideLeft</enum>
+ </property>
+ <property name="animated">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>500</number>
+ </attribute>
+ <attribute name="headerMinimumSectionSize">
+ <number>300</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Providing Mod</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,0">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Non-Conflicted files</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLCDNumber" name="noConflictCount">
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="segmentStyle">
+ <enum>QLCDNumber::Flat</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabCategories">
+ <attribute name="title">
+ <string>Categories</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <item>
+ <widget class="QTreeWidget" name="categoriesTree">
+ <property name="animated">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Primary Category</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="primaryCategoryBox"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabNexus_2">
+ <attribute name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/internet-web-browser.png</normaloff>:/MO/gui/resources/internet-web-browser.png</iconset>
+ </attribute>
+ <attribute name="title">
+ <string>Nexus Info</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Mod ID</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="modIDEdit">
+ <property name="toolTip">
+ <string>Mod ID for this mod on Nexus.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="versionLabel">
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></string>
+ </property>
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="versionEdit">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="maxLength">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_11" stretch="0,1">
+ <item>
+ <widget class="QPushButton" name="refreshButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Refresh</string>
+ </property>
+ <property name="whatsThis">
+ <string>Refresh all information from Nexus.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Description</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWebView" name="descriptionView">
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ </font>
+ </property>
+ <property name="url">
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ <property name="zoomFactor">
+ <double>0.800000011920929</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Files</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableWidget" name="filesWidget">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="whatsThis">
+ <string>List of files currently uploaded on nexus. Double click to download.</string>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Size (kB)</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="visitNexusLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="openExternalLinks">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="endorseBtn">
+ <property name="text">
+ <string>Endorse</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/icon_favorite</normaloff>:/MO/gui/icon_favorite</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabNotes">
+ <attribute name="title">
+ <string>Notes</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_10">
+ <item>
+ <widget class="QTextEdit" name="notesEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tabFiles">
+ <attribute name="title">
+ <string>Filetree</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTreeView" name="fileTree">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>A directory view of this mod</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></string>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::InternalMove</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/modlist.cpp b/src/modlist.cpp new file mode 100644 index 00000000..b1d0caf8 --- /dev/null +++ b/src/modlist.cpp @@ -0,0 +1,671 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "modlist.h"
+
+#include "report.h"
+#include "utility.h"
+#include "messagedialog.h"
+#include "installationtester.h"
+#include <gameinfo.h>
+
+#include <QFileInfo>
+#include <QDir>
+#include <QDirIterator>
+#include <QMimeData>
+#include <stdexcept>
+#include <QStandardItemModel>
+#include <QMessageBox>
+#include <QStringList>
+#include <QEvent>
+#include <QContextMenuEvent>
+#include <QMenu>
+#include <QCheckBox>
+#include <QWidgetAction>
+#include <QAbstractItemView>
+#include <QSortFilterProxyModel>
+#include <sstream>
+#include <algorithm>
+
+
+ModList::ModList(QObject *parent)
+ : QAbstractItemModel(parent), m_Profile(NULL), m_Modified(false),
+ m_FontMetrics(QFont())
+{
+// setSupportedDragActions(Qt::MoveAction);
+}
+
+
+void ModList::setProfile(Profile *profile)
+{
+ m_Profile = profile;
+}
+
+
+int ModList::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid()) {
+ return ModInfo::getNumMods();
+ } else {
+ return 0;
+ }
+}
+
+
+int ModList::columnCount(const QModelIndex &) const
+{
+ return COL_LASTCOLUMN + 1;
+}
+
+
+QVariant ModList::getOverwriteData(int column, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole: {
+ if (column == 0) {
+ return tr("Overwrite");
+ } else {
+ return QVariant();
+ }
+ } break;
+ case Qt::CheckStateRole: {
+ if (column == 0) {
+ return Qt::Checked;
+ } else {
+ return QVariant();
+ }
+ } break;
+ case Qt::TextAlignmentRole: return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
+ case Qt::UserRole: return -1;
+ case Qt::ForegroundRole: return QBrush(Qt::red);
+ case Qt::ToolTipRole: return tr("This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)");
+ default: return QVariant();
+ }
+}
+
+
+QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const
+{
+ switch (flag) {
+ case ModInfo::FLAG_BACKUP: return tr("Backup");
+ case ModInfo::FLAG_INVALID: return tr("No valid game data");
+ case ModInfo::FLAG_NOTENDORSED: return tr("Not endorsed yet");
+ case ModInfo::FLAG_NOTES: return QString("<i>%1</i>").arg(modInfo->notes().replace("\n", "<br>"));
+ case ModInfo::FLAG_CONFLICT_OVERWRITE: return tr("Overwrites files");
+ case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return tr("Overwritten files");
+ case ModInfo::FLAG_CONFLICT_MIXED: return tr("Overwrites & Overwritten");
+ case ModInfo::FLAG_CONFLICT_REDUNDANT: return tr("Redundant");
+ default: return "";
+ }
+}
+
+
+QVariant ModList::data(const QModelIndex &modelIndex, int role) const
+{
+ if (m_Profile == NULL) return QVariant();
+ unsigned int modIndex = modelIndex.row();
+ int column = modelIndex.column();
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ if ((role == Qt::DisplayRole) ||
+ (role == Qt::EditRole)) {
+ if (column == COL_FLAGS) {
+ return QVariant();
+ } else if (column == COL_NAME) {
+ return modInfo->name();
+ } else if (column == COL_VERSION) {
+ QString version = modInfo->getVersion().canonicalString();
+ if (version.isEmpty() && modInfo->canBeUpdated()) {
+ version = "?";
+ }
+ return version;
+ } else if (column == COL_PRIORITY) {
+ int priority = modInfo->getFixedPriority();
+ if (priority != INT_MIN) {
+ return QVariant(); // hide priority for mods where it's fixed
+ } else {
+ if ((m_Profile->getModPriority(modIndex) == 0) && (role == Qt::DisplayRole)) {
+ return tr("min");
+ } else if ((m_Profile->getModPriority(modIndex) == m_Profile->numRegularMods() - 1) &&
+ (role == Qt::DisplayRole)) {
+ return tr("max");
+ } else {
+ //return QString::number(m_Profile->getModPriority(modIndex));
+ return m_Profile->getModPriority(modIndex);
+ }
+ }
+ } else if (column == COL_MODID) {
+ int modID = modInfo->getNexusID();
+ if (modID >= 0) {
+ return modID;
+ } else {
+ return QVariant();
+ }
+ } else if (column == COL_CATEGORY) {
+ int category = modInfo->getPrimaryCategory();
+ if (category != -1) {
+ CategoryFactory &categoryFactory = CategoryFactory::instance();
+ try {
+ return categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(category));
+ } catch (const std::exception &e) {
+ qCritical("failed to retrieve category name: %s", e.what());
+ return QString();
+ }
+ } else {
+ //return tr("None");
+ return QVariant();
+ }
+ } else {
+ return tr("invalid");
+ }
+ } else if ((role == Qt::CheckStateRole) && (column == 0)) {
+ if (modInfo->canBeEnabled()) {
+ return m_Profile->modEnabled(modIndex) ? Qt::Checked : Qt::Unchecked;
+ } else {
+ return QVariant();
+ }
+ } else if (role == Qt::TextAlignmentRole) {
+ if (column == COL_NAME) {
+ if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_CENTER) {
+ return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
+ } else {
+ return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
+ }
+ } else if (column == COL_VERSION) {
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ } else {
+ return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
+ }
+ } else if (role == Qt::UserRole) {
+ return modInfo->getNexusID();
+ } else if (role == Qt::FontRole) {
+ QFont result;
+ if (column == COL_NAME) {
+ if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) {
+ result.setItalic(true);
+ }
+ } else if (column == COL_VERSION) {
+ if (modInfo->updateAvailable()) {
+ result.setWeight(QFont::Bold);
+ }
+ }
+ return result;
+ } else if (role == Qt::DecorationRole) {
+ if ((column == COL_VERSION) &&
+ modInfo->updateAvailable() &&
+ modInfo->getNewestVersion().isValid()) {
+ return QIcon(":/MO/gui/update_available");
+ }
+ return QVariant();
+ } else if (role == Qt::ForegroundRole) {
+ if (column == COL_NAME) {
+ int highlight = modInfo->getHighlight();
+ if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) return QBrush(Qt::darkRed);
+ else if (highlight & ModInfo::HIGHLIGHT_INVALID) return QBrush(Qt::darkGray);
+ } else if (column == COL_VERSION) {
+ if (!modInfo->getNewestVersion().isValid()) {
+ return QVariant();
+ } else if (modInfo->updateAvailable()) {
+ return QBrush(Qt::red);
+ } else {
+ return QBrush(Qt::darkGreen);
+ }
+ }
+ return QVariant();
+ } else if (role == Qt::ToolTipRole) {
+ if (column == COL_FLAGS) {
+ QString result;
+
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+
+ for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
+ if (result.length() != 0) result += "<br>";
+ result += getFlagText(*iter, modInfo);
+ }
+
+ return result;
+ } else if (column == COL_NAME) {
+ try {
+ return modInfo->getDescription();
+ } catch (const std::exception &e) {
+ qCritical("invalid mod description: %s", e.what());
+ return QString();
+ }
+ } else if (column == COL_VERSION) {
+ return tr("installed version: %1, newest version: %2").arg(modInfo->getVersion().canonicalString()).arg(modInfo->getNewestVersion().canonicalString());
+ } else if (column == COL_CATEGORY) {
+ const std::set<int> &categories = modInfo->getCategories();
+ std::wostringstream categoryString;
+ categoryString << ToWString(tr("Categories: <br>"));
+ CategoryFactory &categoryFactory = CategoryFactory::instance();
+ for (std::set<int>::const_iterator catIter = categories.begin();
+ catIter != categories.end(); ++catIter) {
+ if (catIter != categories.begin()) {
+ categoryString << " , ";
+ }
+ try {
+ categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>";
+ } catch (const std::exception &e) {
+ qCritical("failed to generate tooltip: %s", e.what());
+ return QString();
+ }
+ }
+
+ return ToQString(categoryString.str());
+ } else {
+ return QVariant();
+ }
+ } else {
+ return QVariant();
+ }
+}
+
+
+bool ModList::renameMod(int index, const QString &newName)
+{
+ // before we rename, write back the current profile so we don't lose changes and to ensure
+ // there is no scheduled asynchronous rewrite anytime soon
+ m_Profile->writeModlistNow();
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ QString oldName = modInfo->name();
+ modInfo->setName(newName);
+ // this just broke all profiles! The recipient of modRenamed has to do some magic
+ // to can't write the currently active profile back
+ emit modRenamed(oldName, newName);
+
+ // invalidate the currently displayed state of this list
+ notifyChange(-1);
+ return true;
+}
+
+
+bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (m_Profile == NULL) return false;
+
+ if (static_cast<unsigned int>(index.row()) >= ModInfo::getNumMods()) {
+ return false;
+ }
+
+ if (role == Qt::CheckStateRole) {
+ bool enabled = value.toInt() == Qt::Checked;
+ if (m_Profile->modEnabled(index.row()) != enabled) {
+ m_Profile->setModEnabled(index.row(), enabled);
+ m_Modified = true;
+
+ emit modlist_changed(index.row());
+ }
+ return true;
+ } else if (role == Qt::EditRole) {
+ switch (index.column()) {
+ case COL_NAME: {
+ return renameMod(index.row(), value.toString());
+ } break;
+ case COL_PRIORITY: {
+ bool ok = false;
+ int newPriority = value.toInt(&ok);
+ if (ok) {
+ m_Profile->setModPriority(index.row(), newPriority);
+
+ emit modlist_changed(index.row());
+ return true;
+ } else {
+ return false;
+ }
+ } break;
+ case COL_MODID: {
+ ModInfo::Ptr info = ModInfo::getByIndex(index.row());
+ bool ok = false;
+ int newID = value.toInt(&ok);
+ if (ok) {
+ info->setNexusID(newID);
+ emit modlist_changed(index.row());
+ return true;
+ } else {
+ return false;
+ }
+ } break;
+ case COL_VERSION: {
+ ModInfo::Ptr info = ModInfo::getByIndex(index.row());
+ VersionInfo version(value.toString());
+ if (version.isValid()) {
+ info->setVersion(version);
+ return true;
+ } else {
+ return false;
+ }
+ } break;
+ default: {
+ qWarning("edit on column \"%s\" not supported",
+ getColumnName(index.column()).toUtf8().constData());
+ return false;
+ } break;
+ }
+ } else {
+ return false;
+ }
+}
+
+
+ModList::EColumn ModList::getEnabledColumn(int index) const
+{
+ for (int i = 0; i <= COL_LASTCOLUMN; ++i) {
+ if (index == 0) {
+ return static_cast<EColumn>(i);
+ } else {
+ --index;
+ }
+ }
+ return ModList::COL_NAME;
+}
+
+
+QVariant ModList::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ if (role == Qt::DisplayRole) {
+ return getColumnName(section);
+ } else if (role == Qt::ToolTipRole) {
+ return getColumnToolTip(section);
+ } else if (role == Qt::TextAlignmentRole) {
+ return QVariant(Qt::AlignCenter);
+ } else if (role == Qt::SizeHintRole) {
+ QSize temp = m_FontMetrics.size(Qt::TextSingleLine, getColumnName(section));
+ temp.rwidth() += 20;
+ temp.rheight() += 12;
+ return temp;
+ }
+ }
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+
+Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const
+{
+ Qt::ItemFlags result = QAbstractItemModel::flags(modelIndex);
+ if (modelIndex.internalId() < 0) {
+ return Qt::ItemIsEnabled;
+ }
+ if (modelIndex.isValid()) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modelIndex.row());
+ if (modInfo->getFixedPriority() == INT_MIN) {
+ result |= Qt::ItemIsDragEnabled;
+ result |= Qt::ItemIsUserCheckable;
+ if ((modelIndex.column() == COL_NAME) ||
+ (modelIndex.column() == COL_PRIORITY) ||
+ (modelIndex.column() == COL_VERSION) ||
+ (modelIndex.column() == COL_MODID)) {
+ result |= Qt::ItemIsEditable;
+ }
+ }
+ } else {
+ result |= Qt::ItemIsDropEnabled;
+ }
+ return result;
+}
+
+
+void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority)
+{
+ if (m_Profile == NULL) return;
+
+ emit layoutAboutToBeChanged();
+ Profile *profile = m_Profile;
+ // sort rows to insert by their old priority (ascending) and insert them move them in that order
+ std::sort(sourceIndices.begin(), sourceIndices.end(),
+ [profile](const int &LHS, const int &RHS) {
+ return profile->getModPriority(LHS) < profile->getModPriority(RHS);
+ });
+
+ // odd stuff: if any of the dragged sources has priority lower than the destination then the
+ // target idx is that of the row BELOW the dropped location, otherwise it's the one above. why?
+ for (std::vector<int>::const_iterator iter = sourceIndices.begin();
+ iter != sourceIndices.end(); ++iter) {
+ if (profile->getModPriority(*iter) < newPriority) {
+ --newPriority;
+ break;
+ }
+ }
+
+ for (std::vector<int>::const_iterator iter = sourceIndices.begin();
+ iter != sourceIndices.end(); ++iter) {
+ m_Profile->setModPriority(*iter, newPriority);
+ }
+
+ emit layoutChanged();
+
+ emit modorder_changed();
+}
+
+
+void ModList::changeModPriority(int sourceIndex, int newPriority)
+{
+ if (m_Profile == NULL) return;
+ emit layoutAboutToBeChanged();
+
+ m_Profile->setModPriority(sourceIndex, newPriority);
+
+ emit layoutChanged();
+
+ emit modorder_changed();
+}
+
+
+bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction) {
+ return true;
+ }
+
+ if (m_Profile == NULL) return false;
+
+ try {
+ QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist");
+ QDataStream stream(&encoded, QIODevice::ReadOnly);
+ std::vector<int> sourceRows;
+
+ while (!stream.atEnd()) {
+ int sourceRow, col;
+ QMap<int, QVariant> roleDataMap;
+ stream >> sourceRow >> col >> roleDataMap;
+ if (col == 0) {
+ sourceRows.push_back(sourceRow);
+ }
+ }
+
+ if (row == -1) {
+ row = parent.row();
+ }
+
+ if ((row < 0) || (static_cast<unsigned int>(row) >= ModInfo::getNumMods())) {
+ return false;
+ }
+
+ int newPriority = 0;
+ {
+ if ((row < 0) || (row > static_cast<int>(m_Profile->numRegularMods()))) {
+ newPriority = m_Profile->numRegularMods() + 1;
+ } else {
+ newPriority = m_Profile->getModPriority(row);
+ }
+ if (newPriority == -1) {
+ newPriority = m_Profile->numRegularMods() + 1;
+ }
+ }
+ changeModPriority(sourceRows, newPriority);
+ } catch (const std::exception &e) {
+ reportError(tr("drag&drop failed: %1").arg(e.what()));
+ }
+
+ return false;
+}
+
+
+void ModList::removeRowForce(int row)
+{
+ if (static_cast<unsigned int>(row) >= ModInfo::getNumMods()) {
+ return;
+ }
+ if (m_Profile == NULL) return;
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+
+ bool wasEnabled = m_Profile->modEnabled(row);
+ beginRemoveRows(QModelIndex(), row, row);
+
+ m_Profile->cancelWriteModlist(); // don't write modlist while we're changing it
+ ModInfo::removeMod(row);
+ m_Profile->refreshModStatus(); // removes the mod from the status list
+ m_Profile->writeModlist(); // this ensures the modified list gets written back before new mods can be installed
+
+ endRemoveRows();
+ if (wasEnabled) {
+ emit removeOrigin(modInfo->name());
+ }
+}
+
+
+void ModList::removeRow(int row, const QModelIndex&)
+{
+ if (static_cast<unsigned int>(row) >= ModInfo::getNumMods()) {
+ return;
+ }
+ if (m_Profile == NULL) return;
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+
+ QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"), tr("Are you sure you want to remove \"%1\"?").arg(modInfo->name()),
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (confirmBox.exec() == QMessageBox::Yes) {
+ removeRowForce(row);
+ }
+}
+
+
+void ModList::notifyChange(int row)
+{
+ if (row < 0) {
+ beginResetModel();
+ endResetModel();
+ } else {
+ emit dataChanged(this->index(row, 0), this->index(row, this->columnCount() - 1));
+ }
+}
+
+
+QModelIndex ModList::index(int row, int column, const QModelIndex&) const
+{
+ return createIndex(row, column, row);
+}
+
+
+QModelIndex ModList::parent(const QModelIndex&) const
+{
+ return QModelIndex();
+}
+
+
+QString ModList::getColumnName(int column)
+{
+ switch (column) {
+ case COL_FLAGS: return tr("Flags");
+ case COL_NAME: return tr("Name");
+ case COL_VERSION: return tr("Version");
+ case COL_PRIORITY: return tr("Priority");
+ case COL_CATEGORY: return tr("Category");
+ case COL_MODID: return tr("Nexus ID");
+ default: return tr("unknown");
+ }
+}
+
+
+QString ModList::getColumnToolTip(int column)
+{
+ switch (column) {
+ case COL_NAME: return tr("Name of your mods");
+ case COL_VERSION: return tr("Version of the mod (if available)");
+ case COL_PRIORITY: return tr("Installation priority of your mod. The higher, the more \"important\" it is and thus "
+ "overwrites files from mods with lower priority.");
+ case COL_CATEGORY: return tr("Category of the mod.");
+ case COL_MODID: return tr("Id of the mod as used on Nexus.");
+ case COL_FLAGS: return tr("Emblemes to highlight things that might require attention.");
+ default: return tr("unknown");
+ }
+}
+
+
+bool ModList::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::ContextMenu) {
+ QContextMenuEvent *contextEvent = static_cast<QContextMenuEvent*>(event);
+ QWidget *object = qobject_cast<QWidget*>(obj);
+ if (object != NULL) {
+ emit requestColumnSelect(object->mapToGlobal(contextEvent->pos()));
+
+ return true;
+ }
+ } else if ((event->type() == QEvent::KeyPress) && (m_Profile != NULL)) {
+ QAbstractItemView *itemView = qobject_cast<QAbstractItemView*>(obj);
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ if ((itemView != NULL) &&
+ (keyEvent->modifiers() == Qt::ControlModifier) &&
+ ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) {
+ QItemSelectionModel *selectionModel = itemView->selectionModel();
+ const QSortFilterProxyModel *proxyModel = qobject_cast<const QSortFilterProxyModel*>(selectionModel->model());
+ int diff = -1;
+ if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) ||
+ ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) {
+ diff = 1;
+ }
+ QModelIndexList rows = selectionModel->selectedRows();
+ if (keyEvent->key() == Qt::Key_Down) {
+ for (int i = 0; i < rows.size() / 2; ++i) {
+ rows.swap(i, rows.size() - i - 1);
+ }
+ }
+ foreach (QModelIndex idx, rows) {
+ if (proxyModel != NULL) {
+ idx = proxyModel->mapToSource(idx);
+ }
+ int newPriority = m_Profile->getModPriority(idx.row()) + diff;
+ if ((newPriority >= 0) && (newPriority < static_cast<int>(m_Profile->numRegularMods()))) {
+ m_Profile->setModPriority(idx.row(), newPriority);
+ notifyChange(idx.row());
+ }
+ }
+ return true;
+ } else if (keyEvent->key() == Qt::Key_Delete) {
+ emit removeSelectedMods();
+/* QItemSelectionModel *selectionModel = itemView->selectionModel();
+ const QSortFilterProxyModel *proxyModel = qobject_cast<const QSortFilterProxyModel*>(selectionModel->model());
+ QModelIndexList rows = selectionModel->selectedRows();
+ foreach (QModelIndex idx, rows) {
+ if (proxyModel != NULL) {
+ idx = proxyModel->mapToSource(idx);
+ }
+ removeRow(idx.row(), QModelIndex());
+ }*/
+ return true;
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
diff --git a/src/modlist.h b/src/modlist.h new file mode 100644 index 00000000..7c37f4d5 --- /dev/null +++ b/src/modlist.h @@ -0,0 +1,230 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MODLIST_H
+#define MODLIST_H
+
+
+#include "categories.h"
+#include "nexusinterface.h"
+#include "modinfo.h"
+#include "profile.h"
+
+#include <QFile>
+#include <QListWidget>
+#include <QNetworkReply>
+#include <QNetworkAccessManager>
+
+#include <set>
+#include <vector>
+#include <QVector>
+
+
+/**
+ * Model presenting an overview of the installed mod
+ * This is used in a view in the main window of MO. It combines general information about
+ * the mods from ModInfo with status information from the Profile
+ **/
+class ModList : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+
+ enum EColumn {
+ COL_NAME,
+ COL_FLAGS,
+ COL_CATEGORY,
+ COL_MODID,
+ COL_VERSION,
+ COL_PRIORITY,
+
+ COL_LASTCOLUMN = COL_PRIORITY
+ };
+
+public:
+
+ /**
+ * @brief constructor
+ * @todo ensure this view works without a profile set, otherwise there are intransparent dependencies on the initialisation order
+ **/
+ ModList(QObject *parent = NULL);
+
+ /**
+ * @brief set the profile used for status information
+ *
+ * @param profile the profile to use
+ **/
+ void setProfile(Profile *profile);
+
+ /**
+ * @brief retrieve the current sorting mode
+ * @note this is used to store the sorting mode between sessions
+ * @return current sorting mode, encoded to be compatible to previous versions
+ **/
+ int getCurrentSortingMode() const;
+
+ /**
+ * @brief force a refresh of the mod list
+ **/
+ void refresh();
+
+ /**
+ * @brief remove the specified mod without asking for confirmation
+ * @param row the row to remove
+ */
+ void removeRowForce(int row);
+
+ void notifyChange(int row);
+
+ static QString getColumnName(int column);
+
+ void changeModPriority(int sourceIndex, int newPriority);
+
+public: // implementation of virtual functions of QAbstractItemModel
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const;
+ virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; }
+ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+ virtual void removeRow(int row, const QModelIndex &parent);
+
+
+ virtual QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const;
+ virtual QModelIndex parent(const QModelIndex &child) const;
+
+public slots:
+
+signals:
+
+ /**
+ * @brief emitted whenever the sorting in the list was changed by the user
+ *
+ * the sorting of the list can only be manually changed if the list is sorted by priority
+ * in which case the move is intended to change the priority of a mod
+ **/
+ void modorder_changed();
+
+ /**
+ * @brief emitted when the model wants a text to be displayed by the UI
+ *
+ * @param message the message to display
+ **/
+ void showMessage(const QString &message);
+
+ /**
+ * @brief signals change to the count of headers
+ */
+ void resizeHeaders();
+
+ /**
+ * @brief requestColumnSelect is emitted whenever the user requested a menu to select visible columns
+ * @param pos the position to display the menu at
+ */
+ void requestColumnSelect(QPoint pos);
+
+ /**
+ * @brief emitted to remove a file origin
+ * @param name name of the orign to remove
+ */
+ void removeOrigin(const QString &name);
+
+ /**
+ * @brief emitted after a mod has been renamed
+ * This signal MUST be used to fix the mod names in profiles (except the active one) and to invalidate/refresh other
+ * structures that may have become invalid with the rename
+ *
+ * @param oldName the old name of the mod
+ * @param newName new name of the mod
+ */
+ void modRenamed(const QString &oldName, const QString &newName);
+
+ /**
+ * @brief emitted whenever a row in the list has changed
+ *
+ * @param row the row that changed
+ * @note this signal must only be emitted if the row really did change.
+ * Slots handling this signal therefore do not have to verify that a change has happened
+ * @note this signal is currently only used in tutorials
+ **/
+ void modlist_changed(int row);
+
+ /**
+ * @brief emitted to have all selected mods deleted
+ */
+ void removeSelectedMods();
+
+protected:
+
+ // event filter, handles event from the header and the tree view itself
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+
+ bool testValid(const QString &modDir);
+
+ void changeModPriority(std::vector<int> sourceIndices, int newPriority);
+
+ QVariant getOverwriteData(int column, int role) const;
+
+ QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const;
+
+ static QString getColumnToolTip(int column);
+
+ ModList::EColumn getEnabledColumn(int index) const;
+
+ QVariant categoryData(int categoryID, int column, int role) const;
+ QVariant modData(int modID, int modelColumn, int role) const;
+
+ bool renameMod(int index, const QString &newName);
+
+private slots:
+
+private:
+
+ struct TModInfo {
+ TModInfo(unsigned int index, ModInfo::Ptr modInfo)
+ : modInfo(modInfo), nameOrder(index) {}
+ ModInfo::Ptr modInfo;
+ unsigned int nameOrder;
+ unsigned int priorityOrder;
+ unsigned int modIDOrder;
+ unsigned int categoryOrder;
+ };
+
+private:
+
+ Profile *m_Profile;
+
+ NexusInterface *m_NexusInterface;
+ std::set<int> m_RequestIDs;
+
+ mutable bool m_Modified;
+
+ QFontMetrics m_FontMetrics;
+
+};
+
+#endif // MODLIST_H
+
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp new file mode 100644 index 00000000..de1e3230 --- /dev/null +++ b/src/modlistsortproxy.cpp @@ -0,0 +1,229 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "modlistsortproxy.h"
+#include "modinfo.h"
+#include "profile.h"
+#include "modlist.h"
+#include <QMenu>
+#include <QCheckBox>
+#include <QWidgetAction>
+#include <QMessageBox>
+
+
+ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent)
+ : QSortFilterProxyModel(parent), m_Profile(profile),
+ m_CategoryFilter(CategoryFactory::CATEGORY_NONE), m_CurrentFilter()
+{
+ m_EnabledColumns.set(ModList::COL_FLAGS);
+ m_EnabledColumns.set(ModList::COL_NAME);
+ m_EnabledColumns.set(ModList::COL_VERSION);
+ m_EnabledColumns.set(ModList::COL_PRIORITY);
+ setDynamicSortFilter(true); // this seems to work without dynamicsortfilter
+ // but I don't know why. This should be necessary
+}
+
+
+void ModListSortProxy::setProfile(Profile *profile)
+{
+ m_Profile = profile;
+}
+
+
+void ModListSortProxy::setCategoryFilter(int category)
+{
+ m_CategoryFilter = category;
+ this->invalidate();
+}
+
+
+Qt::ItemFlags ModListSortProxy::flags(const QModelIndex &modelIndex) const
+{
+ Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex));
+ if (sortColumn() != ModList::COL_PRIORITY) {
+ flags &= ~Qt::ItemIsDragEnabled;
+ }
+ return flags;
+}
+
+
+
+void ModListSortProxy::displayColumnSelection(const QPoint &pos)
+{
+ QMenu menu;
+
+ for (int i = 0; i <= ModList::COL_LASTCOLUMN; ++i) {
+ QCheckBox *checkBox = new QCheckBox(&menu);
+ checkBox->setText(ModList::getColumnName(i));
+ checkBox->setChecked(m_EnabledColumns.test(i) ? Qt::Checked : Qt::Unchecked);
+ QWidgetAction *checkableAction = new QWidgetAction(&menu);
+ checkableAction->setDefaultWidget(checkBox);
+ menu.addAction(checkableAction);
+ }
+ menu.exec(pos);
+ int i = 0;
+
+ emit layoutAboutToBeChanged();
+ m_EnabledColumns.reset();
+ foreach (const QAction *action, menu.actions()) {
+ const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(widgetAction->defaultWidget());
+ if (checkBox != NULL) {
+ m_EnabledColumns.set(i, checkBox->checkState() == Qt::Checked);
+ }
+ }
+ ++i;
+ }
+ emit layoutChanged();
+}
+
+
+void ModListSortProxy::enableAllVisible()
+{
+ if (m_Profile == NULL) return;
+
+ for (int i = 0; i < this->rowCount(); ++i) {
+ int modID = mapToSource(index(i, 0)).row();
+ m_Profile->setModEnabled(modID, true);
+ }
+}
+
+
+void ModListSortProxy::disableAllVisible()
+{
+ if (m_Profile == NULL) return;
+ for (int i = 0; i < this->rowCount(); ++i) {
+ int modID = mapToSource(index(i, 0)).row();
+ m_Profile->setModEnabled(modID, false);
+ }
+}
+
+
+bool ModListSortProxy::lessThan(const QModelIndex &left,
+ const QModelIndex &right) const
+{
+ int leftIndex = left.internalId();
+ int rightIndex = right.internalId();
+ ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex);
+ ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex);
+
+ bool lt = false;
+ switch (left.column()) {
+ case ModList::COL_FLAGS: lt = leftMod->getFlags().size() < rightMod->getFlags().size(); break;
+ case ModList::COL_NAME: lt = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive) < 0; break;
+ case ModList::COL_CATEGORY: {
+ if (leftMod->getPrimaryCategory() < 0) lt = false;
+ else if (rightMod->getPrimaryCategory() < 0) lt = true;
+ else {
+ try {
+ CategoryFactory &categories = CategoryFactory::instance();
+ QString leftCatName = categories.getCategoryName(categories.getCategoryIndex(leftMod->getPrimaryCategory()));
+ QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->getPrimaryCategory()));
+ lt = leftCatName < rightCatName;
+ } catch (const std::exception &e) {
+ qCritical("failed to compare categories: %s", e.what());
+ }
+ }
+ } break;
+ case ModList::COL_MODID: lt = leftMod->getNexusID() < rightMod->getNexusID(); break;
+ case ModList::COL_VERSION: lt = leftMod->getVersion() < rightMod->getVersion(); break;
+ case ModList::COL_PRIORITY: {
+ if (m_Profile != NULL) {
+ int leftPrio = leftMod->getFixedPriority();
+ int rightPrio = rightMod->getFixedPriority();
+ if (leftPrio == INT_MIN) leftPrio = m_Profile->getModPriority(leftIndex);
+ if (rightPrio == INT_MIN) rightPrio = m_Profile->getModPriority(rightIndex);
+
+ lt = leftPrio < rightPrio;
+ } else {
+ lt = leftMod->name() < rightMod->name();
+ }
+ } break;
+ }
+ return lt;
+}
+
+
+void ModListSortProxy::updateFilter(const QString &filter)
+{
+ m_CurrentFilter = filter;
+ invalidateFilter();
+}
+
+
+bool ModListSortProxy::hasConflictFlag(const std::vector<ModInfo::EFlag> &flags) const
+{
+ foreach (ModInfo::EFlag flag, flags) {
+ if ((flag == ModInfo::FLAG_CONFLICT_MIXED) ||
+ (flag == ModInfo::FLAG_CONFLICT_OVERWRITE) ||
+ (flag == ModInfo::FLAG_CONFLICT_OVERWRITTEN) ||
+ (flag == ModInfo::FLAG_CONFLICT_REDUNDANT)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool ModListSortProxy::filterAcceptsRow(int row, const QModelIndex&) const
+{
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+
+ if (!m_CurrentFilter.isEmpty() &&
+ !modInfo->name().contains(m_CurrentFilter, Qt::CaseInsensitive)) {
+ return false;
+ }
+
+ bool modEnabled = m_Profile != NULL ? m_Profile->modEnabled(row) : false;
+ return ((m_CategoryFilter == CategoryFactory::CATEGORY_NONE) ||
+ ((m_CategoryFilter < CategoryFactory::CATEGORY_SPECIAL_FIRST) && (modInfo->categorySet(m_CategoryFilter))) ||
+ ((m_CategoryFilter == CategoryFactory::CATEGORY_SPECIAL_CHECKED) && modEnabled) ||
+ ((m_CategoryFilter == CategoryFactory::CATEGORY_SPECIAL_UNCHECKED) && !modEnabled) ||
+ ((m_CategoryFilter == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE) && modInfo->updateAvailable()) ||
+ ((m_CategoryFilter == CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY) && (modInfo->getCategories().size() == 0)) ||
+ ((m_CategoryFilter == CategoryFactory::CATEGORY_SPECIAL_CONFLICT) && (hasConflictFlag(modInfo->getFlags()))));
+}
+
+
+/*bool ModListSortProxy::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
+{
+ return m_EnabledColumns.test(source_column);
+}*/
+
+
+bool ModListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ if ((row == -1) && (column == -1)) {
+ return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
+ }
+ // in the regular model, when dropping between rows, the row-value passed to
+ // the sourceModel is inconsistent between ascending and descending ordering.
+ // This should fix that
+ if (sortOrder() == Qt::DescendingOrder) {
+ --row;
+ }
+
+ QModelIndex proxyIndex = index(row, column, parent);
+ QModelIndex sourceIndex = mapToSource(proxyIndex);
+ return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(),
+ sourceIndex.parent());
+}
diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h new file mode 100644 index 00000000..aad87f06 --- /dev/null +++ b/src/modlistsortproxy.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MODLISTSORTPROXY_H
+#define MODLISTSORTPROXY_H
+
+#include <QSortFilterProxyModel>
+#include <bitset>
+#include "modlist.h"
+
+class Profile;
+
+class ModListSortProxy : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+
+ explicit ModListSortProxy(Profile *profile, QObject *parent = 0);
+
+ void setProfile(Profile *profile);
+
+ void setCategoryFilter(int category);
+
+ virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const;
+ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent);
+
+ /**
+ * @brief enable all mods visible under the current filter
+ **/
+ void enableAllVisible();
+
+ /**
+ * @brief disable all mods visible under the current filter
+ **/
+ void disableAllVisible();
+
+public slots:
+
+ void displayColumnSelection(const QPoint &pos);
+ void updateFilter(const QString &filter);
+
+protected:
+
+ virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+ virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const;
+// virtual bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const;
+
+private:
+
+ bool hasConflictFlag(const std::vector<ModInfo::EFlag> &flags) const;
+
+private:
+
+ Profile *m_Profile;
+
+ int m_CategoryFilter;
+ std::bitset<ModList::COL_LASTCOLUMN + 1> m_EnabledColumns;
+ QString m_CurrentFilter;
+
+};
+
+#endif // MODLISTSORTPROXY_H
diff --git a/src/motddialog.cpp b/src/motddialog.cpp new file mode 100644 index 00000000..fbadf5fd --- /dev/null +++ b/src/motddialog.cpp @@ -0,0 +1,48 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "motddialog.h" +#include "bbcode.h" +#include "utility.h" +#include "ui_motddialog.h" +#include <Shlwapi.h> + +MotDDialog::MotDDialog(const QString &message, QWidget *parent) + : QDialog(parent), ui(new Ui::MotDDialog) +{ + ui->setupUi(this); + ui->motdView->setHtml(BBCode::convertToHTML(message)); + ui->motdView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + connect(ui->motdView->page(), SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); +} + +MotDDialog::~MotDDialog() +{
+ delete ui;
+}
+
+void MotDDialog::on_okButton_clicked()
+{ + this->close(); +} + +void MotDDialog::linkClicked(const QUrl &url) +{ + ::ShellExecuteW(NULL, L"open", ToWString(url.toString()).c_str(), NULL, NULL, SW_SHOWNORMAL); +} diff --git a/src/motddialog.h b/src/motddialog.h new file mode 100644 index 00000000..1e9a5078 --- /dev/null +++ b/src/motddialog.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef MOTDDIALOG_H
+#define MOTDDIALOG_H + +#include <QDialog> +#include <QUrl> + +namespace Ui { +class MotDDialog; +}
+
+class MotDDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit MotDDialog(const QString &message, QWidget *parent = 0);
+ ~MotDDialog();
+ +private slots: + void on_okButton_clicked(); + void linkClicked(const QUrl &url); + +private: + Ui::MotDDialog *ui; +};
+
+#endif // MOTDDIALOG_H
diff --git a/src/motddialog.ui b/src/motddialog.ui new file mode 100644 index 00000000..e40cb21f --- /dev/null +++ b/src/motddialog.ui @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MotDDialog</class>
+ <widget class="QDialog" name="MotDDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>483</width>
+ <height>372</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Message of the Day</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWebView" name="motdView">
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>240</red>
+ <green>240</green>
+ <blue>240</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>240</red>
+ <green>240</green>
+ <blue>240</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>240</red>
+ <green>240</green>
+ <blue>240</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="url">
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/nexusdialog.cpp b/src/nexusdialog.cpp new file mode 100644 index 00000000..770b740c --- /dev/null +++ b/src/nexusdialog.cpp @@ -0,0 +1,323 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "nexusdialog.h"
+#include "ui_nexusdialog.h"
+
+#include "messagedialog.h"
+#include "report.h"
+#include "json.h"
+
+#include <utility.h>
+#include <gameinfo.h>
+#include <QNetworkCookieJar>
+#include <QNetworkCookie>
+#include <QMenu>
+#include <QInputDialog>
+#include <QWebHistory>
+
+
+NexusDialog::NexusDialog(NXMAccessManager *accessManager, QWidget *parent)
+ : QDialog(parent), ui(new Ui::NexusDialog),
+ m_AccessManager(accessManager),
+ m_Tutorial(this, "NexusDialog")
+{
+ ui->setupUi(this);
+
+ Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint;
+ Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint;
+ flags = flags & (~helpFlag);
+ setWindowFlags(flags);
+
+ m_Tabs = this->findChild<QTabWidget*>("browserTabWidget");
+
+ m_View = new NexusView(this);
+
+ initTab(m_View);
+
+ m_LoadProgress = this->findChild<QProgressBar*>("loadProgress");
+
+ connect(m_Tabs, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int)));
+
+ m_Tutorial.registerControl();
+}
+
+
+NexusDialog::~NexusDialog()
+{
+
+ delete ui;
+}
+
+void NexusDialog::closeEvent(QCloseEvent *event)
+{
+// m_AccessManager->showCookies();
+ QDialog::closeEvent(event);
+}
+
+void NexusDialog::initTab(NexusView *newView)
+{
+ newView->page()->setNetworkAccessManager(m_AccessManager);
+ newView->page()->setForwardUnsupportedContent(true);
+
+ connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
+ connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
+ connect(newView, SIGNAL(initTab(NexusView*)), this, SLOT(initTab(NexusView*)));
+ connect(newView, SIGNAL(startFind()), this, SLOT(startSearch()));
+ connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
+ connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl)));
+ connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest)));
+
+ connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
+ connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, SLOT(requestNXMDownload(QString)));
+
+ ui->backBtn->setEnabled(false);
+ ui->fwdBtn->setEnabled(false);
+ m_Tabs->addTab(newView, tr("new"));
+
+ m_View->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ m_View->settings()->setAttribute(QWebSettings::AutoLoadImages, true);
+}
+
+
+void NexusDialog::openInNewTab(const QUrl &url)
+{
+ NexusView *newView = new NexusView(this);
+
+ initTab(newView);
+ newView->setUrl(url);
+}
+
+
+NexusView *NexusDialog::getCurrentView()
+{
+ return qobject_cast<NexusView*>(m_Tabs->currentWidget());
+}
+
+
+void NexusDialog::urlChanged(const QUrl&)
+{
+ NexusView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ ui->backBtn->setEnabled(currentView->history()->canGoBack());
+ ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
+ }
+}
+
+
+void NexusDialog::openUrl(const QString &url)
+{
+ m_Url = url;
+ if (m_Url.startsWith("www")) {
+ m_Url.prepend("http://");
+ }
+}
+
+void NexusDialog::login(const QString &username, const QString &password)
+{
+ m_AccessManager->login(username, password);
+
+ connect(m_AccessManager, SIGNAL(loginSuccessful(bool)), this, SLOT(loginFinished(bool)));
+ connect(m_AccessManager, SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
+}
+
+
+void NexusDialog::loginFailed(const QString &message)
+{
+ if (this->isVisible()) {
+ MessageDialog::showMessage(tr("login failed: %1").arg(message), this);
+ }
+}
+
+
+void NexusDialog::loginFinished(bool necessary)
+{
+ if (necessary && this->isVisible()) {
+ MessageDialog::showMessage(tr("login successful"), this);
+ }
+ loadNexus();
+ emit loginSuccessful(necessary);
+}
+
+
+void NexusDialog::loadNexus()
+{
+ m_View->load(QUrl(m_Url));
+}
+
+
+void NexusDialog::progress(int value)
+{
+ m_LoadProgress->setValue(value);
+ m_LoadProgress->setVisible(value != 100);
+}
+
+
+void NexusDialog::titleChanged(const QString &title)
+{
+ NexusView *view = qobject_cast<NexusView*>(sender());
+ for (int i = 0; i < m_Tabs->count(); ++i) {
+ if (m_Tabs->widget(i) == view) {
+ m_Tabs->setTabText(i, title.mid(0, 15));
+ m_Tabs->setTabToolTip(i, title);
+ }
+ }
+}
+
+
+QString NexusDialog::guessFileName(const QString &url)
+{
+ QRegExp uploadsExp(QString("http://.+/uploads/([^/]+)$"));
+ if (uploadsExp.indexIn(url) != -1) {
+ // these seem to be premium downloads
+ return uploadsExp.cap(1);
+ }
+
+ QRegExp filesExp(QString("http://.+\\?file=([^&]+)"));
+ if (filesExp.indexIn(url) != -1) {
+ // a regular manual download?
+ return filesExp.cap(1);
+ }
+ return "unknown";
+}
+
+void NexusDialog::unsupportedContent(QNetworkReply *reply)
+{
+ try {
+ QWebPage *page = qobject_cast<QWebPage*>(sender());
+ if (page == NULL) {
+ qCritical("sender not a page");
+ return;
+ }
+ NexusView *view = qobject_cast<NexusView*>(page->view());
+ if (view == NULL) {
+ qCritical("no view?");
+ return;
+ }
+
+ int modID = 0;
+ QString fileName = guessFileName(reply->url().toString());
+ qDebug("unsupported: %s - %s", view->url().toString().toUtf8().constData(), reply->url().toString().toUtf8().constData());
+ QRegExp sourceExp(QString("http://[a-zA-Z0-9.]*.nexusmods.com/.*"), Qt::CaseInsensitive);
+ QRegExp modidExp(QString("http://([a-zA-Z0-9]*).nexusmods.com/downloads/file.php\\?id=(\\d+)"), Qt::CaseInsensitive);
+ QRegExp modidAltExp(QString("http://([a-zA-Z0-9]*).nexusmods.com/mods/(\\d+)"), Qt::CaseInsensitive);
+ if (sourceExp.indexIn(reply->url().toString()) != -1) {
+ if (modidExp.indexIn(view->url().toString()) != -1) {
+ modID = modidExp.cap(2).toInt();
+ } else if (modidAltExp.indexIn(view->url().toString()) != -1) {
+ modID = modidAltExp.cap(2).toInt();
+ } else {
+ modID = view->getLastSeenModID();
+ }
+ } else {
+ qDebug("not a nexus download: %s", reply->url().toString().toUtf8().constData());
+ return;
+ }
+ emit requestDownload(reply, modID, fileName);
+ } catch (const std::exception &e) {
+ if (isVisible()) {
+ MessageDialog::showMessage(tr("failed to start download"), this);
+ }
+ qCritical("exception downloading unsupported content: %s", e.what());
+ }
+}
+
+
+void NexusDialog::downloadRequested(const QNetworkRequest &request)
+{
+ qCritical("download request %s ignored", request.url().toString().toUtf8().constData());
+}
+
+
+void NexusDialog::requestNXMDownload(const QString&)
+{
+ if (isVisible()) {
+ MessageDialog::showMessage(tr("Download started"), this);
+ }
+}
+
+
+void NexusDialog::tabCloseRequested(int index)
+{
+ if (m_Tabs->count() == 1) {
+ this->close();
+ } else {
+ m_Tabs->widget(index)->deleteLater();
+ m_Tabs->removeTab(index);
+ }
+}
+
+
+void NexusDialog::on_browserTabWidget_customContextMenuRequested(const QPoint&)
+{
+}
+
+void NexusDialog::on_backBtn_clicked()
+{
+ NexusView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->back();
+ }
+}
+
+void NexusDialog::on_fwdBtn_clicked()
+{
+ NexusView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->forward();
+ }
+}
+
+
+void NexusDialog::startSearch()
+{
+ ui->searchEdit->setFocus();
+}
+
+
+void NexusDialog::on_modIDEdit_returnPressed()
+{
+ QString url = ToQString(GameInfo::instance().getNexusPage()).append("/downloads/file.php?id=%1").arg(ui->modIDEdit->text());
+ NexusView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->load(QUrl(url));
+ }
+}
+
+void NexusDialog::on_searchEdit_returnPressed()
+{
+ NexusView *currentView = getCurrentView();
+ if (currentView != NULL) {
+ currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument);
+ }
+}
+
+void NexusDialog::on_browserTabWidget_currentChanged(QWidget *current)
+{
+ NexusView *currentView = qobject_cast<NexusView*>(current);
+ if (currentView != NULL) {
+ ui->backBtn->setEnabled(currentView->history()->canGoBack());
+ ui->fwdBtn->setEnabled(currentView->history()->canGoForward());
+ }
+}
+
+void NexusDialog::on_refreshBtn_clicked()
+{
+ getCurrentView()->reload();
+}
diff --git a/src/nexusdialog.h b/src/nexusdialog.h new file mode 100644 index 00000000..041b5e7c --- /dev/null +++ b/src/nexusdialog.h @@ -0,0 +1,160 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef NEXUSDIALOG_H
+#define NEXUSDIALOG_H
+
+#include "nexusview.h"
+#include "nxmaccessmanager.h"
+#include "tutorialcontrol.h"
+#include <QDialog>
+#include <QProgressBar>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QTimer>
+#include <QWebView>
+#include <QQueue>
+#include <QTabWidget>
+#include <QAtomicInt>
+
+
+namespace Ui {
+ class NexusDialog;
+}
+
+
+/**
+ * @brief a dialog containing a webbrowser that is intended to browse the nexus network
+ **/
+class NexusDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param accessManager the access manager to use for network requests
+ * @param parent parent widget
+ **/
+ explicit NexusDialog(NXMAccessManager *accessManager, QWidget *parent = 0);
+ ~NexusDialog();
+
+ /**
+ * @brief set the url to open. If automatic login is enabled, the url is opened after login
+ *
+ * @param url the url to open
+ **/
+ void openUrl(const QString &url);
+
+ /**
+ * @brief log-in to the nexus page.
+ *
+ * After successful login, loadNexus() is automatically called. If the user is already
+ * logged in, this happens immediately
+ *
+ * @param username the user name to log in as
+ * @param password the user password
+ **/
+ void login(const QString &username, const QString &password);
+
+ /**
+ * @brief load the page set with openUrl()
+ **/
+ void loadNexus();
+
+signals:
+
+ /**
+ * @brief emitted when the user caused a download
+ *
+ * @param reply the network-reply transmitting the file
+ * @param modID mod id of the file requested
+ * @param fileName suggested filename
+ **/
+ void requestDownload(QNetworkReply *reply, int modID, const QString &fileName);
+
+ void loginSuccessful(bool necessary);
+
+protected:
+
+ virtual void closeEvent(QCloseEvent *);
+
+private slots:
+
+ void loginFailed(const QString &message);
+ void loginFinished(bool necessary);
+// void loginError(QNetworkReply::NetworkError errorCode);
+// void loginTimeout();
+
+ void initTab(NexusView *newView);
+ void openInNewTab(const QUrl &url);
+
+ void progress(int value);
+
+ void titleChanged(const QString &title);
+ void requestNXMDownload(const QString &url);
+ void unsupportedContent(QNetworkReply *reply);
+ void downloadRequested(const QNetworkRequest &request);
+
+
+ void tabCloseRequested(int index);
+
+// void openByModID();
+ void on_browserTabWidget_customContextMenuRequested(const QPoint &pos);
+
+ void urlChanged(const QUrl &url);
+
+ void on_backBtn_clicked();
+
+ void on_fwdBtn_clicked();
+
+ void on_modIDEdit_returnPressed();
+
+ void on_searchEdit_returnPressed();
+
+ void startSearch();
+
+ void on_browserTabWidget_currentChanged(QWidget *arg1);
+
+ void on_refreshBtn_clicked();
+
+private:
+
+ QString guessFileName(const QString &url);
+
+ NexusView *getCurrentView();
+
+private:
+
+ Ui::NexusDialog *ui;
+
+ TutorialControl m_Tutorial;
+
+ QString m_Url;
+
+ QTabWidget *m_Tabs;
+ NexusView *m_View;
+ QProgressBar *m_LoadProgress;
+ NXMAccessManager *m_AccessManager;
+
+};
+
+#endif // NEXUSDIALOG_H
diff --git a/src/nexusdialog.ui b/src/nexusdialog.ui new file mode 100644 index 00000000..10b08d92 --- /dev/null +++ b/src/nexusdialog.ui @@ -0,0 +1,306 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NexusDialog</class>
+ <widget class="QDialog" name="NexusDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1008</width>
+ <height>750</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Nexus</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="toolBar" native="true">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>22</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>226</red>
+ <green>226</green>
+ <blue>226</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>106</red>
+ <green>106</green>
+ <blue>106</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>199</red>
+ <green>199</green>
+ <blue>199</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>81</red>
+ <green>81</green>
+ <blue>81</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>226</red>
+ <green>226</green>
+ <blue>226</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>106</red>
+ <green>106</green>
+ <blue>106</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>199</red>
+ <green>199</green>
+ <blue>199</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>81</red>
+ <green>81</green>
+ <blue>81</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>106</red>
+ <green>106</green>
+ <blue>106</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>120</red>
+ <green>120</green>
+ <blue>120</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>81</red>
+ <green>81</green>
+ <blue>81</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>81</red>
+ <green>81</green>
+ <blue>81</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="backBtn">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/previous</normaloff>:/MO/gui/previous</iconset>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="fwdBtn">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/next</normaloff>:/MO/gui/next</iconset>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="refreshBtn">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/refresh</normaloff>:/MO/gui/refresh</iconset>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Mod ID</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="modIDEdit">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="searchEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="browserTabWidget">
+ <property name="contextMenuPolicy">
+ <enum>Qt::DefaultContextMenu</enum>
+ </property>
+ <property name="tabsClosable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="loadProgress">
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp new file mode 100644 index 00000000..c250a7d2 --- /dev/null +++ b/src/nexusinterface.cpp @@ -0,0 +1,466 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "nexusinterface.h"
+#include "nxmaccessmanager.h"
+#include "utility.h"
+#include "json.h"
+#include "selectiondialog.h"
+#include <utility.h>
+#include <regex>
+
+using QtJson::Json;
+
+
+NexusBridge::NexusBridge()
+{
+ m_Interface = NexusInterface::instance();
+}
+
+
+void NexusBridge::requestDescription(int modID, QVariant userData, const QString &url)
+{
+ m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, url));
+}
+
+void NexusBridge::requestFiles(int modID, QVariant userData, const QString &url)
+{
+ m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, url));
+}
+
+void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData, const QString &url)
+{
+ m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, url));
+}
+
+void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData, const QString &url)
+{
+ m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, url));
+}
+
+void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData, const QString &url)
+{
+ m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, url));
+}
+
+void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmDescriptionAvailable(modID, userData, resultData);
+ }
+}
+
+void NexusBridge::nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmFilesAvailable(modID, userData, resultData);
+ }
+}
+
+void NexusBridge::nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmFileInfoAvailable(modID, fileID, userData, resultData);
+ }
+}
+
+void NexusBridge::nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmDownloadURLsAvailable(modID, fileID, userData, resultData);
+ }
+}
+
+void NexusBridge::nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmEndorsementToggled(modID, userData, resultData);
+ }
+}
+
+void NexusBridge::nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorMessage)
+{
+ std::set<int>::iterator iter = m_RequestIDs.find(requestID);
+ if (iter != m_RequestIDs.end()) {
+ m_RequestIDs.erase(iter);
+ emit nxmRequestFailed(modID, userData, errorMessage);
+ }
+}
+
+
+QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0);
+
+
+NexusInterface::NexusInterface()
+ : m_NMMVersion()
+{
+ m_AccessManager = new NXMAccessManager(this);
+
+ m_DiskCache = new QNetworkDiskCache(this);
+ connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
+}
+
+
+NXMAccessManager *NexusInterface::getAccessManager()
+{
+ return m_AccessManager;
+}
+
+
+NexusInterface *NexusInterface::s_Instance = NULL;
+
+
+NexusInterface *NexusInterface::instance()
+{
+ if (s_Instance == NULL) {
+ s_Instance = new NexusInterface;
+ }
+ return s_Instance;
+}
+
+
+void NexusInterface::setCacheDirectory(const QString &directory)
+{
+ m_DiskCache->setCacheDirectory(directory);
+ m_AccessManager->setCache(m_DiskCache);
+}
+
+
+void NexusInterface::setNMMVersion(const QString &nmmVersion)
+{
+ m_NMMVersion = nmmVersion;
+}
+
+
+void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query)
+{
+ static std::tr1::regex exp("^([a-zA-Z0-9_\\- ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*");
+// std::tr1::match_results<std::string::const_iterator> result;
+ QByteArray fileNameUTF8 = fileName.toUtf8();
+ std::tr1::cmatch result;
+ if (std::tr1::regex_search(fileNameUTF8.constData(), result, exp)) {
+ modName = QString::fromUtf8(result[1].str().c_str());
+ modName = modName.replace('_', ' ').trimmed();
+
+ std::string candidate = result[3].str();
+ std::string candidate2 = result[2].str();
+ if (candidate2.length() != 0 && (candidate2.find_last_of("VvRr") == std::string::npos)) {
+ // well, that second match might be an id too...
+ unsigned offset = strspn(candidate2.c_str(), "-_ ");
+ if (offset < candidate2.length() && query) {
+ SelectionDialog selection(tr("Failed to guess mod id for \"%1\", please pick the correct one").arg(fileName));
+ QString r2Highlight(fileName);
+ r2Highlight.insert(result.position(2) + result.length(2), "* ").insert(result.position(2) + offset, " *");
+ QString r3Highlight(fileName);
+ r3Highlight.insert(result.position(3) + result.length(3), "* ").insert(result.position(3), " *");
+
+ selection.addChoice(candidate.c_str(), r3Highlight, strtol(candidate.c_str(), NULL, 10));
+ selection.addChoice(candidate2.c_str() + offset, r2Highlight, abs(strtol(candidate2.c_str() + offset, NULL, 10)));
+ if (selection.exec() == QDialog::Accepted) {
+ modID = selection.getChoiceData().toInt();
+ } else {
+ modID = -1;
+ }
+ } else {
+ modID = -1;
+ }
+ } else {
+ modID = strtol(candidate.c_str(), NULL, 10);
+ }
+ qDebug("mod id guessed: %s -> %d", qPrintable(fileName), modID);
+ } else {
+ modName.clear();
+ modID = -1;
+ }
+}
+
+
+int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, url);
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant,int)),
+ receiver, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+int NexusInterface::requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modIDs, NXMRequestInfo::TYPE_GETUPDATES, userData, url);
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmUpdatesAvailable(std::vector<int>,QVariant,QVariant,int)),
+ receiver, SLOT(nxmUpdatesAvailable(std::vector<int>,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, url);
+ m_RequestQueue.enqueue(requestInfo);
+ connect(this, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant,int)),
+ receiver, SLOT(nxmFilesAvailable(int,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, url);
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmFileInfoAvailable(int,int,QVariant,QVariant,int)),
+ receiver, SLOT(nxmFileInfoAvailable(int,int,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, url);
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)),
+ receiver, SLOT(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+int NexusInterface::requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &url)
+{
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, url);
+ requestInfo.m_Endorse = endorse;
+ m_RequestQueue.enqueue(requestInfo);
+
+ connect(this, SIGNAL(nxmEndorsementToggled(int,QVariant,QVariant,int)),
+ receiver, SLOT(nxmEndorsementToggled(int,QVariant,QVariant,int)), Qt::UniqueConnection);
+
+ connect(this, SIGNAL(nxmRequestFailed(int,QVariant,int,QString)),
+ receiver, SLOT(nxmRequestFailed(int,QVariant,int,QString)), Qt::UniqueConnection);
+
+ nextRequest();
+ return requestInfo.m_ID;
+}
+
+
+void NexusInterface::nextRequest()
+{
+ if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS) || (m_RequestQueue.isEmpty())) {
+ return;
+ }
+
+ NXMRequestInfo info = m_RequestQueue.dequeue();
+ info.m_Timeout = new QTimer(this);
+ info.m_Timeout->setInterval(60000);
+
+ QString url;
+ switch (info.m_Type) {
+ case NXMRequestInfo::TYPE_DESCRIPTION: {
+ url = QString("%1/Mods/%2/").arg(info.m_URL).arg(info.m_ModID);
+ } break;
+ case NXMRequestInfo::TYPE_FILES: {
+ url = QString("%1/Files/indexfrommod/%2/").arg(info.m_URL).arg(info.m_ModID);
+ } break;
+ case NXMRequestInfo::TYPE_FILEINFO: {
+ url = QString("%1/Files/%2/").arg(info.m_URL).arg(info.m_FileID);
+ } break;
+ case NXMRequestInfo::TYPE_DOWNLOADURL: {
+ url = QString("%1/Files/download/%2").arg(info.m_URL).arg(info.m_FileID);
+ } break;
+ case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: {
+ url = QString("%1/Mods/toggleendorsement/%2?lvote=%3").arg(info.m_URL).arg(info.m_ModID).arg(!info.m_Endorse);
+ } break;
+ case NXMRequestInfo::TYPE_GETUPDATES: {
+ QString modIDList = VectorJoin<int>(info.m_ModIDList, ",");
+ modIDList = "[" + modIDList + "]";
+ url = QString("%1/Mods/GetUpdates?ModList=%2").arg(info.m_URL).arg(modIDList);
+ } break;
+ }
+
+/*
+ /// <summary>
+ /// Finds the mods containing the given search terms.
+ /// </summary>
+ /// <param name="p_strModNameSearchString">The terms to use to search for mods.</param>
+ /// <param name="p_strType">Whether the returned mods' names should include all of
+ /// the given search terms, or any of the terms.</param>
+ /// <returns>The mod info for the mods matching the given search criteria.</returns>
+ [OperationContract]
+ [WebGet(
+ BodyStyle = WebMessageBodyStyle.Bare,
+ UriTemplate = "Mods/?Find&name={p_strModNameSearchString}&type={p_strType}",
+ ResponseFormat = WebMessageFormat.Json)]
+ List<NexusModInfo> FindMods(string p_strModNameSearchString, string p_strType);
+
+
+
+*/
+
+
+ QNetworkRequest request(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml");
+ request.setRawHeader("User-Agent", QString("Mod Organizer v0.12.0 (compatible to Nexus Client v%1)").arg(m_NMMVersion).toUtf8());
+
+ info.m_Reply = m_AccessManager->get(request);
+
+ connect(info.m_Reply, SIGNAL(finished()), this, SLOT(requestFinished()));
+ connect(info.m_Reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError)));
+ connect(info.m_Timeout, SIGNAL(timeout()), this, SLOT(requestTimeout()));
+ info.m_Timeout->start();
+ m_ActiveRequest.push_back(info);
+}
+
+
+void NexusInterface::downloadRequestedNXM(const QString &url)
+{
+ emit requestNXMDownload(url);
+}
+
+
+void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
+{
+ QNetworkReply *reply = iter->m_Reply;
+
+ if (reply->error() != QNetworkReply::NoError) {
+ qWarning("request failed: %s", reply->errorString().toUtf8().constData());
+ emit nxmRequestFailed(iter->m_ModID, iter->m_UserData, iter->m_ID, reply->errorString());
+ } else {
+ QByteArray data = reply->readAll();
+ if (data.isNull() || data.isEmpty() || (strcmp(data.constData(), "null") == 0)) {
+ QString nexusError(reply->rawHeader("NexusErrorInfo"));
+ if (nexusError.length() == 0) {
+ nexusError = tr("empty response");
+ }
+
+ emit nxmRequestFailed(iter->m_ModID, iter->m_UserData, iter->m_ID, nexusError);
+ } else {
+ bool ok;
+ QVariant result = Json::parse(data, ok);
+ if (result.isValid() && ok) {
+ switch (iter->m_Type) {
+ case NXMRequestInfo::TYPE_DESCRIPTION: {
+ emit nxmDescriptionAvailable(iter->m_ModID, iter->m_UserData, result, iter->m_ID);
+ } break;
+ case NXMRequestInfo::TYPE_FILES: {
+ emit nxmFilesAvailable(iter->m_ModID, iter->m_UserData, result, iter->m_ID);
+ } break;
+ case NXMRequestInfo::TYPE_FILEINFO: {
+ emit nxmFileInfoAvailable(iter->m_ModID, iter->m_FileID, iter->m_UserData, result, iter->m_ID);
+ } break;
+ case NXMRequestInfo::TYPE_DOWNLOADURL: {
+ emit nxmDownloadURLsAvailable(iter->m_ModID, iter->m_FileID, iter->m_UserData, result, iter->m_ID);
+ } break;
+ case NXMRequestInfo::TYPE_GETUPDATES: {
+ emit nxmUpdatesAvailable(iter->m_ModIDList, iter->m_UserData, result, iter->m_ID);
+ } break;
+ case NXMRequestInfo::TYPE_TOGGLEENDORSEMENT: {
+ emit nxmEndorsementToggled(iter->m_ModID, iter->m_UserData, result, iter->m_ID);
+ } break;
+ }
+ } else {
+ emit nxmRequestFailed(iter->m_ModID, iter->m_UserData, iter->m_ID, tr("invalid response"));
+ }
+ }
+ }
+}
+
+
+void NexusInterface::requestFinished()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
+ for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); iter != m_ActiveRequest.end(); ++iter) {
+ if (iter->m_Reply == reply) {
+ iter->m_Timeout->stop();
+ iter->m_Timeout->deleteLater();
+ requestFinished(iter);
+ iter->m_Reply->deleteLater();
+ m_ActiveRequest.erase(iter);
+ nextRequest();
+ return;
+ }
+ }
+}
+
+
+void NexusInterface::requestError(QNetworkReply::NetworkError)
+{
+ QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
+ if (reply == NULL) {
+ qWarning("invalid sender type");
+ return;
+ }
+
+ qCritical("request error: %s", reply->errorString().toUtf8().constData());
+}
+
+
+void NexusInterface::requestTimeout()
+{
+ QTimer *timer = qobject_cast<QTimer*>(sender());
+ if (timer == NULL) {
+ qWarning("invalid sender type");
+ return;
+ }
+ qWarning("request timeout");
+ for (std::list<NXMRequestInfo>::iterator iter = m_ActiveRequest.begin(); iter != m_ActiveRequest.end(); ++iter) {
+ if (iter->m_Timeout == timer) {
+ // this abort causes a "request failed" which cleans up the rest
+ iter->m_Reply->abort();
+ return;
+ }
+ }
+}
diff --git a/src/nexusinterface.h b/src/nexusinterface.h new file mode 100644 index 00000000..0e6c0eeb --- /dev/null +++ b/src/nexusinterface.h @@ -0,0 +1,327 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef NEXUSINTERFACE_H
+#define NEXUSINTERFACE_H
+
+
+#include "nxmaccessmanager.h"
+
+#include "utility.h"
+#include <gameinfo.h>
+#include <versioninfo.h>
+#include <QNetworkReply>
+#include <QNetworkDiskCache>
+#include <QQueue>
+#include <QVariant>
+#include <QTimer>
+#include <list>
+#include <set>
+
+
+class NexusInterface;
+
+
+/**
+ * @brief convenience class to make nxm requests easier
+ * usually, all objects that started a nxm request will be signaled if one finished.
+ * Therefore, the objects need to store the id of the requests they started and then filter
+ * the result.
+ * NexusBridge does this automatically. Users connect to the signals of NexusBridge they intend
+ * to handle and only receive the signals the caused
+ **/
+class NexusBridge : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ NexusBridge();
+
+ /**
+ * @brief request description for a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ **/
+ void requestDescription(int modID, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request a list of the files belonging to a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ **/
+ void requestFiles(int modID, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request info about a single file of a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param fileID id of the file the caller is interested in
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ **/
+ void requestFileInfo(int modID, int fileID, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request the download url of a file
+ *
+ * @param modID id of the mod caller is interested in
+ * @param fileID id of the file the caller is interested in
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ **/
+ void requestDownloadURL(int modID, int fileID, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief requestToggleEndorsement
+ * @param modID
+ * @param userData
+ * @param url
+ */
+ void requestToggleEndorsement(int modID, bool endorse, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+signals:
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData);
+ void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData);
+ void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
+ void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
+ void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData);
+ void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage);
+
+public slots:
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+ void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+ void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorMessage);
+
+private:
+
+ NexusInterface *m_Interface;
+ std::set<int> m_RequestIDs;
+
+};
+
+
+/**
+ * @brief Makes asynchronous requests to the nexus API
+ *
+ * This class can be used to make asynchronous requests to the Nexus API.
+ * Currently, responses are sent to all receivers that have sent a request of the relevant type, so the
+ * recipient has to filter the response by the id returned when making the request
+ **/
+class NexusInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static NexusInterface *instance();
+
+ /**
+ * @return the access manager object used to connect to nexus
+ **/
+ NXMAccessManager *getAccessManager();
+
+ /**
+ * @brief request description for a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ **/
+ int requestDescription(int modID, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request nexus descriptions for multiple mods at once
+ * @param modIDs a list of ids of mods the caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ */
+ int requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request a list of the files belonging to a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ **/
+ int requestFiles(int modID, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request info about a single file of a mod
+ *
+ * @param modID id of the mod caller is interested in
+ * @param fileID id of the file the caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ **/
+ int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief request the download url of a file
+ *
+ * @param modID id of the mod caller is interested in
+ * @param fileID id of the file the caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ **/
+ int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @brief toggle endorsement state of the mod
+ * @param modID id of the mod
+ * @param endorse true if the mod should be endorsed, false for un-endorse
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @param url the url to request from
+ * @return int an id to identify the request
+ */
+ int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData,
+ const QString &url = ToQString(GameInfo::instance().getNexusInfoUrl()));
+
+ /**
+ * @param directory the directory to store cache files
+ **/
+ void setCacheDirectory(const QString &directory);
+
+ /**
+ * MO has to send a "Nexus Client Vx.y.z" as part of the user agent to be allowed to use the API
+ * @param nmmVersion the version of nmm to impersonate
+ **/
+ void setNMMVersion(const QString &nmmVersion);
+
+public:
+
+ /**
+ * @brief guess the mod id from a filename as delivered by Nexus
+ * @param fileName name of the file
+ * @return the guessed mod id
+ * @note this currently doesn't fit well with the remaining interface but this is the best place for the function
+ */
+ static void interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query);
+
+signals:
+
+ void requestNXMDownload(const QString &url);
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int requestID);
+ void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+ void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+ void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorString);
+
+private slots:
+
+ void requestFinished();
+ void requestError(QNetworkReply::NetworkError error);
+ void requestTimeout();
+
+ void downloadRequestedNXM(const QString &url);
+
+private:
+
+ struct NXMRequestInfo {
+ int m_ModID;
+ std::vector<int> m_ModIDList;
+ int m_FileID;
+ QNetworkReply *m_Reply;
+ enum Type {
+ TYPE_DESCRIPTION,
+ TYPE_FILES,
+ TYPE_FILEINFO,
+ TYPE_DOWNLOADURL,
+ TYPE_TOGGLEENDORSEMENT,
+ TYPE_GETUPDATES
+ } m_Type;
+ QVariant m_UserData;
+ QTimer *m_Timeout;
+ QString m_URL;
+ int m_ID;
+ int m_Endorse;
+
+ NXMRequestInfo(int modID, Type type, QVariant userData, const QString &url)
+ : m_ModID(modID), m_FileID(0), m_Reply(NULL), m_Type(type), m_UserData(userData),
+ m_Timeout(NULL), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
+ NXMRequestInfo(std::vector<int> modIDList, Type type, QVariant userData, const QString &url)
+ : m_ModID(-1), m_ModIDList(modIDList), m_FileID(0), m_Reply(NULL), m_Type(type), m_UserData(userData),
+ m_Timeout(NULL), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
+ NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &url)
+ : m_ModID(modID), m_FileID(fileID), m_Reply(NULL), m_Type(type), m_UserData(userData),
+ m_Timeout(NULL), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
+
+ private:
+ static QAtomicInt s_NextID;
+ };
+
+ static const int MAX_ACTIVE_DOWNLOADS = 2;
+
+private:
+
+ NexusInterface();
+ void nextRequest();
+ void requestFinished(std::list<NXMRequestInfo>::iterator iter);
+
+private:
+
+ static NexusInterface *s_Instance;
+
+ QNetworkDiskCache *m_DiskCache;
+
+ NXMAccessManager *m_AccessManager;
+
+ std::list<NXMRequestInfo> m_ActiveRequest;
+ QQueue<NXMRequestInfo> m_RequestQueue;
+
+ QString m_NMMVersion;
+
+};
+
+#endif // NEXUSINTERFACE_H
diff --git a/src/nexusview.cpp b/src/nexusview.cpp new file mode 100644 index 00000000..1099fff2 --- /dev/null +++ b/src/nexusview.cpp @@ -0,0 +1,87 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "nexusview.h"
+
+#include <QEvent>
+#include <QKeyEvent>
+#include <QWebFrame>
+#include <QWebElement>
+#include <QNetworkDiskCache>
+#include <QMenu>
+#include <Shlwapi.h>
+#include "utility.h"
+
+NexusView::NexusView(QWidget *parent)
+ : QWebView(parent), m_LastSeenModID(0)
+{
+ installEventFilter(this);
+// this->pageAction(QWebPage::OpenLinkInNewWindow)
+ connect(this, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
+
+ page()->settings()->setMaximumPagesInCache(10);
+}
+
+
+void NexusView::urlChanged(const QUrl &url)
+{
+ QRegExp modidExp(QString("http://([a-zA-Z0-9]*).nexusmods.com/downloads/file.php\\?id=(\\d+)"), Qt::CaseInsensitive);
+ if (modidExp.indexIn(url.toString()) != -1) {
+ m_LastSeenModID = modidExp.cap(2).toInt();
+ }
+}
+
+
+QWebView *NexusView::createWindow(QWebPage::WebWindowType)
+{
+ NexusView *newView = new NexusView(parentWidget());
+ emit initTab(newView);
+ return newView;
+}
+
+
+bool NexusView::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ if (keyEvent->matches(QKeySequence::Find)) {
+ emit startFind();
+ } else if (keyEvent->matches(QKeySequence::FindNext)) {
+ emit findAgain();
+ }
+ } else if (event->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ if (mouseEvent->button() == Qt::MidButton) {
+ mouseEvent->ignore();
+ return true;
+ }
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ if (mouseEvent->button() == Qt::MidButton) {
+ QWebHitTestResult hitTest = page()->frameAt(mouseEvent->pos())->hitTestContent(mouseEvent->pos());
+ if (hitTest.linkUrl().isValid()) {
+ emit openUrlInNewTab(hitTest.linkUrl());
+ }
+ mouseEvent->ignore();
+
+ return true;
+ }
+ }
+ return QWebView::eventFilter(obj, event);
+}
diff --git a/src/nexusview.h b/src/nexusview.h new file mode 100644 index 00000000..f0370d27 --- /dev/null +++ b/src/nexusview.h @@ -0,0 +1,89 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef NEXUSVIEW_H
+#define NEXUSVIEW_H
+
+#include "finddialog.h"
+
+#include <QWebView>
+#include <QWebPage>
+#include <QTabWidget>
+
+/**
+ * @brief web view used to display a nexus page
+ **/
+class NexusView : public QWebView
+{
+ Q_OBJECT
+
+public:
+
+ explicit NexusView(QWidget *parent = 0);
+
+ /**
+ * @return last mod id seen in the url
+ */
+ int getLastSeenModID() const { return m_LastSeenModID; }
+
+signals:
+
+ /**
+ * @brief emitted when the user opens a new window to be displayed in another tab
+ *
+ * @param newView the view for the newly opened window
+ **/
+ void initTab(NexusView *newView);
+
+ /**
+ * @brief emitted when the user requests a link to be opened in a new tab by middle-clicking
+ *
+ * @param url the url to open
+ */
+ void openUrlInNewTab(const QUrl &url);
+
+ /**
+ * @brief Ctrl-f was clicked. The containing dialog should activate its find-facility
+ */
+ void startFind();
+
+ /**
+ * @brief F3 was pressed. The containing dialog should search again
+ */
+ void findAgain();
+
+protected:
+
+ virtual QWebView *createWindow(QWebPage::WebWindowType type);
+
+ virtual bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+
+ void urlChanged(const QUrl &url);
+
+private:
+
+ QString m_FindPattern;
+ bool m_MiddleClick;
+ int m_LastSeenModID;
+
+};
+
+#endif // NEXUSVIEW_H
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp new file mode 100644 index 00000000..55fcf0f7 --- /dev/null +++ b/src/nxmaccessmanager.cpp @@ -0,0 +1,153 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "nxmaccessmanager.h"
+#include "nxmurl.h"
+#include "report.h"
+#include "utility.h"
+#include "selfupdater.h"
+#include <QMessageBox>
+#include <QNetworkProxy>
+#include <QNetworkRequest>
+#include <QNetworkCookie>
+#include <QNetworkCookieJar>
+#include <gameinfo.h>
+
+
+NXMAccessManager::NXMAccessManager(QObject *parent)
+ : QNetworkAccessManager(parent), m_LoginReply(NULL)
+{
+}
+
+
+QNetworkReply *NXMAccessManager::createRequest(
+ QNetworkAccessManager::Operation operation, const QNetworkRequest &request,
+ QIODevice *device)
+{
+ if (request.url().scheme() != "nxm") {
+ return QNetworkAccessManager::createRequest(operation, request, device);
+ }
+ if (operation == GetOperation) {
+ emit requestNXMDownload(request.url().toString());
+
+ // eat the request, everything else will be done by the download manager
+ return QNetworkAccessManager::createRequest(QNetworkAccessManager::GetOperation,
+ QNetworkRequest(QUrl()));
+ } else if (operation == PostOperation) {
+ return QNetworkAccessManager::createRequest(operation, request, device);;
+ } else {
+ return QNetworkAccessManager::createRequest(operation, request, device);
+ }
+}
+
+
+void NXMAccessManager::showCookies()
+{
+ QList<QNetworkCookie> cookies = cookieJar()->cookiesForUrl(QUrl(ToQString(GameInfo::instance().getNexusPage())));
+ foreach (QNetworkCookie cookie, cookies) {
+ qDebug("%s - %s", cookie.name().constData(), cookie.value().constData());
+ }
+}
+
+
+bool NXMAccessManager::loggedIn() const
+{
+ return hasLoginCookies();
+}
+
+
+void NXMAccessManager::login(const QString &username, const QString &password)
+{
+ if (m_LoginReply != NULL) {
+ return;
+ }
+
+ if (hasLoginCookies()) {
+ emit loginSuccessful(false);
+ return;
+ }
+
+ m_Username = username;
+ m_Password = password;
+ pageLogin();
+}
+
+
+void NXMAccessManager::pageLogin()
+{
+ QString requestString = QString("http://gatekeeper.nexusmods.com/Sessions/?Login&username=%2&password=%3").arg(m_Username).arg(m_Password);
+
+ QNetworkRequest request(requestString);
+ m_LoginReply = get(request);
+
+ m_LoginTimeout.start();
+ connect(m_LoginReply, SIGNAL(finished()), this, SLOT(loginFinished()));
+ connect(m_LoginReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(loginError(QNetworkReply::NetworkError)));
+}
+
+
+void NXMAccessManager::loginTimeout()
+{
+ emit loginFailed(tr("timeout"));
+ m_LoginReply->deleteLater();
+ m_LoginReply = NULL;
+ m_LoginTimeout.stop();
+ m_Username.clear();
+ m_Password.clear();
+}
+
+
+void NXMAccessManager::loginError(QNetworkReply::NetworkError)
+{
+ emit loginFailed(m_LoginReply->errorString());
+ m_LoginTimeout.stop();
+ m_LoginReply->deleteLater();
+ m_LoginReply = NULL;
+ m_Username.clear();
+ m_Password.clear();
+}
+
+
+bool NXMAccessManager::hasLoginCookies() const
+{
+ bool sidCookie = false;
+ QList<QNetworkCookie> cookies = cookieJar()->cookiesForUrl(QUrl(ToQString(GameInfo::instance().getNexusPage())));
+ foreach (QNetworkCookie cookie, cookies) {
+ if (cookie.name() == "sid") {
+ sidCookie = true;
+ }
+ }
+ return sidCookie;
+}
+
+
+void NXMAccessManager::loginFinished()
+{
+ if (hasLoginCookies()) {
+ emit loginSuccessful(true);
+ } else {
+ emit loginFailed(tr("Please check your password"));
+ }
+
+ m_LoginTimeout.stop();
+ m_LoginReply->deleteLater();
+ m_LoginReply = NULL;
+ m_Username.clear();
+ m_Password.clear();
+}
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h new file mode 100644 index 00000000..8b7e92a8 --- /dev/null +++ b/src/nxmaccessmanager.h @@ -0,0 +1,95 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef NXMACCESSMANAGER_H
+#define NXMACCESSMANAGER_H
+
+
+#include <QNetworkAccessManager>
+#include <QTimer>
+#include <QNetworkReply>
+
+
+/**
+ * @brief access manager extended to handle nxm links
+ **/
+class NXMAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+public:
+
+ explicit NXMAccessManager(QObject *parent);
+
+ bool loggedIn() const;
+
+ void login(const QString &username, const QString &password);
+
+ void showCookies();
+
+signals:
+
+ /**
+ * @brief emitted when a nxm:// link is opened
+ *
+ * @param url the nxm-link
+ **/
+ void requestNXMDownload(const QString &url);
+
+ /**
+ * @brief emitted after a successful login or if login was not necessary
+ *
+ * @param necessary true if a login was necessary and succeeded, false if the user is still logged in
+ **/
+ void loginSuccessful(bool necessary);
+
+ void loginFailed(const QString &message);
+
+ private slots:
+
+// void pageLoginFinished();
+ void loginFinished();
+ void loginError(QNetworkReply::NetworkError errorCode);
+ void loginTimeout();
+
+public slots:
+
+protected:
+
+ virtual QNetworkReply *createRequest(
+ QNetworkAccessManager::Operation operation, const QNetworkRequest &request,
+ QIODevice *device);
+
+private:
+
+ void pageLogin();
+// void dlLogin();
+
+ bool hasLoginCookies() const;
+
+private:
+
+ QTimer m_LoginTimeout;
+ QNetworkReply *m_LoginReply;
+
+ QString m_Username;
+ QString m_Password;
+
+};
+
+#endif // NXMACCESSMANAGER_H
diff --git a/src/nxmurl.cpp b/src/nxmurl.cpp new file mode 100644 index 00000000..53eb369c --- /dev/null +++ b/src/nxmurl.cpp @@ -0,0 +1,34 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "nxmurl.h"
+#include <utility.h>
+#include <QRegExp>
+#include <QStringList>
+
+NXMUrl::NXMUrl(const QString &url)
+{
+ QRegExp exp("nxm://([a-z]+)/mods/(\\d+)/files/(\\d+)", Qt::CaseInsensitive);
+ exp.indexIn(url);
+ if (exp.captureCount() != 3) {
+ throw MyException(tr("invalid nxm-link: %1").arg(url));
+ }
+ m_ModId = exp.cap(2).toInt();
+ m_FileId = exp.cap(3).toInt();
+}
diff --git a/src/nxmurl.h b/src/nxmurl.h new file mode 100644 index 00000000..a38e1910 --- /dev/null +++ b/src/nxmurl.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef NXMURL_H
+#define NXMURL_H
+
+#include <QString>
+#include <QObject>
+
+
+/**
+ * @brief represents a nxm:// url
+ * @todo the game name encoded into the url is not interpreted
+ **/
+class NXMUrl : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param url url following the nxm-protocol
+ **/
+ NXMUrl(const QString &url);
+
+ /**
+ * @brief retrieve the mod id encoded into the url
+ *
+ * @return mod id
+ **/
+ int getModId() const { return m_ModId; }
+
+ /**
+ * @brief retrieve the file id encoded into the url
+ *
+ * @return file id
+ **/
+ int getFileId() const { return m_FileId; }
+
+private:
+
+ int m_ModId;
+ int m_FileId;
+};
+
+#endif // NXMURL_H
diff --git a/src/organizer.pro b/src/organizer.pro new file mode 100644 index 00000000..497ce3ec --- /dev/null +++ b/src/organizer.pro @@ -0,0 +1,284 @@ +#-------------------------------------------------
+#
+# Project created by QtCreator 2011-05-03T18:10:26
+#
+#-------------------------------------------------
+
+contains(QT_VERSION, "^5.*") {
+ QT += core gui widgets webkitwidgets network declarative script xml sql xmlpatterns
+} else {
+ QT += core gui webkit network xml declarative script sql xmlpatterns
+}
+
+TARGET = ModOrganizer
+TEMPLATE = app
+
+SOURCES += \
+ transfersavesdialog.cpp \
+ syncoverwritedialog.cpp \
+ spawn.cpp \
+ singleinstance.cpp \
+ simpleinstalldialog.cpp \
+ settingsdialog.cpp \
+ settings.cpp \
+ selfupdater.cpp \
+ selectiondialog.cpp \
+ savegameinfowidgetgamebryo.cpp \
+ savegameinfowidget.cpp \
+ savegamegamebryo.cpp \
+ savegame.cpp \
+ report.cpp \
+ questionboxmemory.cpp \
+ queryoverwritedialog.cpp \
+ profilesdialog.cpp \
+ profile.cpp \
+ pluginlistsortproxy.cpp \
+ pluginlist.cpp \
+ overwriteinfodialog.cpp \
+ nxmurl.cpp \
+ nxmaccessmanager.cpp \
+ nexusview.cpp \
+ nexusinterface.cpp \
+ nexusdialog.cpp \
+ motddialog.cpp \
+ modlistsortproxy.cpp \
+ modlist.cpp \
+ modinfodialog.cpp \
+ modinfo.cpp \
+ messagedialog.cpp \
+ mainwindow.cpp \
+ main.cpp \
+ loghighlighter.cpp \
+ logbuffer.cpp \
+ lockeddialog.cpp \
+ loadmechanism.cpp \
+ json.cpp \
+ installdialog.cpp \
+ installationmanager.cpp \
+ helper.cpp \
+ fomodinstallerdialog.cpp \
+ finddialog.cpp \
+ filedialogmemory.cpp \
+ executableslist.cpp \
+ editexecutablesdialog.cpp \
+ dummybsa.cpp \
+ downloadmanager.cpp \
+ downloadlistwidgetcompact.cpp \
+ downloadlistwidget.cpp \
+ downloadlistsortproxy.cpp \
+ downloadlist.cpp \
+ directoryrefresher.cpp \
+ credentialsdialog.cpp \
+ categoriesdialog.cpp \
+ categories.cpp \
+ bbcode.cpp \
+ baincomplexinstallerdialog.cpp \
+ archivetree.cpp \
+ activatemodsdialog.cpp \
+ moapplication.cpp \
+ profileinputdialog.cpp \
+ icondelegate.cpp \
+ gameinfoimpl.cpp
+
+HEADERS += \
+ transfersavesdialog.h \
+ syncoverwritedialog.h \
+ spawn.h \
+ singleinstance.h \
+ simpleinstalldialog.h \
+ settingsdialog.h \
+ settings.h \
+ selfupdater.h \
+ selectiondialog.h \
+ savegameinfowidgetgamebryo.h \
+ savegameinfowidget.h \
+ savegamegamebyro.h \
+ savegame.h \
+ report.h \
+ questionboxmemory.h \
+ queryoverwritedialog.h \
+ profilesdialog.h \
+ profile.h \
+ pluginlistsortproxy.h \
+ pluginlist.h \
+ overwriteinfodialog.h \
+ nxmurl.h \
+ nxmaccessmanager.h \
+ nexusview.h \
+ nexusinterface.h \
+ nexusdialog.h \
+ motddialog.h \
+ modlistsortproxy.h \
+ modlist.h \
+ modinfodialog.h \
+ modinfo.h \
+ messagedialog.h \
+ mainwindow.h \
+ loghighlighter.h \
+ logbuffer.h \
+ lockeddialog.h \
+ loadmechanism.h \
+ json.h \
+ installdialog.h \
+ installationmanager.h \
+ helper.h \
+ fomodinstallerdialog.h \
+ finddialog.h \
+ filedialogmemory.h \
+ executableslist.h \
+ editexecutablesdialog.h \
+ dummybsa.h \
+ downloadmanager.h \
+ downloadlistwidgetcompact.h \
+ downloadlistwidget.h \
+ downloadlistsortproxy.h \
+ downloadlist.h \
+ directoryrefresher.h \
+ credentialsdialog.h \
+ categoriesdialog.h \
+ categories.h \
+ bbcode.h \
+ baincomplexinstallerdialog.h \
+ archivetree.h \
+ activatemodsdialog.h \
+ moapplication.h \
+ profileinputdialog.h \
+ icondelegate.h \
+ gameinfoimpl.h
+
+FORMS += \
+ transfersavesdialog.ui \
+ syncoverwritedialog.ui \
+ simpleinstalldialog.ui \
+ settingsdialog.ui \
+ selectiondialog.ui \
+ savegameinfowidget.ui \
+ questionboxmemory.ui \
+ queryoverwritedialog.ui \
+ profilesdialog.ui \
+ overwriteinfodialog.ui \
+ nexusdialog.ui \
+ motddialog.ui \
+ modinfodialog.ui \
+ messagedialog.ui \
+ mainwindow.ui \
+ lockeddialog.ui \
+ installdialog.ui \
+ fomodinstallerdialog.ui \
+ finddialog.ui \
+ editexecutablesdialog.ui \
+ downloadlistwidgetcompact.ui \
+ downloadlistwidget.ui \
+ credentialsdialog.ui \
+ categoriesdialog.ui \
+ baincomplexinstallerdialog.ui \
+ activatemodsdialog.ui \
+ profileinputdialog.ui
+
+INCLUDEPATH += ../shared ../archive ../uibase ../../../bsatk "$(BOOSTPATH)"
+
+LIBS += -L"$(BOOSTPATH)/stage/lib"
+
+
+CONFIG(debug, debug|release) {
+ OUTDIR = $$OUT_PWD/debug
+ DSTDIR = $$PWD/../../outputd
+ LIBS += -L$$OUT_PWD/../shared/debug -L../../../bsatk-build/debug
+ LIBS += -L$$OUT_PWD/../uibase/debug
+} else {
+ OUTDIR = $$OUT_PWD/release
+ DSTDIR = $$PWD/../../output
+ LIBS += -L$$OUT_PWD/../shared/release -L../../../bsatk-build/release
+ LIBS += -L$$OUT_PWD/../uibase/release
+ QMAKE_CXXFLAGS += /Zi
+ QMAKE_LFLAGS += /DEBUG
+}
+
+CONFIG += embed_manifest_exe
+
+# QMAKE_CXXFLAGS += /analyze
+
+# QMAKE_LFLAGS += /MANIFESTUAC:\"level=\'highestAvailable\' uiAccess=\'false\'\"
+
+TRANSLATIONS = organizer_de.ts \
+ organizer_es.ts \
+ organizer_fr.ts \
+ organizer_zh_TW.ts \
+ organizer_zh_CN.ts \
+ organizer_cs.ts \
+ organizer_tr.ts \
+ organizer_ru.ts
+
+!isEmpty(TRANSLATIONS) {
+ isEmpty(QMAKE_LRELEASE) {
+ win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease.exe
+ else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
+ }
+
+ isEmpty(TS_DIR):TS_DIR = Translations
+
+ TSQM.name = lrelease ${QMAKE_FILE_IN}
+ TSQM.input = TRANSLATIONS
+ TSQM.output = $$TS_DIR/${QMAKE_FILE_BASE}.qm
+ TSQM.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN}
+ TSQM.CONFIG = no_link
+ QMAKE_EXTRA_COMPILERS += TSQM
+ PRE_TARGETDEPS += compiler_TSQM_make_all
+} else:message(No translation files in project)
+
+LIBS += -lmo_shared -luibase -lshell32 -lole32 -luser32 -ladvapi32 -lgdi32 -lPsapi -lVersion -lbsatk
+
+DEFINES += UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS NOMINMAX
+
+DEFINES += BOOST_DISABLE_ASSERTS NDEBUG
+#DEFINES += QMLJSDEBUGGER
+
+
+SRCDIR = $$PWD
+SRCDIR ~= s,/,$$QMAKE_DIR_SEP,g
+OUTDIR ~= s,/,$$QMAKE_DIR_SEP,g
+DSTDIR ~= s,/,$$QMAKE_DIR_SEP,g
+
+QMAKE_POST_LINK += mkdir -p $$quote($$DSTDIR) $$escape_expand(\\n)
+QMAKE_POST_LINK += mkdir -p $$quote($$DSTDIR\\dlls) $$escape_expand(\\n)
+QMAKE_POST_LINK += xcopy /y /i $$quote($$OUTDIR\\ModOrganizer*.exe) $$quote($$DSTDIR) $$escape_expand(\\n)
+QMAKE_POST_LINK += xcopy /y /i $$quote($$OUTDIR\\ModOrganizer*.pdb) $$quote($$DSTDIR) $$escape_expand(\\n)
+QMAKE_POST_LINK += xcopy /y /s /i $$quote($$SRCDIR\\stylesheets) $$quote($$DSTDIR)\\stylesheets $$escape_expand(\\n)
+QMAKE_POST_LINK += xcopy /y /s /i $$quote($$SRCDIR\\tutorials) $$quote($$DSTDIR)\\tutorials $$escape_expand(\\n)
+QMAKE_POST_LINK += xcopy /y /s /i $$quote($$SRCDIR\\*.qm) $$quote($$DSTDIR)\\translations $$escape_expand(\\n)
+
+CONFIG(debug, debug|release) {
+ QMAKE_POST_LINK += copy $$quote($$SRCDIR\\..\\dlls.manifest.debug) $$quote($$DSTDIR)\\dlls\\dlls.manifest $$escape_expand(\\n)
+} else {
+ QMAKE_POST_LINK += copy $$quote($$SRCDIR\\..\\dlls.manifest) $$quote($$DSTDIR)\\dlls $$escape_expand(\\n)
+}
+
+RESOURCES += \
+ resources.qrc \
+ stylesheet_resource.qrc
+
+RC_FILE += \
+ app_icon.rc
+
+OTHER_FILES += \
+ version.rc \
+ tutorials/firststeps.qml \
+ tutorials/tutorials.js \
+ tutorials/tutorial_firststeps_main.js \
+ tutorials/tutorial_firststeps_settings.js \
+ tutorials/tutorials_settingsdialog.qml \
+ tutorials/tutorials_mainwindow.qml \
+ tutorials/Highlight.qml \
+ tutorials/TutorialDescription.qml \
+ tutorials/TutorialOverlay.qml \
+ tutorials/tutorials_nexusdialog.qml \
+ tutorials/tutorial_firststeps_browser.js \
+ tutorials/tutorials_modinfodialog.qml \
+ tutorials/tutorial_firststeps_modinfo.js \
+ tutorials/tutorial_conflictresolution_main.js \
+ tutorials/tutorial_conflictresolution_modinfo.js \
+ app_icon.rc \
+ dark.qss \
+ stylesheets/dark.qss \
+ tutorials/tutorial_window_installer.js \
+ tutorials/tutorials_installdialog.qml
diff --git a/src/organizer_cs.qm b/src/organizer_cs.qm Binary files differnew file mode 100644 index 00000000..17762942 --- /dev/null +++ b/src/organizer_cs.qm diff --git a/src/organizer_cs.ts b/src/organizer_cs.ts new file mode 100644 index 00000000..ee2a6eab --- /dev/null +++ b/src/organizer_cs.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="cs_CZ"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_de.qm b/src/organizer_de.qm Binary files differnew file mode 100644 index 00000000..9dad8dff --- /dev/null +++ b/src/organizer_de.qm diff --git a/src/organizer_de.ts b/src/organizer_de.ts new file mode 100644 index 00000000..1cac6e4a --- /dev/null +++ b/src/organizer_de.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="de_DE"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_es.qm b/src/organizer_es.qm Binary files differnew file mode 100644 index 00000000..9dad8dff --- /dev/null +++ b/src/organizer_es.qm diff --git a/src/organizer_es.ts b/src/organizer_es.ts new file mode 100644 index 00000000..07193b1c --- /dev/null +++ b/src/organizer_es.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="es_ES"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_fr.qm b/src/organizer_fr.qm Binary files differnew file mode 100644 index 00000000..c02994ca --- /dev/null +++ b/src/organizer_fr.qm diff --git a/src/organizer_fr.ts b/src/organizer_fr.ts new file mode 100644 index 00000000..59911709 --- /dev/null +++ b/src/organizer_fr.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="fr_FR"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_ru.qm b/src/organizer_ru.qm Binary files differnew file mode 100644 index 00000000..7431612d --- /dev/null +++ b/src/organizer_ru.qm diff --git a/src/organizer_ru.ts b/src/organizer_ru.ts new file mode 100644 index 00000000..11760b65 --- /dev/null +++ b/src/organizer_ru.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="ru_RU"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_tr.qm b/src/organizer_tr.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/src/organizer_tr.qm @@ -0,0 +1 @@ +<¸dÊÍ!¿`¡½Ý
\ No newline at end of file diff --git a/src/organizer_tr.ts b/src/organizer_tr.ts new file mode 100644 index 00000000..45443cef --- /dev/null +++ b/src/organizer_tr.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="tr_TR"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_zh_CN.qm b/src/organizer_zh_CN.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/src/organizer_zh_CN.qm @@ -0,0 +1 @@ +<¸dÊÍ!¿`¡½Ý
\ No newline at end of file diff --git a/src/organizer_zh_CN.ts b/src/organizer_zh_CN.ts new file mode 100644 index 00000000..07c886d3 --- /dev/null +++ b/src/organizer_zh_CN.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="zh_CN"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/organizer_zh_TW.qm b/src/organizer_zh_TW.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/src/organizer_zh_TW.qm @@ -0,0 +1 @@ +<¸dÊÍ!¿`¡½Ý
\ No newline at end of file diff --git a/src/organizer_zh_TW.ts b/src/organizer_zh_TW.ts new file mode 100644 index 00000000..3644dbb5 --- /dev/null +++ b/src/organizer_zh_TW.ts @@ -0,0 +1,4627 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="zh_TW"> +<context> + <name>ActivateModsDialog</name> + <message> + <location filename="activatemodsdialog.ui" line="14"/> + <source>Activate Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="20"/> + <source>This is a list of esps and esms that were active when the save game was created.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="23"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="37"/> + <source>Missing ESP</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.ui" line="42"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="activatemodsdialog.cpp" line="49"/> + <source>not found</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BainComplexInstallerDialog</name> + <message> + <location filename="baincomplexinstallerdialog.ui" line="14"/> + <source>BAIN Package Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="34"/> + <source>This looks like a Package prepared for Installation through BAIN. You can select options from the list below. If there is a package.txt file, it should contain detailed information about the options.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="44"/> + <source>Components of this package.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="47"/> + <source>Components of this package. +If there is a component called "00 Core" it is usually required. Options are ordered by priority as set up by the author.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="57"/> + <location filename="baincomplexinstallerdialog.ui" line="60"/> + <source>The package.txt is often part of BAIN packages and contains details about the options available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="63"/> + <source>Package.txt</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="83"/> + <location filename="baincomplexinstallerdialog.ui" line="86"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="89"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="96"/> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="baincomplexinstallerdialog.ui" line="103"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CategoriesDialog</name> + <message> + <location filename="categoriesdialog.ui" line="14"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="66"/> + <source>ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="69"/> + <source>Internal ID for the category.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="72"/> + <source>Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="77"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="80"/> + <location filename="categoriesdialog.ui" line="83"/> + <source>Name of the Categorie used for display.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="88"/> + <source>Nexus IDs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="91"/> + <source>Comma-Separated list of Nexus IDs to be matched to the internal ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="94"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can match one or multiple nexus categories to a internal ID. Whenever you download a mod from a Nexus Page, Mod Organizer will try to resolve the category defined on the Nexus to one available in MO.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">To find out a category id used by the nexus, visit the categories list of the nexus page and hover over the links there.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="105"/> + <source>Parent ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.ui" line="108"/> + <source>If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="238"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categoriesdialog.cpp" line="239"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>CredentialsDialog</name> + <message> + <location filename="credentialsdialog.ui" line="14"/> + <source>Login</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="20"/> + <source>This feature may not work unless you're logged in with Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="32"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="46"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="64"/> + <source>Remember</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="credentialsdialog.ui" line="75"/> + <source>Never ask again</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DirectoryRefresher</name> + <message> + <location filename="directoryrefresher.cpp" line="81"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadList</name> + <message> + <location filename="downloadlist.cpp" line="63"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="64"/> + <source>Filetime</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="65"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlist.cpp" line="79"/> + <source>Information missing, please select "Query Info" from the context menu to re-retrieve.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidget</name> + <message> + <location filename="downloadlistwidget.ui" line="17"/> + <location filename="downloadlistwidget.ui" line="59"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.ui" line="68"/> + <location filename="downloadlistwidget.cpp" line="91"/> + <location filename="downloadlistwidget.cpp" line="93"/> + <source>Done - Double Click to install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="82"/> + <location filename="downloadlistwidget.cpp" line="84"/> + <source>Installed - Double Click to re-install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompact</name> + <message> + <location filename="downloadlistwidgetcompact.ui" line="17"/> + <location filename="downloadlistwidgetcompact.ui" line="47"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.ui" line="100"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetCompactDelegate</name> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="84"/> + <source>Installed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="87"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="153"/> + <location filename="downloadlistwidgetcompact.cpp" line="162"/> + <location filename="downloadlistwidgetcompact.cpp" line="171"/> + <location filename="downloadlistwidgetcompact.cpp" line="180"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="154"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="163"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="172"/> + <source>This will permanently remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="181"/> + <source>This will permanently remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="205"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="207"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="209"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="210"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="212"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="213"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="215"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="216"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="220"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="221"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="223"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidgetcompact.cpp" line="224"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadListWidgetDelegate</name> + <message> + <location filename="downloadlistwidget.cpp" line="161"/> + <location filename="downloadlistwidget.cpp" line="170"/> + <location filename="downloadlistwidget.cpp" line="179"/> + <location filename="downloadlistwidget.cpp" line="188"/> + <source>Are you sure?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="162"/> + <source>This will remove all finished downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="171"/> + <source>This will remove all installed downloads from this list and from disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="180"/> + <source>This will remove all finished downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="189"/> + <source>This will remove all installed downloads from this list (but NOT from disk).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="212"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="214"/> + <source>Query Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="216"/> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="217"/> + <source>Remove from View</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="219"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="220"/> + <source>Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="222"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="223"/> + <source>Resume</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="227"/> + <source>Delete Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="228"/> + <source>Delete All...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="230"/> + <source>Remove Installed...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadlistwidget.cpp" line="231"/> + <source>Remove All...</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>DownloadManager</name> + <message> + <location filename="downloadmanager.cpp" line="56"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>Download again?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="215"/> + <source>A file with the same name has already been downloaded. Do you want to download it again? The new file will receive a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="243"/> + <source>failed to download %1: could not open output file: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="274"/> + <location filename="downloadmanager.cpp" line="460"/> + <location filename="downloadmanager.cpp" line="470"/> + <location filename="downloadmanager.cpp" line="480"/> + <location filename="downloadmanager.cpp" line="490"/> + <location filename="downloadmanager.cpp" line="500"/> + <location filename="downloadmanager.cpp" line="511"/> + <location filename="downloadmanager.cpp" line="521"/> + <location filename="downloadmanager.cpp" line="531"/> + <source>invalid index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="292"/> + <source>failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="298"/> + <source>failed to delete meta file for %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="357"/> + <location filename="downloadmanager.cpp" line="375"/> + <location filename="downloadmanager.cpp" line="389"/> + <location filename="downloadmanager.cpp" line="403"/> + <location filename="downloadmanager.cpp" line="422"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Please enter the nexus mod id</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="434"/> + <source>Mod ID:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="707"/> + <source>Information updated</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="709"/> + <location filename="downloadmanager.cpp" line="723"/> + <source>No matching file found on Nexus! Maybe this file is no longer available or it was renamed?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="711"/> + <source>No file on Nexus matches the selected file by name. Please manually choose the correct one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="798"/> + <source>No download server available. Please try again later.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="836"/> + <source>Failed to request file info from nexus: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="857"/> + <source>Download failed: %1 (%2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="downloadmanager.cpp" line="915"/> + <source>failed to re-open %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>EditExecutablesDialog</name> + <message> + <location filename="editexecutablesdialog.ui" line="14"/> + <source>Modify Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="20"/> + <source>List of configured executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="23"/> + <source>This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="38"/> + <source>Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="45"/> + <location filename="editexecutablesdialog.ui" line="48"/> + <source>Name of the executable. This is only for display purposes.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="59"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="66"/> + <location filename="editexecutablesdialog.ui" line="69"/> + <source>Binary to run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="76"/> + <source>Browse filesystem</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="79"/> + <source>Browse filesystem for the executable to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="82"/> + <location filename="editexecutablesdialog.ui" line="103"/> + <source>...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="93"/> + <source>Start in</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="114"/> + <source>Arguments</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="121"/> + <location filename="editexecutablesdialog.ui" line="124"/> + <source>Arguments to pass to the application</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="135"/> + <source>Allow the Steam AppID to be used for this executable to be changed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="138"/> + <source>Allow the Steam AppID to be used for this executable to be changed. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="143"/> + <source>Overwrite Steam AppID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="153"/> + <source>Steam AppID to use for this executable that differs from the games AppID.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="156"/> + <source>Steam AppID to use for this executable that differs from the games AppID. +Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). +Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="169"/> + <location filename="editexecutablesdialog.ui" line="172"/> + <location filename="editexecutablesdialog.cpp" line="182"/> + <source>If checked, MO will be closed once the specified executable is run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="175"/> + <source>Close MO when started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="182"/> + <location filename="editexecutablesdialog.ui" line="185"/> + <source>Add an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="188"/> + <location filename="editexecutablesdialog.cpp" line="152"/> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="199"/> + <location filename="editexecutablesdialog.ui" line="202"/> + <source>Remove the selected executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.ui" line="205"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Select a binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="112"/> + <source>Executable (%1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="122"/> + <source>Select a directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="131"/> + <source>Really remove "%1" from executables?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="156"/> + <source>Modify</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="editexecutablesdialog.cpp" line="179"/> + <source>MO must be kept running or this application will not work correctly.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FindDialog</name> + <message> + <location filename="finddialog.ui" line="14"/> + <source>Find</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="24"/> + <source>Find what:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="31"/> + <location filename="finddialog.ui" line="34"/> + <source>Search term</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="47"/> + <location filename="finddialog.ui" line="50"/> + <source>Find next occurence from current file position.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="53"/> + <source>&Find Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="finddialog.ui" line="60"/> + <location filename="finddialog.ui" line="63"/> + <location filename="finddialog.ui" line="66"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>FomodInstallerDialog</name> + <message> + <location filename="fomodinstallerdialog.ui" line="14"/> + <source>FOMOD Installation Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="46"/> + <source>Author</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="60"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="74"/> + <source>Website</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="81"/> + <source><a href="#">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="160"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="170"/> + <source>Back</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="177"/> + <location filename="fomodinstallerdialog.cpp" line="933"/> + <source>Next</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.ui" line="184"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="98"/> + <source>ModuleConfig.xml missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="360"/> + <source><a href="%1">Link</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="368"/> + <source>failed to parse info.xml: %1 (%2) (line %3, column %4)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="387"/> + <source>unsupported order type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="405"/> + <source>unsupported group type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="561"/> + <source>This component is required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="567"/> + <source>It is recommended you enable this component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="573"/> + <source>Optional component</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="578"/> + <source>This component is not usable in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="583"/> + <source>You may be experiencing instability in combination with other installed plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="620"/> + <source>None</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="636"/> + <source>Select one or more of these options:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="818"/> + <source>failed to parse ModuleConfig.xml: %1 - %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="fomodinstallerdialog.cpp" line="919"/> + <source>Install</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="installdialog.ui" line="20"/> + <source>Install Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="32"/> + <source>New Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="46"/> + <location filename="installdialog.cpp" line="242"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="53"/> + <source>Pick a name for the mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="56"/> + <source>Pick a name for the mod. This is also used as a directory name, so please don't use characters that are illegal in file names.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="65"/> + <source>Content</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="75"/> + <source>Content of the archive. You can change the directory structure by using drag&drop. Hint: Also try right clicking...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="78"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This displays the content of the archive. &lt;data&gt; represents the base directory which will map to the game's data directory. You can change the base directory via the right-click context menu and you can move around files via drag&amp;drop</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="121"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="141"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.ui" line="148"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="188"/> + <source>Looks good</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="189"/> + <source>No problem detected</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="192"/> + <source>No game data on top level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="193"/> + <source>There is no esp/esm file or asset directory (textures, meshes, interface, ...) on the top level.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="242"/> + <source>Enter a directory name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="247"/> + <source>A directory with that name exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="274"/> + <source>Set data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="275"/> + <source>Unset data directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="277"/> + <source>Create directory...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="279"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installdialog.cpp" line="294"/> + <source>This mod was probably NOT set up correctly, most likely it will NOT work. Really continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>InstallationManager</name> + <message> + <location filename="installationmanager.cpp" line="75"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="96"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="166"/> + <location filename="installationmanager.cpp" line="248"/> + <location filename="installationmanager.cpp" line="566"/> + <source>Extracting files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="492"/> + <source>failed to create backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Mod Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="498"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="692"/> + <source>Preparing installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="737"/> + <source>Installation as fomod failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="779"/> + <source>failed to start %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Running external installer. +Note: This installer will not be aware of other installed mods!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="783"/> + <source>Force Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="800"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="855"/> + <source>Finalization of the installation failed. The mod may or may not work correctly. See mo_interface.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="858"/> + <source>installation failed (errorcode %1)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="885"/> + <source>File format "%1" not supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1015"/> + <source>Failed to open "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1029"/> + <source>This seems like a bundle of fomods, which one do you want to install?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1104"/> + <source>Installer missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1105"/> + <source>This package contains a scripted installer. To use this installer you need the optional "NCC"-package and the .net runtime. Do you want to continue, treating this as a manual installer?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1111"/> + <source>Please install NCC</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1220"/> + <source>no error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1223"/> + <source>7z.dll not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1226"/> + <source>7z.dll isn't valid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1229"/> + <source>archive not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1232"/> + <source>failed to open archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1235"/> + <source>unsupported archive type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1238"/> + <source>internal library error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1241"/> + <source>archive invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="1245"/> + <source>unknown archive error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LockedDialog</name> + <message> + <location filename="lockeddialog.ui" line="14"/> + <source>Locked</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="20"/> + <source>This dialog should disappear automatically if the application/game is done. Click unlock if it didn't.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="23"/> + <source>MO is locked while the executable is running.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="lockeddialog.ui" line="51"/> + <source>Unlock</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>LogBuffer</name> + <message> + <location filename="logbuffer.cpp" line="70"/> + <source>failed to write log to %1: %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MOApplication</name> + <message> + <location filename="moapplication.cpp" line="60"/> + <source>an error occured: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="moapplication.cpp" line="65"/> + <source>an error occured</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="mainwindow.ui" line="42"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="105"/> + <source>Profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="115"/> + <source>Pick a module collection</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="118"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different play throughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept seperate for different profiles.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="136"/> + <source>Refresh list</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="139"/> + <source>Refresh list. This is usually not necessary unless you modified data outside the program.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="155"/> + <source>Installed Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="264"/> + <source>List of available mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="267"/> + <source>This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="355"/> + <location filename="mainwindow.ui" line="905"/> + <source>Filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="375"/> + <source>Name filter</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="394"/> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="421"/> + <source>Pick a program to run.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="424"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="472"/> + <source>Run program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="475"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="485"/> + <source>Run</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="526"/> + <source>Create a shortcut in your start menu or on the desktop to the specified program</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="529"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="536"/> + <source>Shortcut</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="602"/> + <source>save esp list and load order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="605"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Save the list of active mods and load order. This automatically happens if you close MO or start a program.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="612"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="671"/> + <source>List of available esp/esm files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="674"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="728"/> + <source>IMPORTANT: You can change the order of BSAs here but installation order of mods has priority over the order specified here!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="741"/> + <source>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="744"/> + <source>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. +By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + +BSAs checked here are loaded in such a way that your installation order is obeyed properly.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="781"/> + <location filename="mainwindow.ui" line="836"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="786"/> + <location filename="mainwindow.ui" line="841"/> + <source>Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="795"/> + <source>Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="804"/> + <source>refresh data-directory overview</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="807"/> + <source>Refresh the overview. This may take a moment.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="810"/> + <location filename="mainwindow.cpp" line="2642"/> + <location filename="mainwindow.cpp" line="3316"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="826"/> + <source>This is an overview of your data directory as visible to the game (and tools). </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="851"/> + <location filename="mainwindow.ui" line="854"/> + <source>Filter the above list so that only conflicts are displayed.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="857"/> + <source>Show only conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="865"/> + <source>Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="880"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="894"/> + <source>Downloads</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="924"/> + <source>This is a list of mods you downloaded from Nexus. Double click one to install it.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="971"/> + <source>Compact</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="995"/> + <source>Tool Bar</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1037"/> + <source>Install Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1040"/> + <source>Install &Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1043"/> + <source>Install a new mod from an archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1046"/> + <source>Ctrl+M</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1055"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1058"/> + <source>&Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1061"/> + <source>Configure Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1064"/> + <source>Ctrl+P</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1073"/> + <source>Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1076"/> + <source>&Executables</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1079"/> + <source>Configure the executables that can be started through Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1082"/> + <source>Ctrl+E</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1091"/> + <location filename="mainwindow.ui" line="1097"/> + <source>Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1094"/> + <source>&Tools</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1100"/> + <source>Ctrl+I</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1109"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1112"/> + <source>&Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1115"/> + <source>Configure settings and workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1118"/> + <source>Ctrl+S</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1127"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1130"/> + <source>Search nexus network for more mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1133"/> + <source>Ctrl+N</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1145"/> + <location filename="mainwindow.cpp" line="3264"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1148"/> + <source>Mod Organizer is up-to-date</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1160"/> + <location filename="mainwindow.cpp" line="301"/> + <source>No Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1163"/> + <source>This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. + +!Work in progress! +Right now this has very limited functionality</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1175"/> + <location filename="mainwindow.ui" line="1178"/> + <source>Help</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1181"/> + <source>Ctrl+H</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1190"/> + <source>Endorse MO</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.ui" line="1193"/> + <location filename="mainwindow.cpp" line="3344"/> + <source>Endorse Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="174"/> + <source>Desktop</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="175"/> + <source>Start Menu</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="298"/> + <location filename="mainwindow.cpp" line="375"/> + <location filename="mainwindow.cpp" line="3641"/> + <source>Problems</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="299"/> + <location filename="mainwindow.cpp" line="376"/> + <source>There are potential problems with your setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="302"/> + <location filename="mainwindow.cpp" line="378"/> + <source>Everything seems to be in order</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="344"/> + <source><li>%1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="350"/> + <source><li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href="http://skyrim.nexusmods.com/downloads/file.php?id=1334">the MO page on nexus</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="354"/> + <source><li>NCC version may be incompatible.</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="361"/> + <source><li>dotNet is not installed or outdated. This is required to use NCC. Get it from here: <a href="%1">%1</a></li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="367"/> + <source><li>There was an error reported in your last log. Please see %1</li></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="389"/> + <source>Help on UI</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="393"/> + <source>Documentation Wiki</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="397"/> + <source>Report Issue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="401"/> + <source>Tutorials</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="458"/> + <source>load order could not be saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="463"/> + <source>failed to save load order: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="476"/> + <source>failed to save archives order, do you have write access to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="492"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="493"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="501"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="544"/> + <source>Show tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="545"/> + <source>You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="571"/> + <source>Downloads in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="572"/> + <source>There are still downloads in progress, do you really want to quit?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="628"/> + <source>failed to read savegame: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="872"/> + <source>The mod "%1" already exists!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="912"/> + <source>Failed to start "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="914"/> + <source>Please press OK once you're logged into steam.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="926"/> + <source>"%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="940"/> + <source>Start Steam?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="941"/> + <source>Steam is required to be running already to correctly start the game. Should MO try to start steam now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1134"/> + <source>Also in: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1145"/> + <source>No conflict</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1241"/> + <source><Edit...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1448"/> + <source>This bsa is enabled in the ini file so it may be required!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1455"/> + <source>This archive will still be loaded since there is a plugin of the same name but its files will not follow installation order!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1603"/> + <location filename="mainwindow.cpp" line="3012"/> + <source>Installation successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1614"/> + <location filename="mainwindow.cpp" line="3025"/> + <source>Configure Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1615"/> + <location filename="mainwindow.cpp" line="3026"/> + <source>This mod contains ini tweaks. Do you want to configure them now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1621"/> + <location filename="mainwindow.cpp" line="3032"/> + <source>mod "%1" not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>Installation cancelled</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1624"/> + <location filename="mainwindow.cpp" line="3039"/> + <source>The mod was not installed completely.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1638"/> + <source>Choose Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1639"/> + <source>Mod Archive</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1799"/> + <source>Start Tutorial?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1800"/> + <source>You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1945"/> + <location filename="mainwindow.cpp" line="2939"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1968"/> + <source>failed to update mod list: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1995"/> + <source>failed to spawn notepad.exe: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2036"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2114"/> + <source>failed to change origin name: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2133"/> + <location filename="mainwindow.cpp" line="2136"/> + <source><All></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2137"/> + <source><Checked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2138"/> + <source><Unchecked></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2139"/> + <source><Update></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2140"/> + <source><No category></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2141"/> + <source><Conflicted></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2174"/> + <source>failed to rename mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2187"/> + <source>Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2188"/> + <source>This will replace the existing mod "%1". Continue?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2191"/> + <source>failed to remove mod "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2195"/> + <location filename="mainwindow.cpp" line="3210"/> + <location filename="mainwindow.cpp" line="3234"/> + <source>failed to rename "%1" to "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2216"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2217"/> + <source>Remove the following mods?<br><ul>%1</ul></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2228"/> + <source>failed to remove mod: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <location filename="mainwindow.cpp" line="2249"/> + <source>Failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2246"/> + <source>Installation file no longer exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2250"/> + <source>Mods installed with old versions of MO can't be reinstalled in this way.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2265"/> + <location filename="mainwindow.cpp" line="2287"/> + <source>You need to be logged in with Nexus to endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2359"/> + <location filename="mainwindow.cpp" line="3562"/> + <source>Extract BSA</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2360"/> + <source>This mod contains at least one BSA. Do you want to unpack it? +(This removes the BSA after completion. If you don't know about BSAs, just select no)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2370"/> + <location filename="mainwindow.cpp" line="3519"/> + <location filename="mainwindow.cpp" line="3571"/> + <source>failed to read %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2383"/> + <location filename="mainwindow.cpp" line="3584"/> + <source>This archive contains invalid hashes. Some files may be broken.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2406"/> + <source>Nexus ID for this Mod is unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2452"/> + <source>Choose Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2635"/> + <source>Install Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2637"/> + <source>Enable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2638"/> + <source>Disable all visible</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2640"/> + <source>Check all for update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2649"/> + <source>Sync to Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2651"/> + <source>Restore Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2652"/> + <source>Remove Backup...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2654"/> + <source>Set Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2658"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2662"/> + <source>Rename Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2663"/> + <source>Remove Mod...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2664"/> + <source>Reinstall Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2666"/> + <source>Un-Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2668"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2670"/> + <source>Visit on Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2671"/> + <source>Open in explorer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2674"/> + <source>Information...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2680"/> + <location filename="mainwindow.cpp" line="3707"/> + <source>Exception: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2682"/> + <location filename="mainwindow.cpp" line="3709"/> + <source>Unknown exception</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2785"/> + <source>Fix Mods...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2802"/> + <location filename="mainwindow.cpp" line="2833"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2817"/> + <location filename="mainwindow.cpp" line="2848"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2862"/> + <source>Can't change download directory while downloads are in progress!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="2942"/> + <source>Download failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3088"/> + <source>failed to write to file %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3094"/> + <source>%1 written</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Select binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3133"/> + <source>Binary</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3159"/> + <source>Enter Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3160"/> + <source>Please enter a name for the executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>Not an executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3170"/> + <source>This is not a recognized executable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <location filename="mainwindow.cpp" line="3220"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3195"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3198"/> + <location filename="mainwindow.cpp" line="3223"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3220"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3266"/> + <source>Update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3303"/> + <source>Open/Execute</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3304"/> + <source>Add as Executable</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3308"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3310"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3315"/> + <source>Write To File...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3345"/> + <source>Do you want to endorse Mod Organizer on %1 now?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3442"/> + <source>Thank you for your endorsement!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3454"/> + <source>Request to Nexus failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3461"/> + <location filename="mainwindow.cpp" line="3478"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3487"/> + <source>login failed: %1. Trying to download anyway</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3498"/> + <source>login failed: %1. You need to log-in with Nexus to update MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3531"/> + <source>failed to extract %1 (errorcode %2)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3627"/> + <source>Extract...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3671"/> + <source>Edit Categories...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3693"/> + <source>Enable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3694"/> + <source>Disable all</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3698"/> + <source>Unlock index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="3700"/> + <source>Lock index</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MessageDialog</name> + <message> + <location filename="messagedialog.ui" line="150"/> + <location filename="messagedialog.ui" line="180"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfo</name> + <message> + <location filename="modinfo.cpp" line="121"/> + <location filename="modinfo.cpp" line="149"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="136"/> + <source>invalid mod id %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoBackup</name> + <message> + <location filename="modinfo.cpp" line="787"/> + <source>This is the backup of a mod</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoDialog</name> + <message> + <location filename="modinfodialog.ui" line="14"/> + <source>Mod Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="27"/> + <source>Textfiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="39"/> + <source>A list of text-files in the mod directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="42"/> + <source>A list of text-files in the mod directory like readmes. </source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="64"/> + <location filename="modinfodialog.ui" line="149"/> + <source>Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="74"/> + <source>INI-Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="94"/> + <source>This is a list of .ini files in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="97"/> + <source>This is a list of .ini files in the mod. These are usually used to configure the behaviour of mods if there are configurable parameters.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="143"/> + <source>Save changes to the file.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="146"/> + <source>Save changes to the file. This overwrites the original. There is no automatic backup!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="159"/> + <source>Images</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="214"/> + <source>Images located in the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="217"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This lists all the images (.jpg and .png) in the mod directory, like screenshots and such. Click one to get a larger view.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="245"/> + <location filename="modinfodialog.ui" line="268"/> + <source>Optional ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="251"/> + <source>List of esps and esms that can not be loaded by the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="254"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">They usually contain optional functionality, see the readme.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Most mods do not have optional esps, so chances are good you are looking at an empty list.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="283"/> + <source>Make the selected mod in the lower list unavailable.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="286"/> + <source>The selected esp (in the lower list) will be pushed into a subdirectory of the mod and will thus become "invisible" to the game. It can then no longer be activated.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="312"/> + <source>Move a file to the data directory.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="315"/> + <source>This moves a esp to the esp directory so it can be enabled in the main window. Please note that the ESP merely becomes "available", it will not necessarily be loaded! That is configured in the main window of omo.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="350"/> + <source>ESPs in the data directory and thus visible to the game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="353"/> + <source>These are the mod files that are in the (virtual) data directory of your game and will thus be selecteable in the esp list in the main window.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="360"/> + <source>Available ESPs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="368"/> + <source>Conflicts</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="376"/> + <source>The following conflicted files are provided by this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="423"/> + <location filename="modinfodialog.ui" line="470"/> + <source>File</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="428"/> + <source>Overwritten Mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="438"/> + <source>The following conflicted files are provided by other mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="475"/> + <source>Providing Mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="485"/> + <source>Non-Conflicted files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="505"/> + <source>Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="528"/> + <source>Primary Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="545"/> + <source>Nexus Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="553"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="560"/> + <source>Mod ID for this mod on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="563"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod ID for this mod on Nexus. This is filled in automatically if you downloaded and installed the mod from inside MO. Otherwise you can enter it manually. To find the correct id, find the mod on nexus. The URL will look like this: </span><a href=" http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">http://skyrim.nexusmods.com/downloads/file.php?id=1334</span></a><a href="http://www.skyrimnexus.com/downloads/file.php?id=1334"><span style=" font-size:8pt; color:#000000;">. In this example, 1334 is the id you're looking for. Besides: The above is the link to Mod Organizer on the Nexus. Why not go there now and endorse?</span></a></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="587"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Installed Version of the Mod. The tooltip will contain the current version available on nexus. The installed version is only set if you installed the mod through MO.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="594"/> + <location filename="modinfodialog.ui" line="715"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="624"/> + <source>Refresh</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="627"/> + <source>Refresh all information from Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="641"/> + <source>Description</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="656"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="667"/> + <source>Files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="686"/> + <source>List of files currently uploaded on nexus. Double click to download.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="705"/> + <source>Type</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="710"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="720"/> + <source>Size (kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="746"/> + <source>Endorse</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="760"/> + <source>Filetree</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="769"/> + <source>A directory view of this mod</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="772"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a modifiable directory view of the mod directory. You can move around files using drag &amp; drop and rename them (double click).</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Changes happen immediately on disc, so do</span><span style=" font-size:8pt; font-weight:600;"> be careful</span><span style=" font-size:8pt;">.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.ui" line="812"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="102"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="103"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="104"/> + <source>&Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="105"/> + <source>&Unhide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="106"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="107"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="339"/> + <location filename="modinfodialog.cpp" line="354"/> + <source>Save changes to "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="550"/> + <source>A file with that name exists, please enter a new one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="567"/> + <source>failed to move file</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="592"/> + <source>failed to create directory "optional"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="630"/> + <location filename="modinfodialog.cpp" line="1206"/> + <source>Info requested, please wait</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="684"/> + <source>Main</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="685"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="686"/> + <source>Optional</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="687"/> + <source>Old</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="688"/> + <source>Misc</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="689"/> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="699"/> + <source>Current Version: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="702"/> + <source>No update available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="743"/> + <source>(description incomplete, please visit nexus)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="800"/> + <source><a href="%1">Visit on Nexus</a></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <location filename="modinfodialog.cpp" line="917"/> + <location filename="modinfodialog.cpp" line="922"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="864"/> + <source>Download "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="867"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="870"/> + <source>Exception: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="906"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="917"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="922"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="996"/> + <location filename="modinfodialog.cpp" line="1002"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1008"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <location filename="modinfodialog.cpp" line="1136"/> + <source>Replace file?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1112"/> + <source>There already is a hidden version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>File operation failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1115"/> + <location filename="modinfodialog.cpp" line="1139"/> + <source>Failed to remove "%1". Maybe you lack the required file permissions?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1126"/> + <location filename="modinfodialog.cpp" line="1149"/> + <source>failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1136"/> + <source>There already is a visible version of this file. Replace it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1185"/> + <source>Un-Hide</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfodialog.cpp" line="1187"/> + <source>Hide</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoOverwrite</name> + <message> + <location filename="modinfo.cpp" line="824"/> + <source>This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.h" line="772"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModInfoRegular</name> + <message> + <location filename="modinfo.cpp" line="414"/> + <source>failed to write %1/meta.ini: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="643"/> + <source>%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modinfo.cpp" line="647"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ModList</name> + <message> + <location filename="modlist.cpp" line="64"/> + <location filename="modlist.cpp" line="76"/> + <location filename="modlist.cpp" line="563"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="64"/> + <source>Really enable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="76"/> + <source>Really disable all visible mods?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="106"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="121"/> + <source>This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="130"/> + <source>Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="131"/> + <source>No valid game data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="132"/> + <source>Not endorsed yet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="133"/> + <source>Overwrites files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="134"/> + <source>Overwritten files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="135"/> + <source>Overwrites & Overwritten</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="136"/> + <source>Redundant</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="167"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="170"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="193"/> + <source>invalid</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="264"/> + <source>installed version: %1, newest version: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="268"/> + <source>Categories: <br></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="523"/> + <source>drag&drop failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="563"/> + <source>Are you sure you want to remove "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="598"/> + <source>Flags</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="599"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="600"/> + <source>Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="601"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="602"/> + <source>Category</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="603"/> + <source>Nexus ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="604"/> + <location filename="modlist.cpp" line="619"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="612"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="613"/> + <source>Version of the mod (if available)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="614"/> + <source>Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="616"/> + <source>Category of the mod.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="617"/> + <source>Id of the mod as used on Nexus.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="modlist.cpp" line="618"/> + <source>Emblemes to highlight things that might require attention.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MotDDialog</name> + <message> + <location filename="motddialog.ui" line="14"/> + <source>Message of the Day</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="58"/> + <source>about:blank</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="motddialog.ui" line="81"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>MyFileSystemModel</name> + <message> + <location filename="overwriteinfodialog.cpp" line="45"/> + <source>Overwrites</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="57"/> + <source>not implemented</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMAccessManager</name> + <message> + <location filename="nxmaccessmanager.cpp" line="107"/> + <source>timeout</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nxmaccessmanager.cpp" line="145"/> + <source>Please check your password</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NXMUrl</name> + <message> + <location filename="nxmurl.cpp" line="30"/> + <source>invalid nxm-link: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusDialog</name> + <message> + <location filename="nexusdialog.ui" line="14"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="256"/> + <source>Mod ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.ui" line="273"/> + <source>Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="93"/> + <source>new</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="144"/> + <source>login failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="152"/> + <source>login successful</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="235"/> + <source>failed to start download</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusdialog.cpp" line="251"/> + <source>Download started</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>NexusInterface</name> + <message> + <location filename="nexusinterface.cpp" line="177"/> + <source>Failed to guess mod id for "%1", please pick the correct one</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="383"/> + <source>empty response</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="nexusinterface.cpp" line="412"/> + <source>invalid response</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>OverwriteInfoDialog</name> + <message> + <location filename="overwriteinfodialog.ui" line="14"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="86"/> + <source>&Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="87"/> + <source>&Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="88"/> + <source>&Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="89"/> + <source>&New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="133"/> + <source>Failed to delete "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="144"/> + <source>Are sure you want to delete "%1"?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="149"/> + <source>Are sure you want to delete the selected files?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="199"/> + <location filename="overwriteinfodialog.cpp" line="205"/> + <source>New Folder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="overwriteinfodialog.cpp" line="211"/> + <source>Failed to create "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PluginList</name> + <message> + <location filename="pluginlist.cpp" line="82"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="83"/> + <source>Priority</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="84"/> + <source>Mod Index</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="85"/> + <location filename="pluginlist.cpp" line="97"/> + <source>unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="93"/> + <source>Name of your mods</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="94"/> + <source>Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="96"/> + <source>The modindex determins the formids of objects originating from this mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="194"/> + <source>esp not found: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="335"/> + <source>The file containing locked plugin indices is broken</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="349"/> + <location filename="pluginlist.cpp" line="403"/> + <source>failed to open output file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="391"/> + <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="601"/> + <source>min</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="603"/> + <source>max</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="635"/> + <source>This plugin can't be disabled (enforced by the game)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="637"/> + <source>Origin: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Profile</name> + <message> + <location filename="profile.cpp" line="245"/> + <location filename="profile.cpp" line="274"/> + <location filename="profile.cpp" line="358"/> + <location filename="profile.cpp" line="376"/> + <location filename="profile.cpp" line="386"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="339"/> + <source>Overwrite directory couldn't be parsed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="348"/> + <source>invalid priority %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="528"/> + <location filename="profile.cpp" line="555"/> + <source>failed to parse ini file (%1): %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="631"/> + <source>Delete savegames?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="632"/> + <source>Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames)</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfileInputDialog</name> + <message> + <location filename="profileinputdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="20"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="30"/> + <source>If checked, the new profile will use the default game settings.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="33"/> + <source>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profileinputdialog.ui" line="36"/> + <source>Default Game Settings</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>ProfilesDialog</name> + <message> + <location filename="profilesdialog.ui" line="14"/> + <source>Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="22"/> + <source>List of Profiles</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="25"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="38"/> + <location filename="profilesdialog.ui" line="41"/> + <source>If checked, savegames are local to this profile and will not appear when starting with a different profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="44"/> + <source>Local Savegames</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="51"/> + <source>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="54"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="64"/> + <source>Automatic Archive Invalidation</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="75"/> + <location filename="profilesdialog.ui" line="78"/> + <source>Create a new profile from scratch</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="81"/> + <source>Create</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="91"/> + <source>Clone the selected profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="94"/> + <source>This creates a new profile with the same settings and active mods as the selected one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="97"/> + <source>Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="107"/> + <location filename="profilesdialog.ui" line="110"/> + <source>Delete the selected Profile. This can not be un-done!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="113"/> + <source>Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="123"/> + <location filename="profilesdialog.ui" line="126"/> + <source>Transfer save games to the selected profile.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="129"/> + <source>Transfer Saves</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.ui" line="152"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="55"/> + <source>Archive invalidation isn't required for this game.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="95"/> + <location filename="profilesdialog.cpp" line="146"/> + <source>failed to create profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="154"/> + <source>Please enter a name for the new profile</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="162"/> + <source>failed to copy profile: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="169"/> + <source>Are you sure you want to remove this profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="212"/> + <source>failed to change archive invalidation state: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="246"/> + <source>failed to determine if invalidation is active: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="categories.cpp" line="122"/> + <source>Failed to save custom categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="187"/> + <location filename="categories.cpp" line="222"/> + <location filename="categories.cpp" line="232"/> + <location filename="categories.cpp" line="242"/> + <source>invalid index %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="categories.cpp" line="253"/> + <source>invalid category id %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gameinfoimpl.cpp" line="37"/> + <source>invalid game type %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="53"/> + <source>helper failed</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="helper.cpp" line="69"/> + <location filename="helper.cpp" line="90"/> + <source>failed to determine account name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="installationmanager.cpp" line="62"/> + <location filename="selfupdater.cpp" line="46"/> + <source>invalid 7-zip32.dll: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="46"/> + <source>failed to open %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="100"/> + <location filename="loadmechanism.cpp" line="109"/> + <source>%1 not found</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="134"/> + <source>Failed to delete %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="140"/> + <source>Failed to deactivate script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="161"/> + <source>Failed to remove %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="163"/> + <location filename="loadmechanism.cpp" line="255"/> + <source>Failed to rename %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="170"/> + <source>Failed to deactivate proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="204"/> + <location filename="loadmechanism.cpp" line="238"/> + <location filename="loadmechanism.cpp" line="258"/> + <source>Failed to copy %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="209"/> + <source>Failed to set up script extender loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="235"/> + <source>Failed to delete old proxy-dll %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="251"/> + <source>Failed to overwrite %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="loadmechanism.cpp" line="263"/> + <source>Failed to set up proxy-dll loading</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="120"/> + <source>Permissions required</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="121"/> + <source>The current user account doesn't have the required access rights to run Mod Organizer. The neccessary changes can be made automatically (the MO directory will be made writable for the current user account). You will be asked to run "helper.exe" with administrative rights).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="208"/> + <location filename="main.cpp" line="246"/> + <source>Woops</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="209"/> + <source>ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file by email (sherb@gmx.net), the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="247"/> + <source>ModOrganizer has crashed! Unfortunately I was not able to write a diagnostic file: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <location filename="settings.cpp" line="362"/> + <source>Mod Organizer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="286"/> + <source>An instance of Mod Organizer is already running</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="308"/> + <source>No game identified in "%1". The directory is required to contain the game binary and its launcher.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.cpp" line="311"/> + <location filename="main.cpp" line="340"/> + <source>Please select the game to manage</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="557"/> + <source>Please use "Help" from the toolbar to get usage instructions to all elements</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1178"/> + <location filename="mainwindow.cpp" line="2979"/> + <source><Manage...></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="mainwindow.cpp" line="1196"/> + <source>failed to parse profile %1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="292"/> + <location filename="profile.cpp" line="202"/> + <source>failed to find "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="365"/> + <source>encoding error, please report this as a bug and include the file mo_interface.log!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="469"/> + <source>failed to access %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="pluginlist.cpp" line="483"/> + <source>failed to set file time %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="49"/> + <location filename="profile.cpp" line="56"/> + <source>failed to create %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="76"/> + <source>modlist.txt missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profile.cpp" line="82"/> + <source>"%1" is missing</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="profilesdialog.cpp" line="74"/> + <source>Before you can use ModOrganizer, you need to create at least one profile. ATTENTION: Run the game at least once before creating a profile!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="report.cpp" line="29"/> + <location filename="report.cpp" line="32"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="136"/> + <location filename="savegamegamebryo.cpp" line="195"/> + <location filename="savegamegamebryo.cpp" line="237"/> + <source>wrong file format</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegamegamebryo.cpp" line="323"/> + <source>failed to open %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="369"/> + <source>Script Extender</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="376"/> + <source>Proxy DLL</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="77"/> + <source>failed to spawn "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="81"/> + <source>failed to spawn "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="89"/> + <source>"%1" doesn't exist</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="96"/> + <source>failed to inject dll into "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="spawn.cpp" line="104"/> + <source>failed to run "%1"</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QueryOverwriteDialog</name> + <message> + <location filename="queryoverwritedialog.ui" line="14"/> + <source>Mod Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="45"/> + <source>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="63"/> + <source>Keep Backup</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="70"/> + <source>Merge</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="77"/> + <source>Replace</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="84"/> + <source>Rename</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="queryoverwritedialog.ui" line="91"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>QuestionBoxMemory</name> + <message> + <location filename="questionboxmemory.ui" line="86"/> + <source>Remember selection</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidget</name> + <message> + <location filename="savegameinfowidget.ui" line="33"/> + <source>Save #</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="45"/> + <source>Character</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="57"/> + <source>Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="69"/> + <source>Location</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="savegameinfowidget.ui" line="81"/> + <source>Date</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SaveGameInfoWidgetGamebryo</name> + <message> + <location filename="savegameinfowidgetgamebryo.cpp" line="41"/> + <source>Missing ESPs</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelectionDialog</name> + <message> + <location filename="selectiondialog.ui" line="14"/> + <source>Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="23"/> + <source>Placeholder</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selectiondialog.ui" line="77"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SelfUpdater</name> + <message> + <location filename="selfupdater.cpp" line="60"/> + <source>archive.dll not loaded: "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="110"/> + <location filename="selfupdater.cpp" line="134"/> + <location filename="selfupdater.cpp" line="259"/> + <location filename="selfupdater.cpp" line="407"/> + <source>Update</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="111"/> + <source>An update is available (newest version: %1), do you want to install it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="135"/> + <source>Download in progress</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="190"/> + <source>Download failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="201"/> + <source>Failed to install update: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="222"/> + <source>failed to open archive "%1": %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="259"/> + <source>Update installed, Mod Organizer will now be restarted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="287"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="343"/> + <location filename="selfupdater.cpp" line="445"/> + <source>Failed to parse response. Please report this as a bug and include the file mo_interface.log.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="408"/> + <source>No incremental update available for this version, the complete package needs to be downloaded (%1 kB)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="417"/> + <source>no file for update found. Please update manually.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="selfupdater.cpp" line="431"/> + <source>Failed to retrieve update information: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>Settings</name> + <message> + <location filename="settings.cpp" line="227"/> + <source>setting for invalid plugin "%1" requested</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="231"/> + <source>invalid setting "%1" requested for plugin "%2"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="416"/> + <source>Administrative rights required to change this.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settings.cpp" line="452"/> + <source>Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SettingsDialog</name> + <message> + <location filename="settingsdialog.ui" line="14"/> + <source>Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="24"/> + <source>General</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="32"/> + <source>Language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="39"/> + <source>The display language</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="42"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="57"/> + <source>Style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="64"/> + <source>graphical style</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="67"/> + <source>graphical style of the MO user interface</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="78"/> + <source>Log Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="85"/> + <source>Decides the amount of data printed to "ModOrganizer.log"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="88"/> + <source>Decides the amount of data printed to "ModOrganizer.log". +"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="93"/> + <source>Debug</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="98"/> + <source>Info</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="103"/> + <source>Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="113"/> + <source>Advanced</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="125"/> + <location filename="settingsdialog.ui" line="128"/> + <source>Directory where downloads are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="148"/> + <source>Mod Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="155"/> + <source>Directory where mods are stored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="158"/> + <source>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="172"/> + <source>Download Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="179"/> + <source>Cache Directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="205"/> + <source>Reset stored information from dialogs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="208"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="211"/> + <source>Reset Dialogs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="231"/> + <location filename="settingsdialog.ui" line="234"/> + <source>Modify the categories available to arrange your mods.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="237"/> + <source>Configure Mod Categories</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="245"/> + <source>Installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="251"/> + <source>Choose the integrated fomod installer over the external one wherever possible.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="254"/> + <source>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="257"/> + <source>Prefer integrated fomod installer</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="264"/> + <location filename="settingsdialog.ui" line="267"/> + <source>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="270"/> + <source>Enable "Quick Installer"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="294"/> + <location filename="settingsdialog.ui" line="310"/> + <source>Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="300"/> + <source>Allows automatic log-in when the Nexus-Page for the game is clicked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="303"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="319"/> + <source>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="322"/> + <source>Automatically Log-In to Nexus</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="334"/> + <source>Username</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="348"/> + <source>Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="370"/> + <source>Sets up MO as the global handler for NXM links.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="373"/> + <source>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links. +On some systems this will require administrative rights.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="377"/> + <source>Handle NXM Links</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="384"/> + <location filename="settingsdialog.ui" line="387"/> + <source>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="390"/> + <source>Prefer external browser</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="411"/> + <source>Plugins</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="431"/> + <source>Author:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="445"/> + <source>Version:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="459"/> + <source>Description:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="497"/> + <source>Key</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="502"/> + <source>Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="513"/> + <source>Workarounds</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="521"/> + <source>Steam App ID</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="541"/> + <source>The Steam AppID for your game</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="544"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="575"/> + <source>Load Mechanism</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="595"/> + <source>Select loading mechanism. See help for details.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="598"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="617"/> + <source>NMM Version</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="637"/> + <source>The Version of Nexus Mod Manager to impersonate.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="640"/> + <source>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. +On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. +Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. + +tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="662"/> + <source>Enforces that inactive ESPs and ESMs are never loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="665"/> + <source>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. +I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="669"/> + <source>Hide inactive ESPs/ESMs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="676"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="679"/> + <source>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) +Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="683"/> + <source>Force-enable game files</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="693"/> + <location filename="settingsdialog.ui" line="697"/> + <source>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. +For the other games this is not a sufficient replacement for AI!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="701"/> + <source>Back-date BSAs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.ui" line="725"/> + <source>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="85"/> + <source>Select download directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="93"/> + <source>Select mod directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="101"/> + <source>Select cache directory</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="109"/> + <source>Confirm?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="settingsdialog.cpp" line="110"/> + <source>This will make all dialogs show up again where you checked the "Remember selection"-box. Continue?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SimpleInstallDialog</name> + <message> + <location filename="simpleinstalldialog.ui" line="14"/> + <source>Quick Install</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="22"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="49"/> + <location filename="simpleinstalldialog.ui" line="52"/> + <source>Opens a Dialog that allows custom modifications.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="55"/> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="62"/> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="simpleinstalldialog.ui" line="72"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SingleInstance</name> + <message> + <location filename="singleinstance.cpp" line="50"/> + <source>SHM error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="82"/> + <location filename="singleinstance.cpp" line="88"/> + <source>failed to connect to running instance: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="singleinstance.cpp" line="100"/> + <source>failed to receive data from secondary instance: %1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>SyncOverwriteDialog</name> + <message> + <location filename="syncoverwritedialog.ui" line="14"/> + <source>Sync Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="27"/> + <source>Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.ui" line="32"/> + <source>Sync To</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="83"/> + <source><don't sync></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="132"/> + <source>failed to remove %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="syncoverwritedialog.cpp" line="134"/> + <source>failed to move %1 to %2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TransferSavesDialog</name> + <message> + <location filename="transfersavesdialog.ui" line="14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="22"/> + <source>Global Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="29"/> + <source>This is a list of characters in the global location.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="32"/> + <source>This is a list of characters in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="46"/> + <source>This is a list of save games for the selected character in the global location. + +On Windows Vista/Windows 7: + C:\Users\[UserName]\Documents\My Games\Skyrim\Saves + +On Windows XP: + C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves + +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="87"/> + <source>Move -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="97"/> + <source>Copy -></source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="123"/> + <source><- Move</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="133"/> + <source><- Copy</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="156"/> + <source>Done</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.ui" line="167"/> + <source>Profile Characters</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="136"/> + <source>Overwrite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="137"/> + <source>Overwrite the file "%1"</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="160"/> + <location filename="transfersavesdialog.cpp" line="198"/> + <location filename="transfersavesdialog.cpp" line="233"/> + <location filename="transfersavesdialog.cpp" line="272"/> + <source>Confirm</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="161"/> + <location filename="transfersavesdialog.cpp" line="199"/> + <source>Copy all save games of character "%1" to the profile?</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="234"/> + <source>Move all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="transfersavesdialog.cpp" line="273"/> + <source>Copy all save games of character "%1" to the global location? Please be aware that this will mess up the running number of save games.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp new file mode 100644 index 00000000..1af73b7b --- /dev/null +++ b/src/overwriteinfodialog.cpp @@ -0,0 +1,250 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "overwriteinfodialog.h"
+#include "ui_overwriteinfodialog.h"
+#include "report.h"
+#include "utility.h"
+#include <QMessageBox>
+#include <QMenu>
+#include <Shlwapi.h>
+
+
+class MyFileSystemModel : public QFileSystemModel {
+
+public:
+ MyFileSystemModel(QObject *parent)
+ : QFileSystemModel(parent), m_RegularColumnCount(0) {}
+
+ virtual int columnCount(const QModelIndex &parent) const {
+ m_RegularColumnCount = QFileSystemModel::columnCount(parent);
+// return m_RegularColumnCount + 1;
+ return m_RegularColumnCount;
+ }
+
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const {
+ if ((orientation == Qt::Horizontal) &&
+ (section >= m_RegularColumnCount)) {
+ if (role == Qt::DisplayRole) {
+ return tr("Overwrites");
+ } else {
+ return QVariant();
+ }
+ } else {
+ return QFileSystemModel::headerData(section, orientation, role);
+ }
+ }
+
+ virtual QVariant data(const QModelIndex &index, int role) const {
+ if (index.column() == m_RegularColumnCount + 0) {
+ if (role == Qt::DisplayRole) {
+ return tr("not implemented");
+ } else {
+ return QVariant();
+ }
+ } else {
+ return QFileSystemModel::data(index, role);
+ }
+ }
+
+private:
+ mutable int m_RegularColumnCount;
+};
+
+
+OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent)
+ : QDialog(parent), ui(new Ui::OverwriteInfoDialog), m_FileSystemModel(NULL),
+ m_DeleteAction(NULL), m_RenameAction(NULL), m_OpenAction(NULL)
+{
+ ui->setupUi(this);
+
+ QString path = modInfo->absolutePath();
+ m_FileSystemModel = new MyFileSystemModel(this);
+ m_FileSystemModel->setReadOnly(false);
+ m_FileSystemModel->setRootPath(path);
+ ui->filesView->setModel(m_FileSystemModel);
+ ui->filesView->setRootIndex(m_FileSystemModel->index(path));
+ ui->filesView->setColumnWidth(0, 250);
+// ui->filesView->header()->hideSection(3);
+
+ m_DeleteAction = new QAction(tr("&Delete"), ui->filesView);
+ m_RenameAction = new QAction(tr("&Rename"), ui->filesView);
+ m_OpenAction = new QAction(tr("&Open"), ui->filesView);
+ m_NewFolderAction = new QAction(tr("&New Folder"), ui->filesView);
+ QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered()));
+ QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered()));
+ QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered()));
+ QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered()));
+}
+
+OverwriteInfoDialog::~OverwriteInfoDialog()
+{
+ delete ui;
+}
+
+
+bool OverwriteInfoDialog::recursiveDelete(const QModelIndex &index)
+{
+ for (int childRow = 0; childRow < m_FileSystemModel->rowCount(index); ++childRow) {
+ QModelIndex childIndex = m_FileSystemModel->index(childRow, 0, index);
+ if (m_FileSystemModel->isDir(childIndex)) {
+ if (!recursiveDelete(childIndex)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData());
+ return false;
+ }
+ } else {
+ if (!m_FileSystemModel->remove(childIndex)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(childIndex).toUtf8().constData());
+ return false;
+ }
+ }
+ }
+ if (!m_FileSystemModel->remove(index)) {
+ qCritical("failed to delete %s", m_FileSystemModel->fileName(index).toUtf8().constData());
+ return false;
+ }
+ return true;
+}
+
+
+void OverwriteInfoDialog::deleteFile(const QModelIndex &index)
+{
+
+ bool res = m_FileSystemModel->isDir(index) ? recursiveDelete(index)
+ : m_FileSystemModel->remove(index);
+ if (!res) {
+ QString fileName = m_FileSystemModel->fileName(index);
+ reportError(tr("Failed to delete \"%1\"").arg(fileName));
+ }
+}
+
+
+void OverwriteInfoDialog::deleteTriggered()
+{
+ if (m_FileSelection.count() == 0) {
+ return;
+ } else if (m_FileSelection.count() == 1) {
+ QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0));
+ if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete \"%1\"?").arg(fileName),
+ QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
+ return;
+ }
+ } else {
+ if (QMessageBox::question(this, tr("Confirm"), tr("Are sure you want to delete the selected files?"),
+ QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
+ return;
+ }
+ }
+
+ foreach(QModelIndex index, m_FileSelection) {
+ deleteFile(index);
+ }
+}
+
+
+void OverwriteInfoDialog::renameTriggered()
+{
+ QModelIndex selection = m_FileSelection.at(0);
+ QModelIndex index = selection.sibling(selection.row(), 0);
+ if (!index.isValid() || m_FileSystemModel->isReadOnly()) {
+ return;
+ }
+
+ ui->filesView->edit(index);
+}
+
+
+void OverwriteInfoDialog::openFile(const QModelIndex &index)
+{
+ QString fileName = m_FileSystemModel->filePath(index);
+
+ HINSTANCE res = ::ShellExecuteW(NULL, L"open", ToWString(fileName).c_str(), NULL, NULL, SW_SHOW);
+ if ((int)res <= 32) {
+ qCritical("failed to invoke %s: %d", fileName.toUtf8().constData(), res);
+ }
+}
+
+
+void OverwriteInfoDialog::openTriggered()
+{
+ foreach(QModelIndex idx, m_FileSelection) {
+ openFile(idx);
+ }
+}
+
+void OverwriteInfoDialog::createDirectoryTriggered()
+{
+ QModelIndex selection = m_FileSelection.at(0);
+
+ QModelIndex index = m_FileSystemModel->isDir(selection) ? selection
+ : selection.parent();
+ index = index.sibling(index.row(), 0);
+
+ QString name = tr("New Folder");
+ QString path = m_FileSystemModel->filePath(index).append("/");
+
+ QModelIndex existingIndex = m_FileSystemModel->index(path + name);
+ int suffix = 1;
+ while (existingIndex.isValid()) {
+ name = tr("New Folder") + QString::number(suffix++);
+ existingIndex = m_FileSystemModel->index(path + name);
+ }
+
+ QModelIndex newIndex = m_FileSystemModel->mkdir(index, name);
+ if (!newIndex.isValid()) {
+ reportError(tr("Failed to create \"%1\"").arg(name));
+ return;
+ }
+
+ ui->filesView->setCurrentIndex(newIndex);
+ ui->filesView->edit(newIndex);
+}
+
+
+void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos)
+{
+ QItemSelectionModel *selectionModel = ui->filesView->selectionModel();
+ m_FileSelection = selectionModel->selectedRows(0);
+
+// m_FileSelection = m_FileTree->indexAt(pos);
+ QMenu menu(ui->filesView);
+
+ menu.addAction(m_NewFolderAction);
+
+ bool hasFiles = false;
+
+ foreach(QModelIndex idx, m_FileSelection) {
+ if (m_FileSystemModel->fileInfo(idx).isFile()) {
+ hasFiles = true;
+ break;
+ }
+ }
+
+ if (selectionModel->hasSelection()) {
+ if (hasFiles) {
+ menu.addAction(m_OpenAction);
+ }
+ menu.addAction(m_RenameAction);
+ menu.addAction(m_DeleteAction);
+ } else {
+ m_FileSelection.clear();
+ m_FileSelection.append(m_FileSystemModel->index(m_FileSystemModel->rootPath(), 0));
+ }
+ menu.exec(ui->filesView->mapToGlobal(pos));
+}
diff --git a/src/overwriteinfodialog.h b/src/overwriteinfodialog.h new file mode 100644 index 00000000..a60e0571 --- /dev/null +++ b/src/overwriteinfodialog.h @@ -0,0 +1,67 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef OVERWRITEINFODIALOG_H
+#define OVERWRITEINFODIALOG_H
+
+#include "modinfo.h"
+#include <QDialog>
+#include <QFileSystemModel>
+
+namespace Ui {
+class OverwriteInfoDialog;
+}
+
+class OverwriteInfoDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ explicit OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent = 0);
+ ~OverwriteInfoDialog();
+
+private:
+
+ void openFile(const QModelIndex &index);
+ bool recursiveDelete(const QModelIndex &index);
+ void deleteFile(const QModelIndex &index);
+
+private slots:
+
+ void deleteTriggered();
+ void renameTriggered();
+ void openTriggered();
+ void createDirectoryTriggered();
+
+ void on_filesView_customContextMenuRequested(const QPoint &pos);
+
+private:
+
+ Ui::OverwriteInfoDialog *ui;
+ QFileSystemModel *m_FileSystemModel;
+ QModelIndexList m_FileSelection;
+ QAction *m_DeleteAction;
+ QAction *m_RenameAction;
+ QAction *m_OpenAction;
+ QAction *m_NewFolderAction;
+
+};
+
+#endif // OVERWRITEINFODIALOG_H
diff --git a/src/overwriteinfodialog.ui b/src/overwriteinfodialog.ui new file mode 100644 index 00000000..2aa1bcd8 --- /dev/null +++ b/src/overwriteinfodialog.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OverwriteInfoDialog</class>
+ <widget class="QDialog" name="OverwriteInfoDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>710</width>
+ <height>418</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Overwrite</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTreeView" name="filesView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>OverwriteInfoDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>OverwriteInfoDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp new file mode 100644 index 00000000..72a8563b --- /dev/null +++ b/src/pluginlist.cpp @@ -0,0 +1,851 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "pluginlist.h"
+#include "report.h"
+#include "inject.h"
+#include <utility.h>
+#include "settings.h"
+#include <gameinfo.h>
+#include <windows_error.h>
+
+#include <QtDebug>
+#include <QMessageBox>
+#include <QMimeData>
+#include <QCoreApplication>
+#include <QDir>
+#include <QTextCodec>
+#include <QFileInfo>
+#include <QListWidgetItem>
+#include <QString>
+#include <QApplication>
+#include <QKeyEvent>
+#include <QSortFilterProxyModel>
+
+#include <tchar.h>
+#include <ctime>
+#include <algorithm>
+#include <stdexcept>
+
+
+
+bool ByName(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo& RHS) {
+ return LHS.m_Name.toUpper() < RHS.m_Name.toUpper();
+}
+
+bool ByPriority(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo& RHS) {
+ if (LHS.m_IsMaster && !RHS.m_IsMaster) {
+ return true;
+ } else if (!LHS.m_IsMaster && RHS.m_IsMaster) {
+ return false;
+ } else {
+ return LHS.m_Priority < RHS.m_Priority;
+ }
+}
+
+bool ByDate(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo& RHS) {
+ QString lhsExtension = LHS.m_Name.right(3).toLower();
+ QString rhsExtension = RHS.m_Name.right(3).toLower();
+ if (lhsExtension != rhsExtension) {
+ return lhsExtension == "esm";
+ }
+
+ return ::CompareFileTime(&LHS.m_Time, &RHS.m_Time) < 0;
+}
+
+PluginList::PluginList(QObject *parent)
+ : QAbstractTableModel(parent), m_Modified(false),
+ m_FontMetrics(QFont())
+{
+}
+
+
+QString PluginList::getColumnName(int column)
+{
+ switch (column) {
+ case COL_NAME: return tr("Name");
+ case COL_PRIORITY: return tr("Priority");
+ case COL_MODINDEX: return tr("Mod Index");
+ default: return tr("unknown");
+ }
+}
+
+
+QString PluginList::getColumnToolTip(int column)
+{
+ switch (column) {
+ case COL_NAME: return tr("Name of your mods");
+ case COL_PRIORITY: return tr("Load priority of your mod. The higher, the more \"important\" it is and thus "
+ "overwrites data from plugins with lower priority.");
+ case COL_MODINDEX: return tr("The modindex determins the formids of objects originating from this mods.");
+ default: return tr("unknown");
+ }
+}
+
+
+void PluginList::refresh(const QString &profileName, const DirectoryEntry &baseDirectory,
+ const QString &pluginsFile, const QString &loadOrderFile,
+ const QString &lockedOrderFile)
+{
+ emit layoutAboutToBeChanged();
+ m_ESPsByName.clear();
+ m_ESPsByPriority.clear();
+ m_ESPs.clear();
+ std::vector<std::wstring> primaryPlugins = GameInfo::instance().getPrimaryPlugins();
+
+ m_CurrentProfile = profileName;
+
+ std::vector<FileEntry*> files = baseDirectory.getFiles();
+ for (auto iter = files.begin(); iter != files.end(); ++iter) {
+ FileEntry *current = *iter;
+ if (current == NULL) {
+ continue;
+ }
+ QString filename = QString::fromUtf16(current->getName().c_str());
+ QString extension = filename.right(3).toLower();
+
+ if ((extension == "esp") || (extension == "esm")) {
+ bool forceEnabled = Settings::instance().forceEnableCoreFiles() &&
+ std::find(primaryPlugins.begin(), primaryPlugins.end(), ToWString(filename.toLower())) != primaryPlugins.end();
+
+ bool archive = false;
+ FilesOrigin &origin = baseDirectory.getOriginByID(current->getOrigin(archive));
+ m_ESPs.push_back(ESPInfo(filename, forceEnabled, current->getFileTime(), ToQString(origin.getName())));
+ }
+ }
+
+ if (readLoadOrder(loadOrderFile)) {
+ int maxPriority = 0;
+ // assign known load orders
+ for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) {
+ std::map<QString, int>::const_iterator priorityIter = m_ESPLoadOrder.find(espIter->m_Name.toLower());
+ if (priorityIter != m_ESPLoadOrder.end()) {
+ if (priorityIter->second > maxPriority) {
+ maxPriority = priorityIter->second;
+ }
+ espIter->m_Priority = priorityIter->second;
+ } else {
+ espIter->m_Priority = -1;
+ }
+ }
+
+ ++maxPriority;
+
+ // assign maximum priorities for plugins with unknown priority
+ for (std::vector<ESPInfo>::iterator espIter = m_ESPs.begin(); espIter != m_ESPs.end(); ++espIter) {
+ if (espIter->m_Priority == -1) {
+ espIter->m_Priority = maxPriority++;
+ }
+ }
+ } else {
+ // no load order stored, determine by date
+ std::sort(m_ESPs.begin(), m_ESPs.end(), ByDate);
+
+ for (size_t i = 0; i < m_ESPs.size(); ++i) {
+ m_ESPs[i].m_Priority = i;
+ }
+ }
+
+ std::sort(m_ESPs.begin(), m_ESPs.end(), ByPriority); // first, sort by priority
+ // remove gaps from the priorities so we can use them as array indices without overflow
+ for (int i = 0; i < static_cast<int>(m_ESPs.size()); ++i) {
+ m_ESPs[i].m_Priority = i;
+ }
+
+ std::sort(m_ESPs.begin(), m_ESPs.end(), ByName); // sort by name so alphabetical sorting works
+
+ updateIndices();
+
+ readEnabledFrom(pluginsFile);
+
+ readLockedOrderFrom(lockedOrderFile);
+
+ refreshLoadOrder();
+
+ emit layoutChanged();
+ emit dataChanged(this->index(0, 0), this->index(m_ESPs.size(), 1));
+}
+
+
+void PluginList::enableESP(const QString &name)
+{
+ std::map<QString, int>::iterator iter = m_ESPsByName.find(name.toLower());
+
+ if (iter != m_ESPsByName.end()) {
+ m_ESPs[iter->second].m_Enabled = true;
+ m_Modified = true;
+ } else {
+ reportError(tr("esp not found: %1").arg(name));
+ }
+}
+
+
+void PluginList::enableAll()
+{
+ for (std::vector<ESPInfo>::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) {
+ iter->m_Enabled = true;
+ }
+ m_Modified = true;
+ emit esplist_changed();
+}
+
+
+void PluginList::disableAll()
+{
+ for (std::vector<ESPInfo>::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) {
+ if (!iter->m_ForceEnabled) {
+ iter->m_Enabled = false;
+ }
+ }
+ m_Modified = true;
+ emit esplist_changed();
+}
+
+
+bool PluginList::isEnabled(const QString &name)
+{
+ std::map<QString, int>::iterator iter = m_ESPsByName.find(name.toLower());
+
+ if (iter != m_ESPsByName.end()) {
+ return m_ESPs[iter->second].m_Enabled;
+ } else {
+ return false;
+ }
+}
+
+
+bool PluginList::isEnabled(int index)
+{
+ return m_ESPs.at(index).m_Enabled;
+}
+
+
+bool PluginList::readLoadOrder(const QString &fileName)
+{
+ std::set<QString> availableESPs;
+ for (std::vector<ESPInfo>::const_iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) {
+ availableESPs.insert(iter->m_Name.toLower());
+ }
+
+ m_ESPLoadOrder.clear();
+
+ int priority = 0;
+
+ std::vector<std::wstring> primaryPlugins = GameInfo::instance().getPrimaryPlugins();
+ for (std::vector<std::wstring>::iterator iter = primaryPlugins.begin();
+ iter != primaryPlugins.end(); ++iter) {
+ if (availableESPs.find(ToQString(*iter)) != availableESPs.end()) {
+ m_ESPLoadOrder[ToQString(*iter)] = priority++;
+ }
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ return false;
+ }
+ while (!file.atEnd()) {
+ QByteArray line = file.readLine().trimmed();
+ QString modName;
+ if ((line.size() > 0) && (line.at(0) != '#')) {
+ modName = QString::fromUtf8(line.constData()).toLower();
+ }
+
+ if ((modName.size() > 0) &&
+ (m_ESPLoadOrder.find(modName) == m_ESPLoadOrder.end()) &&
+ (availableESPs.find(modName) != availableESPs.end())) {
+ m_ESPLoadOrder[modName] = priority++;
+ }
+ }
+
+ file.close();
+ return true;
+}
+
+
+void PluginList::readEnabledFrom(const QString &fileName)
+{
+ for (std::vector<ESPInfo>::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) {
+ if (!iter->m_ForceEnabled) {
+ iter->m_Enabled = false;
+ }
+ iter->m_LoadOrder = -1;
+ }
+
+ QFile file(fileName);
+ if (!file.exists()) {
+ throw std::runtime_error(QObject::tr("failed to find \"%1\"").arg(fileName).toUtf8().constData());
+ }
+
+ file.open(QIODevice::ReadOnly);
+ while (!file.atEnd()) {
+ QByteArray line = file.readLine();
+ QString modName;
+ if ((line.size() > 0) && (line.at(0) != '#')) {
+ modName = QString::fromUtf8(line.trimmed().constData());
+ }
+ if (modName.size() > 0) {
+ std::map<QString, int>::iterator iter = m_ESPsByName.find(modName.toLower());
+ if (iter != m_ESPsByName.end()) {
+ m_ESPs[iter->second].m_Enabled = true;
+ } else {
+ qWarning("plugin %s not found", modName.toUtf8().constData());
+ m_Modified = true;
+ }
+ }
+ }
+
+ file.close();
+}
+
+
+void PluginList::readLockedOrderFrom(const QString &fileName)
+{
+ m_LockedOrder.clear();
+
+ QFile file(fileName);
+ if (!file.exists()) {
+ // no locked load order, that's ok
+ return;
+ }
+
+ file.open(QIODevice::ReadOnly);
+ while (!file.atEnd()) {
+ QByteArray line = file.readLine();
+ if ((line.size() > 0) && (line.at(0) != '#')) {
+ QList<QByteArray> fields = line.split('|');
+ if (fields.count() == 2) {
+ m_LockedOrder[QString::fromUtf8(fields.at(0))] = fields.at(1).trimmed().toInt();
+ } else {
+ reportError(tr("The file containing locked plugin indices is broken"));
+ break;
+ }
+ }
+ }
+
+ file.close();
+}
+
+
+void PluginList::writePlugins(const QString &fileName, bool writeUnchecked) const
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ throw MyException(tr("failed to open output file: %1").arg(fileName));
+ }
+
+ QTextCodec *textCodec = writeUnchecked ? QTextCodec::codecForName("utf-8")
+ : QTextCodec::codecForName("Windows-1252");
+
+ if (textCodec == NULL) {
+ QList<QByteArray> encodingList = QTextCodec::availableCodecs();
+ QString encodings;
+ QTextStream temp(&encodings);
+ foreach (QByteArray encoding, encodingList) {
+ temp << encoding << ", ";
+ }
+ qCritical("required string-encoding not supported. Available codecs: %s",
+ encodings.toUtf8().constData());
+
+ throw std::runtime_error(QObject::tr("encoding error, please report this as a bug and include the file "
+ "mo_interface.log!").toUtf8().constData());
+ }
+
+ file.resize(0);
+
+ file.write(textCodec->fromUnicode("# This file was automatically generated by Mod Organizer.\r\n"));
+
+ bool invalidFileNames = false;
+
+ for (size_t i = 0; i < m_ESPs.size(); ++i) {
+ int priority = m_ESPsByPriority[i];
+ if ((m_ESPs[priority].m_Enabled || writeUnchecked) && !m_ESPs[priority].m_Removed) {
+ //file.write(m_ESPs[priority].m_Name.toUtf8());
+ if (!textCodec->canEncode(m_ESPs[priority].m_Name)) {
+ invalidFileNames = true;
+ qCritical("invalid plugin name %s", m_ESPs[priority].m_Name.toUtf8().constData());
+ } else {
+ file.write(textCodec->fromUnicode(m_ESPs[priority].m_Name));
+ }
+ file.write("\r\n");
+ }
+ }
+ file.close();
+
+ if (invalidFileNames) {
+ reportError(tr("Some of your plugins have invalid names! These plugins can not be loaded by the game. "
+ "Please see mo_interface.log for a list of affected plugins and rename them."));
+ }
+
+ qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
+}
+
+
+void PluginList::writeLockedOrder(const QString &fileName) const
+{
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ throw MyException(tr("failed to open output file: %1").arg(fileName));
+ }
+
+ file.resize(0);
+ file.write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8());
+ for (auto iter = m_LockedOrder.begin(); iter != m_LockedOrder.end(); ++iter) {
+ file.write(QString("%1|%2\r\n").arg(iter->first).arg(iter->second).toUtf8());
+ }
+ file.close();
+}
+
+
+void PluginList::saveTo(const QString &pluginFileName, const QString &loadOrderFileName, const QString &lockedOrderFileName, const QString& deleterFileName, bool hideUnchecked) const
+{
+ if (!m_Modified) {
+ return;
+ }
+
+ writePlugins(pluginFileName, false);
+ writePlugins(loadOrderFileName, true);
+ writeLockedOrder(lockedOrderFileName);
+
+ if (hideUnchecked) {
+ QFile deleterFile(deleterFileName);
+ deleterFile.open(QIODevice::WriteOnly);
+ deleterFile.resize(0);
+ deleterFile.write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8());
+
+ for (size_t i = 0; i < m_ESPs.size(); ++i) {
+ int priority = m_ESPsByPriority[i];
+ if (m_ESPs[priority].m_Removed) {
+ deleterFile.write(m_ESPs[priority].m_Name.toUtf8());
+ deleterFile.write("\r\n");
+ }
+ }
+ deleterFile.close();
+ qDebug("%s saved", QDir::toNativeSeparators(deleterFileName).toUtf8().constData());
+ }
+
+ m_Modified = false;
+}
+
+
+bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure)
+{
+ if (GameInfo::instance().getLoadOrderMechanism() != GameInfo::TYPE_FILETIME) {
+ // nothing to do
+ return true;
+ }
+
+ for (std::vector<ESPInfo>::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) {
+ std::wstring espName = ToWString(iter->m_Name);
+ const FileEntry *fileEntry = directoryStructure.findFile(espName);
+ if (fileEntry != NULL) {
+ QString fileName;
+ bool archive = false;
+ int originid = fileEntry->getOrigin(archive);
+ fileName = QString("%1\\%2").arg(QDir::toNativeSeparators(ToQString(directoryStructure.getOriginByID(originid).getPath()))).arg(iter->m_Name);
+
+ HANDLE file = ::CreateFile(ToWString(fileName).c_str(), GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ if (::GetLastError() == ERROR_SHARING_VIOLATION) {
+ // file is locked, probably the game is running
+ return false;
+ } else {
+ throw windows_error(QObject::tr("failed to access %1").arg(fileName).toUtf8().constData());
+ }
+ }
+
+ ULONGLONG temp = 0;
+ temp = (145731ULL + iter->m_Priority) * 24 * 60 * 60 * 10000000ULL;
+
+ FILETIME newWriteTime;
+
+ newWriteTime.dwLowDateTime = (DWORD)(temp & 0xFFFFFFFF);
+ newWriteTime.dwHighDateTime = (DWORD)(temp >> 32);
+ iter->m_Time = newWriteTime;
+ fileEntry->setFileTime(newWriteTime);
+ if (!::SetFileTime(file, NULL, NULL, &newWriteTime)) {
+ throw windows_error(QObject::tr("failed to set file time %1").arg(fileName).toUtf8().constData());
+ }
+
+ CloseHandle(file);
+ }
+ }
+ return true;
+}
+
+bool PluginList::isESPLocked(int index) const
+{
+ return m_LockedOrder.find(m_ESPs.at(index).m_Name.toLower()) != m_LockedOrder.end();
+}
+
+
+void PluginList::lockESPIndex(int index, bool lock)
+{
+ if (lock) {
+ m_LockedOrder[getName(index).toLower()] = m_ESPs.at(index).m_LoadOrder;
+ } else {
+ auto iter = m_LockedOrder.find(getName(index).toLower());
+ if (iter != m_LockedOrder.end()) {
+ m_LockedOrder.erase(iter);
+ }
+ }
+ m_Modified = true;
+ emit esplist_changed();
+}
+
+
+void PluginList::syncLoadOrder()
+{
+ int loadOrder = 0;
+ for (unsigned int i = 0; i < m_ESPs.size(); ++i) {
+ int index = m_ESPsByPriority[i];
+
+ if (m_ESPs[index].m_Enabled) {
+ m_ESPs[index].m_LoadOrder = loadOrder++;
+ } else {
+ m_ESPs[index].m_LoadOrder = -1;
+ }
+ }
+}
+
+void PluginList::refreshLoadOrder()
+{
+ syncLoadOrder();
+
+ // set priorities according to locked load order
+ std::map<int, QString> lockedLoadOrder;
+ std::for_each(m_LockedOrder.begin(), m_LockedOrder.end(),
+ [&lockedLoadOrder] (const std::pair<QString, int> &ele) { lockedLoadOrder[ele.second] = ele.first; });
+
+ int targetPrio = 0;
+ // this is guaranteed to iterate from lowest key (load order) to highest
+ for (auto iter = lockedLoadOrder.begin(); iter != lockedLoadOrder.end(); ++iter) {
+ auto nameIter = m_ESPsByName.find(iter->second);
+ if (nameIter != m_ESPsByName.end()) {
+ // locked esp exists
+
+ // find the location to insert at
+ while ((targetPrio < static_cast<int>(m_ESPs.size())) &&
+ (m_ESPs[m_ESPsByPriority[targetPrio]].m_LoadOrder < iter->first)) {
+ if (QString::compare(m_ESPs[m_ESPsByPriority[targetPrio]].m_Name, iter->second) != 0) {
+ ++targetPrio;
+ }
+ }
+ int temp = targetPrio;
+ if (m_ESPs[nameIter->second].m_Priority != temp) {
+ setPluginPriority(nameIter->second, temp);
+ m_ESPs[nameIter->second].m_LoadOrder = iter->first;
+ syncLoadOrder();
+ m_Modified = true;
+ }
+ }
+ }
+}
+
+
+void PluginList::updateIndices()
+{
+ m_ESPsByName.clear();
+ m_ESPsByPriority.clear();
+ m_ESPsByPriority.resize(m_ESPs.size());
+
+ for (unsigned int i = 0; i < m_ESPs.size(); ++i) {
+ m_ESPsByName[m_ESPs[i].m_Name.toLower()] = i;
+ m_ESPsByPriority[m_ESPs[i].m_Priority] = i;
+ }
+}
+
+
+int PluginList::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid()) {
+ return m_ESPs.size();
+ } else {
+ return 0;
+ }
+}
+
+int PluginList::columnCount(const QModelIndex &) const
+{
+ return 3;
+}
+
+
+QVariant PluginList::data(const QModelIndex &modelIndex, int role) const
+{
+ int index = modelIndex.row();
+
+ if (role == Qt::DisplayRole) {
+ switch (modelIndex.column()) {
+ case COL_NAME: {
+ return m_ESPs[index].m_Name;
+ } break;
+ case COL_PRIORITY: {
+ if (m_ESPs[index].m_Priority == 0) {
+ return tr("min");
+ } else if (m_ESPs[index].m_Priority == m_ESPs.size() - 1) {
+ return tr("max");
+ } else {
+ return QString::number(m_ESPs[index].m_Priority);
+ }
+ } break;
+ case COL_MODINDEX: {
+ if (m_ESPs[index].m_LoadOrder == -1) {
+ return QString();
+ } else {
+ return QString("%1").arg(m_ESPs[index].m_LoadOrder, 2, 16, QChar('0')).toUpper();
+ }
+ } break;
+ default: {
+ return QVariant();
+ } break;
+ }
+ } else if ((role == Qt::DecorationRole) && (modelIndex.column() == 0)) {
+ if (m_LockedOrder.find(m_ESPs[index].m_Name.toLower()) != m_LockedOrder.end()) {
+ return QIcon(":/MO/gui/locked");
+ } else {
+ return QVariant();
+ }
+ } else if ((role == Qt::CheckStateRole) && (modelIndex.column() == 0)) {
+ return m_ESPs[index].m_Enabled ? Qt::Checked : Qt::Unchecked;
+ } else if (role == Qt::TextAlignmentRole) {
+ if (modelIndex.column() == 0) {
+ return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
+ } else {
+ return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
+ }
+ } else if (role == Qt::ToolTipRole) {
+ if (m_ESPs[index].m_ForceEnabled) {
+ return tr("This plugin can't be disabled (enforced by the game)");
+ } else {
+ return tr("Origin: %1").arg(m_ESPs[index].m_OriginName);
+ }
+ } else {
+ return QVariant();
+ }
+}
+
+
+bool PluginList::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == Qt::CheckStateRole) {
+ m_ESPs[index.row()].m_Enabled = value.toInt() == Qt::Checked;
+
+ emit layoutAboutToBeChanged();
+
+ refreshLoadOrder();
+ m_Modified = true;
+ emit esplist_changed();
+
+ emit layoutChanged();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+QVariant PluginList::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ if (role == Qt::DisplayRole) {
+ return getColumnName(section);
+ } else if (role == Qt::ToolTipRole) {
+ return getColumnToolTip(section);
+ } else if (role == Qt::SizeHintRole) {
+ QSize temp = m_FontMetrics.size(Qt::TextSingleLine, getColumnName(section));
+ temp.rwidth() += 25;
+ temp.rheight() += 12;
+ return temp;
+ }
+ }
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+
+Qt::ItemFlags PluginList::flags(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+ Qt::ItemFlags result = QAbstractTableModel::flags(modelIndex);
+
+ if (modelIndex.isValid()) {
+ if ((m_ESPs[index].m_ForceEnabled)) {
+ result &= ~Qt::ItemIsEnabled;
+ }
+ result |= Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
+ } else {
+ result |= Qt::ItemIsDropEnabled;
+ }
+
+ return result;
+}
+
+
+void PluginList::setPluginPriority(int row, int &newPriority)
+{
+ int newPriorityTemp = newPriority;
+
+ QString sourceExtension = m_ESPs[row].m_Name.right(3).toLower();
+ if (sourceExtension == "esp") {
+ // don't allow esps to be moved above esms
+ while ((newPriorityTemp < static_cast<int>(m_ESPsByPriority.size() - 1)) &&
+ (m_ESPs[m_ESPsByPriority[newPriorityTemp]].m_Name.right(3).toLower() == "esm")) {
+ ++newPriorityTemp;
+ }
+ } else {
+ // don't allow esms to be moved below esps
+ while ((newPriorityTemp > 0) &&
+ (m_ESPs[m_ESPsByPriority[newPriorityTemp - 1]].m_Name.right(3).toLower() == "esp")) {
+ --newPriorityTemp;
+ }
+ // also don't allow "regular" esms to be moved above primary plugins
+ while ((newPriorityTemp < static_cast<int>(m_ESPsByPriority.size() - 1)) &&
+ (m_ESPs[m_ESPsByPriority[newPriorityTemp]].m_ForceEnabled)) {
+ ++newPriorityTemp;
+ }
+ }
+
+ int oldPriority = m_ESPs[row].m_Priority;
+ if (newPriorityTemp > oldPriority) {
+ // priority is higher than the old, so the gap we left is in lower priorities
+ for (int i = oldPriority + 1; i <= newPriorityTemp; ++i) {
+ --m_ESPs[m_ESPsByPriority[i]].m_Priority;
+ }
+ } else {
+ for (int i = newPriorityTemp; i < oldPriority; ++i) {
+ ++m_ESPs[m_ESPsByPriority[i]].m_Priority;
+ }
+ ++newPriority;
+ }
+
+ m_ESPs[row].m_Priority = newPriorityTemp;
+ updateIndices();
+}
+
+
+void PluginList::changePluginPriority(std::vector<int> rows, int newPriority)
+{
+ emit layoutAboutToBeChanged();
+ // sort rows to insert by their old priority (ascending) and insert them move them in that order
+ const std::vector<ESPInfo> &esp = m_ESPs;
+ std::sort(rows.begin(), rows.end(),
+ [&esp](const int &LHS, const int &RHS) {
+ return esp[LHS].m_Priority < esp[RHS].m_Priority;
+ });
+
+ // odd stuff: if any of the dragged sources has priority lower than the destination then the
+ // target idx is that of the row BELOW the dropped location, otherwise it's the one above. why?
+ for (std::vector<int>::const_iterator iter = rows.begin();
+ iter != rows.end(); ++iter) {
+ if (m_ESPs[*iter].m_Priority < newPriority) {
+ --newPriority;
+ break;
+ }
+ }
+
+ for (std::vector<int>::const_iterator iter = rows.begin(); iter != rows.end(); ++iter) {
+ setPluginPriority(*iter, newPriority);
+ }
+ refreshLoadOrder();
+
+ emit esplist_changed();
+
+ m_Modified = true;
+
+ emit layoutChanged();
+}
+
+
+bool PluginList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction) {
+ return true;
+ }
+
+ QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist");
+ QDataStream stream(&encoded, QIODevice::ReadOnly);
+
+ std::vector<int> sourceRows;
+
+ while (!stream.atEnd()) {
+ int sourceRow, col;
+ QMap<int, QVariant> roleDataMap;
+ stream >> sourceRow >> col >> roleDataMap;
+ if (col == 0) { // only add each row once
+ sourceRows.push_back(sourceRow);
+ }
+ }
+
+ if (row == -1) {
+ row = parent.row();
+ }
+
+ int newPriority = 0;
+
+ if ((row < 0) ||
+ (row >= static_cast<int>(m_ESPs.size()))) {
+ newPriority = m_ESPs.size();
+ } else {
+ newPriority = m_ESPs[row].m_Priority;
+ }
+ changePluginPriority(sourceRows, newPriority);
+
+
+ return false;
+}
+
+
+bool PluginList::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::KeyPress) {
+ QAbstractItemView *itemView = qobject_cast<QAbstractItemView*>(obj);
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
+ if ((itemView != NULL) &&
+ (keyEvent->modifiers() == Qt::ControlModifier) &&
+ ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) {
+ QItemSelectionModel *selectionModel = itemView->selectionModel();
+ const QSortFilterProxyModel *proxyModel = qobject_cast<const QSortFilterProxyModel*>(selectionModel->model());
+ int diff = -1;
+ if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) ||
+ ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) {
+ diff = 1;
+ }
+ QModelIndexList rows = selectionModel->selectedRows();
+ if (keyEvent->key() == Qt::Key_Down) {
+ for (int i = 0; i < rows.size() / 2; ++i) {
+ rows.swap(i, rows.size() - i - 1);
+ }
+ }
+ foreach (QModelIndex idx, rows) {
+ if (proxyModel != NULL) {
+ idx = proxyModel->mapToSource(idx);
+ }
+ int newPriority = m_ESPs[idx.row()].m_Priority + diff;
+ if ((newPriority >= 0) && (newPriority < rowCount())) {
+ setPluginPriority(idx.row(), newPriority);
+ emit dataChanged(this->index(idx.row(), 0), this->index(idx.row(), this->columnCount() - 1));
+ }
+ }
+ refreshLoadOrder();
+ return true;
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
diff --git a/src/pluginlist.h b/src/pluginlist.h new file mode 100644 index 00000000..aa6d1426 --- /dev/null +++ b/src/pluginlist.h @@ -0,0 +1,220 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef PLUGINLIST_H +#define PLUGINLIST_H + +#include <QString> +#include <QListWidget> +#include <vector> +#include <directoryentry.h> + + +/** + * @brief model representing the plugins (.esp/.esm) in the current virtual data folder + **/ +class PluginList : public QAbstractTableModel +{ + Q_OBJECT + +public: + + enum EColumn { + COL_NAME, + COL_PRIORITY, + COL_MODINDEX, + + COL_LASTCOLUMN = COL_MODINDEX + }; + +public: + + /** + * @brief constructor + * + * @param parent parent object + **/ + PluginList(QObject *parent = NULL); + + /** + * @brief does a complete refresh of the list + * + * @param profileName name of the current profile + * @param baseDirectory the root directory structure representing the virtual data directory + * @todo the profile is not used? If it was, we should pass the Profile-object instead + **/ + void refresh(const QString &profileName, const DirectoryEntry &baseDirectory, const QString &pluginsFile, const QString &loadOrderFile, const QString &lockedOrderFile); + + /** + * @brief enable a plugin based on its name + * + * @param name name of the plugin to enable + **/ + void enableESP(const QString &name); + + /** + * @brief test if a plugin is enabled + * + * @param name name of the plugin to look up + * @return true if the plugin is enabled, false otherwise + **/ + bool isEnabled(const QString &name); + + /** + * @brief test if a plugin is enabled + * + * @param index index of the plugin to look up + * @return true if the plugin is enabled, false otherwise + * @throws std::out_of_range exception is thrown if index is invalid + **/ + bool isEnabled(int index); + + /** + * @brief update the plugin status (enabled/disabled) from the specified file + * + * @param fileName path of the file to load. the filename should be "plugin.txt" + * @todo it would make sense to move this into the Profile-class + **/ + void readEnabledFrom(const QString &fileName); + + /** + * @brief save the plugin status to the specified file + * + * @param pluginFileName path of the plugin.txt to write to + * @param loadOrderFileName path of the loadorder.txt to write to + * @param lockedOrderFileName path of the lockedorder.txt to write to + * @param deleterFileName file to receive a list of files to hide from the virtual data tree. This is used to hide unchecked plugins if "hideUnchecked" is true + * @param hideUnchecked if true, plugins that aren't enabled will be hidden from the virtual data directory + **/ + void saveTo(const QString &pluginFileName, const QString &loadOrderFileName, const QString &lockedOrderFileName, + const QString &deleterFileName, bool hideUnchecked) const; + + /** + * @brief save the current load order + * + * the load order used by the game is defined by the last modification time which this + * function sets. An exception is newer version of skyrim where the load order is defined + * by the order of files in plugins.txt + * @param directoryStructure the root directory structure representing the virtual data directory + * @return true on success or if there was nothing to save, false if the load order can't be saved, i.e. because files are locked + * @todo since this works on actual files the load order can't be configured per-profile. Files of the same name + * in different mods can also have different load orders which makes this very intransparent + * @note also stores to disk the list of locked esps + **/ + bool saveLoadOrder(DirectoryEntry &directoryStructure); + + QString getName(int index) const { return m_ESPs.at(index).m_Name; } + int getPriority(int index) const { return m_ESPs.at(index).m_Priority; } + bool isESPLocked(int index) const; + void lockESPIndex(int index, bool lock); + + bool eventFilter(QObject *obj, QEvent *event); + + static QString getColumnName(int column); + static QString getColumnToolTip(int column); + +public: // implementation of the QAbstractTableModel interface + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + + void syncLoadOrder(); +public slots: + + /** + * @brief enables ALL plugins + **/ + void enableAll(); + + /** + * @brief disables ALL plugins + **/ + void disableAll(); + +signals: + + /** + * @brief emitted when the plugin list changed, i.e. the load order was modified or a plugin was checked/unchecked + * @note this is currently only used to signal that there are changes that can be saved, it does + * not immediately cause anything to be written to disc + **/ + void esplist_changed(); + +private: + + void refreshLoadOrder(); + void updateIndices(); + + void writePlugins(const QString &fileName, bool writeUnchecked) const; + void writeLockedOrder(const QString &fileName) const; + + bool readLoadOrder(const QString &fileName); + void readLockedOrderFrom(const QString &fileName); + void setPluginPriority(int row, int &newPriority); + void changePluginPriority(std::vector<int> rows, int newPriority); + +private: + + struct ESPInfo { + + ESPInfo(const QString &name, bool enabled, FILETIME time, const QString &originName) + : m_Name(name), m_Enabled(enabled), m_ForceEnabled(enabled), m_Removed(false), m_Priority(0), + m_LoadOrder(-1), m_Time(time), m_OriginName(originName), + m_IsMaster(name.endsWith("esm", Qt::CaseInsensitive)) {} + QString m_Name; + bool m_Enabled; + bool m_ForceEnabled; + bool m_Removed; + int m_Priority; + int m_LoadOrder; + FILETIME m_Time; + QString m_OriginName; + bool m_IsMaster; + }; + + friend bool ByName(const ESPInfo& LHS, const ESPInfo& RHS); + friend bool ByDate(const ESPInfo& LHS, const ESPInfo& RHS); + friend bool ByPriority(const ESPInfo& LHS, const ESPInfo& RHS); + +private: + + std::vector<ESPInfo> m_ESPs; + + std::map<QString, int> m_ESPsByName; + std::vector<int> m_ESPsByPriority; + + // maps esp names to the priority specified in loadorder.txt. The esp names are + // all lowercase!! This is to work around the fact that BOSS for some reason writes some file with + // capitalization that doesn't match the actual name + std::map<QString, int> m_ESPLoadOrder; + std::map<QString, int> m_LockedOrder; + + QString m_CurrentProfile; + mutable bool m_Modified; + QFontMetrics m_FontMetrics; + +}; + +#endif // PLUGINLIST_H diff --git a/src/pluginlistsortproxy.cpp b/src/pluginlistsortproxy.cpp new file mode 100644 index 00000000..788073ab --- /dev/null +++ b/src/pluginlistsortproxy.cpp @@ -0,0 +1,143 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "pluginlistsortproxy.h"
+#include "pluginlist.h"
+#include <QMenu>
+#include <QCheckBox>
+#include <QWidgetAction>
+
+
+PluginListSortProxy::PluginListSortProxy(QObject *parent)
+ : QSortFilterProxyModel(parent),
+ m_SortIndex(0), m_SortOrder(Qt::AscendingOrder)
+{
+ m_EnabledColumns.set(PluginList::COL_NAME);
+ m_EnabledColumns.set(PluginList::COL_PRIORITY);
+ m_EnabledColumns.set(PluginList::COL_MODINDEX);
+ this->setDynamicSortFilter(true);
+}
+
+
+unsigned int PluginListSortProxy::getEnabledColumns() const
+{
+ unsigned int result = 0;
+ for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) {
+ if (m_EnabledColumns.test(i)) {
+ result |= 1 << i;
+ }
+ }
+ return result;
+}
+
+
+void PluginListSortProxy::setEnabledColumns(unsigned int columns)
+{
+ emit layoutAboutToBeChanged();
+ for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) {
+ m_EnabledColumns.set(i, (columns & (1 << i)) != 0);
+ }
+ emit layoutChanged();
+}
+
+
+Qt::ItemFlags PluginListSortProxy::flags(const QModelIndex &modelIndex) const
+{
+ Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex));
+ if (sortColumn() == PluginList::COL_NAME) {
+ flags &= ~Qt::ItemIsDragEnabled;
+ }
+ return flags;
+}
+
+
+void PluginListSortProxy::displayColumnSelection(const QPoint &pos)
+{
+ QMenu menu;
+
+ for (int i = 0; i <= PluginList::COL_LASTCOLUMN; ++i) {
+ QCheckBox *checkBox = new QCheckBox(&menu);
+ checkBox->setText(PluginList::getColumnName(i));
+ checkBox->setChecked(m_EnabledColumns.test(i) ? Qt::Checked : Qt::Unchecked);
+ QWidgetAction *checkableAction = new QWidgetAction(&menu);
+ checkableAction->setDefaultWidget(checkBox);
+ menu.addAction(checkableAction);
+ }
+ menu.exec(pos);
+ int i = 0;
+
+ emit layoutAboutToBeChanged();
+ m_EnabledColumns.reset();
+ foreach (const QAction *action, menu.actions()) {
+ const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action);
+ if (widgetAction != NULL) {
+ const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(widgetAction->defaultWidget());
+ if (checkBox != NULL) {
+ m_EnabledColumns.set(i, checkBox->checkState() == Qt::Checked);
+ }
+ }
+ ++i;
+ }
+ emit layoutChanged();
+}
+
+
+bool PluginListSortProxy::lessThan(const QModelIndex &left,
+ const QModelIndex &right) const
+{
+ PluginList *plugins = qobject_cast<PluginList*>(sourceModel());
+ switch (left.column()) {
+ case PluginList::COL_NAME: {
+ return QString::compare(plugins->getName(left.row()), plugins->getName(right.row()), Qt::CaseInsensitive) < 0;
+ } break;
+ case PluginList::COL_PRIORITY:
+ case PluginList::COL_MODINDEX: {
+ return plugins->getPriority(left.row()) < plugins->getPriority(right.row());
+ } break;
+ default: {
+ static bool first = true;
+ if (first) {
+ qCritical("invalid sort column %d", left.column());
+ first = false;
+ }
+ return plugins->getPriority(left.row()) < plugins->getPriority(right.row());
+ } break;
+ }
+}
+
+
+bool PluginListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ if ((row == -1) && (column == -1)) {
+ return this->sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
+ }
+ // in the regular model, when dropping between rows, the row-value passed to
+ // the sourceModel is inconsistent between ascending and descending ordering.
+ // This should fix that
+ if (sortOrder() == Qt::DescendingOrder) {
+ --row;
+ }
+
+ QModelIndex proxyIndex = index(row, column, parent);
+ QModelIndex sourceIndex = mapToSource(proxyIndex);
+ return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(),
+ sourceIndex.parent());
+}
+
diff --git a/src/pluginlistsortproxy.h b/src/pluginlistsortproxy.h new file mode 100644 index 00000000..7397ff7c --- /dev/null +++ b/src/pluginlistsortproxy.h @@ -0,0 +1,68 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef PLUGINLISTSORTPROXY_H
+#define PLUGINLISTSORTPROXY_H
+
+
+#include <bitset>
+#include <QSortFilterProxyModel>
+#include "pluginlist.h"
+
+
+class PluginListSortProxy : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+
+ enum ESorting {
+ SORT_ASCENDING,
+ SORT_DESCENDING
+ };
+
+public:
+
+ explicit PluginListSortProxy(QObject *parent = 0);
+
+ unsigned int getEnabledColumns() const;
+
+ void setEnabledColumns(unsigned int columns);
+
+ virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const;
+
+ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+
+public slots:
+
+ void displayColumnSelection(const QPoint &pos);
+
+protected:
+
+ virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+
+private:
+
+ int m_SortIndex;
+ Qt::SortOrder m_SortOrder;
+
+ std::bitset<PluginList::COL_LASTCOLUMN + 1> m_EnabledColumns;
+
+};
+
+#endif // PLUGINLISTSORTPROXY_H
diff --git a/src/profile.cpp b/src/profile.cpp new file mode 100644 index 00000000..21cd1216 --- /dev/null +++ b/src/profile.cpp @@ -0,0 +1,693 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "profile.h"
+#include "report.h"
+#include "gameinfo.h"
+#include "windows_error.h"
+#include "dummybsa.h"
+#include "modinfo.h"
+#include <utility.h>
+#include <util.h>
+#include <appconfig.h>
+#include <QMessageBox>
+#include <QApplication>
+#include <QSettings>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <shlobj.h>
+#include <stdexcept>
+
+
+Profile::Profile()
+{
+ initTimer();
+}
+
+Profile::Profile(const QString &name, bool useDefaultSettings)
+{
+ QString profilesDir = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir()));
+ QDir profileBase(profilesDir);
+
+ if (!profileBase.exists() || !profileBase.mkdir(name)) {
+ throw std::runtime_error(QObject::tr("failed to create %1").arg(name).toUtf8().constData());
+ }
+ QString fullPath = profilesDir + "/" + name;
+ m_Directory = QDir(fullPath);
+ QFile modList(m_Directory.filePath("modlist.txt"));
+ if (!modList.open(QIODevice::ReadWrite)) {
+ profileBase.rmdir(name);
+ throw std::runtime_error(QObject::tr("failed to create %1").arg(m_Directory.filePath("modlist.txt")).toUtf8().constData());
+ }
+ modList.close();
+
+ try {
+ GameInfo::instance().createProfile(ToWString(fullPath), useDefaultSettings);
+ } catch (...) {
+ // clean up in case of an error
+ removeDir(profileBase.absoluteFilePath(name));
+ throw;
+ }
+ initTimer();
+ refreshModStatus();
+}
+
+
+Profile::Profile(const QDir& directory)
+ : m_Directory(directory)
+{
+ if (!QFile::exists(m_Directory.filePath("modlist.txt"))) {
+ throw std::runtime_error(QObject::tr("modlist.txt missing").toUtf8().constData());
+ }
+
+ GameInfo::instance().repairProfile(ToWString(m_Directory.absolutePath()));
+
+ if (!QFile::exists(getIniFileName())) {
+ reportError(QObject::tr("\"%1\" is missing").arg(getIniFileName()));
+ }
+ initTimer();
+ refreshModStatus();
+}
+
+
+Profile::Profile(const Profile& reference)
+ : m_Directory(reference.m_Directory)
+{
+ initTimer();
+ refreshModStatus();
+}
+
+
+Profile::~Profile()
+{
+ writeModlistNow();
+}
+
+
+void Profile::initTimer()
+{
+ m_SaveTimer = new QTimer(this);
+ m_SaveTimer->setSingleShot(true);
+ connect(m_SaveTimer, SIGNAL(timeout()), this, SLOT(writeModlistNow()));
+}
+
+
+bool Profile::exists() const
+{
+ return m_Directory.exists();
+}
+
+
+void Profile::writeModlist() const
+{
+ if (!m_SaveTimer->isActive()) {
+ m_SaveTimer->start(2000);
+ }
+}
+
+
+void Profile::cancelWriteModlist() const
+{
+ m_SaveTimer->stop();
+}
+
+
+void Profile::writeModlistNow() const
+{
+ m_SaveTimer->stop();
+#pragma message("right now, we're doing unnecessary saves. We need a flag that says that mod priority, enabled-state or name of a mod has changed")
+
+ QString fileName = getModlistFileName();
+ QFile file(fileName);
+ file.open(QIODevice::WriteOnly);
+ file.resize(0);
+ file.write(QString("# This file was automatically generated by Mod Organizer.\r\n").toUtf8());
+ if (m_ModStatus.empty()) {
+ return;
+ }
+
+ for (int i = m_ModStatus.size() - 1; i >= 0; --i) {
+ // the priority order was inverted on load so it has to be inverted again
+ unsigned int index = m_ModIndexByPriority[i];
+ if (index != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ if (modInfo->getFixedPriority() == INT_MIN) {
+ if (m_ModStatus[index].m_Enabled) {
+ file.write("+");
+ } else {
+ file.write("-");
+ }
+ file.write(modInfo->name().toUtf8());
+ file.write("\r\n");
+ }
+ }
+ }
+
+ file.close();
+ qDebug("%s saved", QDir::toNativeSeparators(fileName).toUtf8().constData());
+}
+
+
+void Profile::createTweakedIniFile()
+{
+ QFileInfo iniInfo(getIniFileName());
+
+ QString tweakedIni = iniInfo.absolutePath() + "/initweaks.ini";
+// QFile iniFile(tweakedIni);
+
+ // workaround: the fallout nv launcher seems to mark the file read-only. crazy...
+/* ::SetFileAttributesW(ToWString(tweakedIni).c_str(), FILE_ATTRIBUTE_NORMAL);
+ QFile(tweakedIni).remove();
+ if (!iniFile.copy(tweakedIni)) {
+ reportError(tr("failed to apply ini tweaks").append(": ").append(iniFile.errorString()));
+ return;
+ }*/
+
+ QFile::remove(tweakedIni); // remove the old ini tweaks
+
+ for (unsigned int i = 0; i < m_ModStatus.size(); ++i) {
+ if (m_ModStatus[i].m_Enabled) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
+ mergeTweaks(modInfo, tweakedIni);
+ }
+ }
+}
+
+
+void Profile::refreshModStatus()
+{
+ // don't lose changes!
+ if (m_SaveTimer->isActive()) {
+ writeModlistNow();
+ }
+
+ QFile file(getModlistFileName());
+ if (!file.exists()) {
+ throw MyException(QObject::tr("failed to find \"%1\"").arg(getModlistFileName()));
+ }
+
+ bool modStatusModified = false;
+ m_ModStatus.clear();
+ m_ModStatus.resize(ModInfo::getNumMods());
+
+ std::set<QString> namesRead;
+
+ // load mods from file and update enabled state and priority for them
+ file.open(QIODevice::ReadOnly);
+ int index = 0;
+ while (!file.atEnd()) {
+ QByteArray line = file.readLine();
+ bool enabled = true;
+ QString modName;
+ if (line.length() == 0) {
+ // empty line
+ continue;
+ } else if (line.at(0) == '#') {
+ // comment line
+ continue;
+ } else if (line.at(0) == '-') {
+ enabled = false;
+ modName = QString::fromUtf8(line.mid(1).trimmed().constData());
+ } else if (line.at(0) == '+') {
+ modName = QString::fromUtf8(line.mid(1).trimmed().constData());
+ } else {
+ modName = QString::fromUtf8(line.trimmed().constData());
+ }
+ if (modName.size() > 0) {
+ if (namesRead.find(modName) != namesRead.end()) {
+ continue;
+ } else {
+ namesRead.insert(modName);
+ }
+ unsigned int modindex = ModInfo::getIndex(modName);
+ if (modindex != UINT_MAX) {
+ ModInfo::Ptr info = ModInfo::getByIndex(modindex);
+ if ((modindex < m_ModStatus.size()) && (info->getFixedPriority() == INT_MIN)) {
+ m_ModStatus[modindex].m_Enabled = enabled;
+ if (m_ModStatus[modindex].m_Priority == -1) {
+ if (static_cast<size_t>(index) >= m_ModStatus.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+ m_ModStatus[modindex].m_Priority = index++;
+ }
+ } else {
+ qDebug("mod \"%s\" (profile \"%s\") not found",
+ modName.toUtf8().constData(), m_Directory.path().toUtf8().constData());
+ // need to rewrite the modlist to fix this
+ modStatusModified = true;
+ }
+ }
+ } else {
+ // line was empty after trimming
+ }
+ }
+
+ int numKnownMods = index;
+
+ // invert priority order to match that of the pluginlist. Also
+ // give priorities to mods not referenced in the profile
+ for (size_t i = 0; i < m_ModStatus.size(); ++i) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
+ if (!modInfo->canBeEnabled()) {
+ continue;
+ }
+ if (m_ModStatus[i].m_Priority != -1) {
+ m_ModStatus[i].m_Priority = numKnownMods - m_ModStatus[i].m_Priority - 1;
+ } else {
+ if (static_cast<size_t>(index) >= m_ModStatus.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+ m_ModStatus[i].m_Priority = index++;
+ // also, mark the mod-list as changed
+ modStatusModified = true;
+ }
+ }
+
+ file.close();
+ updateIndices();
+ if (modStatusModified) {
+ writeModlist();
+ }
+}
+
+
+void Profile::dumpModStatus() const
+{
+ for (unsigned int i = 0; i < m_ModStatus.size(); ++i) {
+ ModInfo::Ptr info = ModInfo::getByIndex(i);
+ qWarning("%d: %s - %d (%s)", i, info->name().toUtf8().constData(), m_ModStatus[i].m_Priority,
+ m_ModStatus[i].m_Enabled ? "enabled" : "disabled");
+ }
+}
+
+
+void Profile::updateIndices()
+{
+ m_NumRegularMods = 0;
+ m_ModIndexByPriority.clear();
+ m_ModIndexByPriority.resize(m_ModStatus.size(), UINT_MAX);
+ for (unsigned int i = 0; i < m_ModStatus.size(); ++i) {
+ int priority = m_ModStatus[i].m_Priority;
+ if (priority < 0) {
+ continue;
+ } else if (priority >= static_cast<int>(m_ModIndexByPriority.size())) {
+ qCritical("invalid priority %d for mod", priority);
+ continue;
+ } else {
+ ++m_NumRegularMods;
+ m_ModIndexByPriority.at(priority) = i;
+ }
+ }
+}
+
+
+std::vector<std::tuple<QString, QString, int> > Profile::getActiveMods()
+{
+ std::vector<std::tuple<QString, QString, int> > result;
+ for (std::vector<unsigned int>::const_iterator iter = m_ModIndexByPriority.begin();
+ iter != m_ModIndexByPriority.end(); ++iter) {
+ if ((*iter != UINT_MAX) && m_ModStatus[*iter].m_Enabled) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(*iter);
+ result.push_back(std::make_tuple(modInfo->name(), modInfo->absolutePath(), m_ModStatus[*iter].m_Priority));
+ }
+ }
+
+ unsigned int overwriteIndex = ModInfo::findMod([](ModInfo::Ptr mod) -> bool {
+ std::vector<ModInfo::EFlag> flags = mod->getFlags();
+ return std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end(); });
+
+ if (overwriteIndex != UINT_MAX) {
+ ModInfo::Ptr overwriteInfo = ModInfo::getByIndex(overwriteIndex);
+ result.push_back(std::make_tuple(overwriteInfo->name(), overwriteInfo->absolutePath(), UINT_MAX));
+ } else {
+ reportError(tr("Overwrite directory couldn't be parsed"));
+ }
+ return result;
+}
+
+
+unsigned int Profile::modIndexByPriority(unsigned int priority) const
+{
+ if (priority >= m_ModStatus.size()) {
+ throw MyException(tr("invalid priority %1").arg(priority));
+ }
+
+ return m_ModIndexByPriority[priority];
+}
+
+
+void Profile::setModEnabled(unsigned int index, bool enabled)
+{
+ if (index >= m_ModStatus.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+
+ if (m_ModStatus[index].m_Overwrite) {
+ // overwrite is always enabled
+ return;
+ }
+
+ if (enabled != m_ModStatus[index].m_Enabled) {
+ m_ModStatus[index].m_Enabled = enabled;
+ emit modStatusChanged(index);
+ }
+}
+
+
+bool Profile::modEnabled(unsigned int index) const
+{
+ if (index >= m_ModStatus.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+
+ return m_ModStatus[index].m_Enabled;
+}
+
+
+int Profile::getModPriority(unsigned int index) const
+{
+ if (index >= m_ModStatus.size()) {
+ throw MyException(tr("invalid index %1").arg(index));
+ }
+
+ return m_ModStatus[index].m_Priority;
+}
+
+
+void Profile::setModPriority(unsigned int index, int &newPriority)
+{
+ int newPriorityTemp = (std::max)(0, (std::min<int>)(m_ModStatus.size() - 1, newPriority));
+ if (m_ModStatus[index].m_Overwrite) {
+ // can't change priority of the overwrite
+ return;
+ }
+ int oldPriority = m_ModStatus[index].m_Priority;
+ if (newPriorityTemp > oldPriority) {
+ // priority is higher than the old, so the gap we left is in lower priorities
+ for (int i = oldPriority + 1; i <= newPriorityTemp; ++i) {
+ --m_ModStatus[m_ModIndexByPriority[i]].m_Priority;
+ }
+ } else {
+ for (int i = newPriorityTemp; i < oldPriority; ++i) {
+ ++m_ModStatus[m_ModIndexByPriority[i]].m_Priority;
+ }
+ ++newPriority;
+ }
+
+ m_ModStatus[index].m_Priority = newPriorityTemp;
+
+ updateIndices();
+ writeModlist();
+}
+
+
+Profile Profile::createFrom(const QString &name, const Profile &reference)
+{
+ QString profileDirectory = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())).append("/").append(name);
+ reference.copyFilesTo(profileDirectory);
+ return Profile(QDir(profileDirectory));
+}
+
+
+void Profile::copyFilesTo(QString &target) const
+{
+ copyDir(m_Directory.absolutePath(), target, false);
+}
+
+
+std::vector<std::wstring> Profile::splitDZString(const wchar_t *buffer) const
+{
+ std::vector<std::wstring> result;
+ const wchar_t *pos = buffer;
+ size_t length = wcslen(pos);
+ while (length != 0U) {
+ result.push_back(pos);
+ pos += length + 1;
+ length = wcslen(pos);
+ }
+ return result;
+}
+
+
+void Profile::mergeTweak(const QString &tweakName, const QString &tweakedIni) const
+{
+ static const int bufferSize = 32768;
+
+ std::wstring tweakNameW = ToWString(tweakName);
+ std::wstring tweakedIniW = ToWString(tweakedIni);
+ QScopedArrayPointer<wchar_t> buffer(new wchar_t[bufferSize]);
+
+ // retrieve a list of sections
+ DWORD size = ::GetPrivateProfileSectionNamesW(
+ buffer.data(), bufferSize, tweakNameW.c_str());
+
+ if (size == bufferSize - 2) {
+ // unfortunately there is no good way to find the required size
+ // of the buffer
+ throw MyException(QString("Buffer too small. Please report this as a bug. "
+ "For now you might want to split up %1").arg(tweakName));
+ }
+
+ std::vector<std::wstring> sections = splitDZString(buffer.data());
+
+ // now iterate over all sections and retrieve a list of keys in each
+ for (std::vector<std::wstring>::iterator iter = sections.begin();
+ iter != sections.end(); ++iter) {
+ // retrieve the names of all keys
+ size = ::GetPrivateProfileStringW(iter->c_str(), NULL, NULL, buffer.data(),
+ bufferSize, tweakNameW.c_str());
+ if (size == bufferSize - 2) {
+ throw MyException(QString("Buffer too small. Please report this as a bug. "
+ "For now you might want to split up %1").arg(tweakName));
+ }
+
+ std::vector<std::wstring> keys = splitDZString(buffer.data());
+
+ for (std::vector<std::wstring>::iterator keyIter = keys.begin();
+ keyIter != keys.end(); ++keyIter) {
+ //TODO this treats everything as strings but how could I differentiate the type?
+ ::GetPrivateProfileStringW(iter->c_str(), keyIter->c_str(),
+ NULL, buffer.data(), bufferSize, ToWString(tweakName).c_str());
+ ::WritePrivateProfileStringW(iter->c_str(), keyIter->c_str(),
+ buffer.data(), tweakedIniW.c_str());
+ }
+ }
+}
+
+void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const
+{
+ std::vector<QString> iniTweaks = modInfo->getIniTweaks();
+ for (std::vector<QString>::iterator iter = iniTweaks.begin();
+ iter != iniTweaks.end(); ++iter) {
+ mergeTweak(*iter, tweakedIni);
+ }
+
+ ::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"1", ToWString(tweakedIni).c_str());
+
+ if (localSavesEnabled()) {
+ ::WritePrivateProfileStringW(L"General", L"bUseMyGamesDirectory", L"1", ToWString(tweakedIni).c_str());
+
+ ::WritePrivateProfileStringW(L"General", L"SLocalSavePath",
+ AppConfig::localSavePlaceholder(),
+ ToWString(tweakedIni).c_str());
+ }
+}
+
+
+bool Profile::invalidationActive(bool *supported) const
+{
+ if (GameInfo::instance().requiresBSAInvalidation()) {
+ *supported = true;
+ wchar_t buffer[1024];
+ std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName()));
+ if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ L"", buffer, 1024, iniFileName.c_str()) == 0) {
+ if (errno != 0x02) {
+ if (supported != NULL) {
+ *supported = false;
+ }
+ return false;
+ } else {
+ qCritical("failed to parse \"%ls\"", iniFileName.c_str());
+ QString errorMessage = tr("failed to parse ini file (%1): %2").arg(QDir::toNativeSeparators(getIniFileName())).arg(::GetLastError());
+ throw windows_error(errorMessage.toUtf8().constData());
+ }
+ }
+ QStringList archives = ToQString(buffer).split(',');
+
+ for (int i = 0; i < archives.count(); ++i) {
+ QString bsaName = archives.at(i).trimmed();
+ if (GameInfo::instance().isInvalidationBSA(ToWString(bsaName))) {
+ return true;
+ }
+ }
+ } else {
+ *supported = false;
+ }
+ return false;
+}
+
+
+void Profile::deactivateInvalidation() const
+{
+ if (GameInfo::instance().requiresBSAInvalidation()) {
+ wchar_t buffer[1024];
+ std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName()));
+ if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ L"", buffer, 1024, iniFileName.c_str()) == 0) {
+ if (errno == 0x02) {
+ QString errorMessage = tr("failed to parse ini file (%1): %2").arg(QDir::toNativeSeparators(getIniFileName())).arg(::GetLastError());
+ throw windows_error(errorMessage.toUtf8().constData());
+ } else {
+ return;
+ }
+ }
+ QStringList archives = ToQString(buffer).split(", ");
+
+ for (int i = 0; i < archives.count();) {
+ QString bsaName = archives.at(i).trimmed();
+ if (GameInfo::instance().isInvalidationBSA(ToWString(bsaName))) {
+ archives.removeAt(i);
+ } else {
+ ++i;
+ }
+ }
+
+ if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) ||
+ !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"0", iniFileName.c_str()) ||
+ !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"ArchiveInvalidation.txt", iniFileName.c_str())) {
+ throw windows_error("failed to modify ini file");
+ }
+ }
+}
+
+
+void Profile::activateInvalidation(const QString& dataDirectory) const
+{
+ if (GameInfo::instance().requiresBSAInvalidation()) {
+ wchar_t buffer[1024];
+ std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName()));
+ if (::GetPrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ L"", buffer, 1024, iniFileName.c_str()) == 0) {
+ throw windows_error("failed to parse ini file");
+ }
+ QStringList archives = ToQString(buffer).split(", ");
+
+ QString invalidationBSA = ToQString(GameInfo::instance().getInvalidationBSA());
+
+ if (!archives.contains(invalidationBSA)) {
+ archives.insert(0, invalidationBSA);
+ }
+
+ if (!::WritePrivateProfileStringW(L"Archive", GameInfo::instance().archiveListKey().c_str(),
+ ToWString(archives.join(", ").toUtf8()).c_str(), iniFileName.c_str()) ||
+ !::WritePrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"1", iniFileName.c_str()) ||
+ !::WritePrivateProfileStringW(L"Archive", L"SInvalidationFile", L"", iniFileName.c_str())) {
+ throw windows_error("failed to modify ini file");
+ }
+
+ QString bsaFile = dataDirectory + "/" + invalidationBSA;
+ if (!QFile::exists(bsaFile)) {
+ DummyBSA bsa;
+ bsa.write(bsaFile);
+ }
+ }
+}
+
+
+bool Profile::localSavesEnabled() const
+{
+ return m_Directory.exists("saves");
+}
+
+
+bool Profile::enableLocalSaves(bool enable)
+{
+ if (enable) {
+ if (m_Directory.exists("_saves")) {
+ m_Directory.rename("_saves", "saves");
+ } else {
+ m_Directory.mkdir("saves");
+ }
+ } else {
+
+ QMessageBox::StandardButton res = QMessageBox::question(QApplication::activeModalWidget(), tr("Delete savegames?"),
+ tr("Do you want to delete local savegames? (If you select \"No\", the save games "
+ "will show up again if you re-enable local savegames)"),
+ QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+ QMessageBox::Cancel);
+ if (res == QMessageBox::Yes) {
+ removeDir(m_Directory.absoluteFilePath("_saves"));
+ } else if (res == QMessageBox::No) {
+ m_Directory.rename("saves", "_saves");
+ } else {
+ return false;
+ }
+ }
+
+ // default: assume success
+ return true;
+}
+
+
+QString Profile::getModlistFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("modlist.txt"));
+}
+
+QString Profile::getPluginsFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("plugins.txt"));
+}
+
+
+QString Profile::getLoadOrderFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("loadorder.txt"));
+}
+
+
+QString Profile::getLockedOrderFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("lockedorder.txt"));
+}
+
+
+QString Profile::getArchivesFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("archives.txt"));
+}
+
+QString Profile::getDeleterFileName() const
+{
+ return QDir::cleanPath(m_Directory.absoluteFilePath("hide_plugins.txt"));
+}
+
+
+QString Profile::getIniFileName() const
+{
+ std::wstring primaryIniFile = *(GameInfo::instance().getIniFileNames().begin());
+ return m_Directory.absoluteFilePath(ToQString(primaryIniFile));
+}
+
+QString Profile::getPath() const
+{
+ return QDir::cleanPath(m_Directory.absolutePath());
+}
diff --git a/src/profile.h b/src/profile.h new file mode 100644 index 00000000..0c25b8f1 --- /dev/null +++ b/src/profile.h @@ -0,0 +1,311 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef PROFILE_H
+#define PROFILE_H
+
+
+#include "modinfo.h"
+
+#include <QString>
+#include <QDir>
+#include <QMetaType>
+#include <QSettings>
+#include <vector>
+#include <tuple>
+
+
+/**
+ * @brief represents a profile
+ **/
+class Profile : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief default constructor
+ * @todo This constructor initialised nothing, the resulting object is not usable
+ **/
+ Profile();
+
+ /**
+ * @brief constructor
+ *
+ * This constructor is used to create a new profile so it is to be assumed a profile
+ * by this name does not yet exist
+ * @param name name of the new profile
+ * @param filter save game filter. Defaults to <no filter>.
+ **/
+ Profile(const QString &name, bool useDefaultSettings);
+ /**
+ * @brief constructor
+ *
+ * This constructor is used to open an existing profile though it will also try to repair
+ * the profile if important files are missing (including the directory itself) so technically,
+ * invoking this should always produce a working profile
+ * @param directory directory to read the profile from
+ **/
+ Profile(const QDir &directory);
+
+ Profile(const Profile &reference);
+
+ ~Profile();
+
+ /**
+ * @return true if this profile (still) exists on disc
+ */
+ bool exists() const;
+
+ /**
+ * @brief copy constructor
+ *
+ * @param name of the new profile
+ * @param reference profile to copy from
+ **/
+ static Profile createFrom(const QString &name, const Profile &reference);
+
+ /**
+ * @brief write out the modlist.txt
+ **/
+ void writeModlist() const;
+
+ /**
+ * cancel any potential request to write modlist.txt. This is used to ensure no invalid modlist is
+ * saved while it's being modified
+ */
+ void cancelWriteModlist() const;
+
+ /**
+ * @brief test if this profile uses archive invalidation
+ *
+ * @param supported if this is not null, the parameter will be set to false if invalidation is not supported in this profile
+ * @return true if archive invalidation is active
+ * @note currently, invalidation is not supported if the relevant entry in the ini file does not exist
+ **/
+ bool invalidationActive(bool *supported) const;
+
+ /**
+ * @brief deactivate archive invalidation if it was active
+ **/
+ void deactivateInvalidation() const;
+
+ /**
+ * @brief activate archive invalidation
+ *
+ * @param dataDirectory data directory of the game
+ * @todo passing the data directory as a parameter is useless, the function should
+ * be able to query it from GameInfo
+ **/
+ void activateInvalidation(const QString &dataDirectory) const;
+
+ /**
+ * @return true if this profile uses local save games
+ */
+ bool localSavesEnabled() const;
+
+ /**
+ * @brief enables or disables the use of local save games for this profile
+ * disabling this does not delete exising local saves but they will not be visible
+ * in the game
+ * @param enable if true, local saves are enabled, otherewise they are disabled
+ */
+ bool enableLocalSaves(bool enable);
+
+ /**
+ * @return name of the profile (this is identical to its directory name)
+ **/
+ QString getName() const { return m_Directory.dirName(); }
+
+ /**
+ * @return the path of the plugins file in this profile
+ * @todo is this required? can the functionality using this function be moved to the Profile-class?
+ **/
+ QString getPluginsFileName() const;
+
+ /**
+ * @return the path of the loadorder file in this profile
+ **/
+ QString getLoadOrderFileName() const;
+
+ /**
+ * @return the path of the file containing locked mod indices
+ */
+ QString getLockedOrderFileName() const;
+
+ /**
+ * @return path of the archives file in this profile
+ */
+ QString getArchivesFileName() const;
+
+ /**
+ * @return the path of the delete file in this profile
+ * @note the deleter file lists plugins that should be hidden from the game and other tools
+ **/
+ QString getDeleterFileName() const;
+
+ /**
+ * @return the path of the ini file in this profile
+ * @todo since the game can contain multiple ini files (i.e. skyrim.ini skyrimprefs.ini)
+ * the concept of this function is somewhat broken
+ **/
+ QString getIniFileName() const;
+
+ /**
+ * @return path to this profile
+ **/
+ QString getPath() const;
+
+ /**
+ * @brief create the ini file to be used by the game
+ *
+ * the tweaked ini file constructed by this file is a merger
+ * of the game-ini of this profile with ini tweaks applied */
+ void createTweakedIniFile();
+
+ /**
+ * @brief re-read the modlist.txt and update the mod status from it
+ **/
+ void refreshModStatus();
+
+ /**
+ * @brief retrieve a list of mods that are enabled in this profile
+ *
+ * @return list of active mods sorted by priority (ascending). "first" is the mod name, "second" is its path
+ **/
+ std::vector<std::tuple<QString, QString, int> > getActiveMods();
+
+ /**
+ * retrieve the number of mods for which this object has status information.
+ * This is usually the same as ModInfo::getNumMods() except between
+ * calls to ModInfo::updateFromDisc() and the Profile::refreshModStatus()
+ *
+ * @return number of mods for which the profile has status information
+ **/
+ unsigned int numMods() const { return m_ModStatus.size(); }
+
+ /**
+ * @return the number of mods that can be enabled and where the priority can be modified
+ */
+ unsigned int numRegularMods() const { return m_NumRegularMods; }
+
+ /**
+ * @brief retrieve the mod index based on the priority
+ *
+ * @param priority priority to look up
+ * @return the index of the mod
+ * @throw std::exception an exception is thrown if there is no mod with the specified priority
+ **/
+ unsigned int modIndexByPriority(unsigned int priority) const;
+
+ /**
+ * @brief enable or disable a mod
+ *
+ * @param index index of the mod to enable/disable
+ * @param enabled true if the mod is to be enabled, false if it is to be disabled
+ **/
+ void setModEnabled(unsigned int index, bool enabled);
+
+ /**
+ * change the priority of a mod. Of course this also changes the priority of other mods.
+ * The priority of the mods in the range ]old, new priority] are shifted so that no gaps
+ * are possible.
+ *
+ * @param index index of the mod to change
+ * @param newPriority the new priority value
+ *
+ * @todo what happens if the new priority is outside the range?
+ **/
+ void setModPriority(unsigned int index, int &newPriority);
+
+ /**
+ * @brief determine if a mod is enabled
+ *
+ * @param index index of the mod to look up
+ * @return true if the mod is enabled, false otherwise
+ **/
+ bool modEnabled(unsigned int index) const;
+
+ /**
+ * @brief query the priority of a mod
+ *
+ * @param index index of the mod to look up
+ * @return priority of the specified mod
+ **/
+ int getModPriority(unsigned int index) const;
+
+ void dumpModStatus() const;
+
+signals:
+
+ /**
+ * @brief emitted whenever the status (enabled/disabled) of a mod changed
+ *
+ * @param index index of the mod that changed
+ **/
+ void modStatusChanged(unsigned int index);
+
+public slots:
+
+ void writeModlistNow() const;
+
+private:
+
+ class ModStatus {
+ friend class Profile;
+ public:
+ ModStatus() : m_Overwrite(false), m_Enabled(false), m_Priority(-1) {}
+ private:
+ bool m_Overwrite;
+ bool m_Enabled;
+ int m_Priority;
+ };
+
+private:
+ Profile& operator=(const Profile &reference); // not implemented
+
+ void initTimer();
+
+ void updateIndices();
+
+ QString getModlistFileName() const;
+ void copyFilesTo(QString &target) const;
+
+ std::vector<std::wstring> splitDZString(const wchar_t *buffer) const;
+ void mergeTweak(const QString &tweakName, const QString &tweakedIni) const;
+ void mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const;
+
+private:
+
+ QDir m_Directory;
+
+ std::vector<ModStatus> m_ModStatus;
+ std::vector<unsigned int> m_ModIndexByPriority;
+ unsigned int m_NumRegularMods;
+
+ QTimer *m_SaveTimer;
+
+};
+
+Q_DECLARE_METATYPE(Profile)
+
+
+#endif // PROFILE_H
diff --git a/src/profileinputdialog.cpp b/src/profileinputdialog.cpp new file mode 100644 index 00000000..7402d4d5 --- /dev/null +++ b/src/profileinputdialog.cpp @@ -0,0 +1,45 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "profileinputdialog.h"
+#include "ui_profileinputdialog.h"
+
+ProfileInputDialog::ProfileInputDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::ProfileInputDialog)
+{
+ ui->setupUi(this);
+}
+
+ProfileInputDialog::~ProfileInputDialog()
+{
+ delete ui;
+}
+
+QString ProfileInputDialog::getName() const
+{
+ return ui->nameEdit->text().trimmed();
+}
+
+
+bool ProfileInputDialog::getPreferDefaultSettings() const
+{
+ return ui->defaultSettingsBox->checkState() == Qt::Checked;
+}
+
diff --git a/src/profileinputdialog.h b/src/profileinputdialog.h new file mode 100644 index 00000000..5ee1d600 --- /dev/null +++ b/src/profileinputdialog.h @@ -0,0 +1,44 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef PROFILEINPUTDIALOG_H
+#define PROFILEINPUTDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class ProfileInputDialog;
+}
+
+class ProfileInputDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ProfileInputDialog(QWidget *parent = 0);
+ ~ProfileInputDialog();
+
+ QString getName() const;
+ bool getPreferDefaultSettings() const;
+
+private:
+ Ui::ProfileInputDialog *ui;
+};
+
+#endif // PROFILEINPUTDIALOG_H
diff --git a/src/profileinputdialog.ui b/src/profileinputdialog.ui new file mode 100644 index 00000000..76265aa1 --- /dev/null +++ b/src/profileinputdialog.ui @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProfileInputDialog</class>
+ <widget class="QDialog" name="ProfileInputDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>436</width>
+ <height>129</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Please enter a name for the new profile</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="defaultSettingsBox">
+ <property name="toolTip">
+ <string>If checked, the new profile will use the default game settings.</string>
+ </property>
+ <property name="whatsThis">
+ <string>If checked, the new profile will use the default game settings instead of the "global" settings. Global settings are the settings you configure when running the game launcher directly, without MO.</string>
+ </property>
+ <property name="text">
+ <string>Default Game Settings</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProfileInputDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProfileInputDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp new file mode 100644 index 00000000..3aceeb01 --- /dev/null +++ b/src/profilesdialog.cpp @@ -0,0 +1,274 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "profilesdialog.h"
+#include "ui_profilesdialog.h"
+#include "profile.h"
+#include "report.h"
+#include "utility.h"
+#include "transfersavesdialog.h"
+#include "profileinputdialog.h"
+#include "mainwindow.h"
+#include <gameinfo.h>
+#include <QListWidgetItem>
+#include <QInputDialog>
+#include <QLineEdit>
+#include <QDirIterator>
+#include <QMessageBox>
+#include <QWhatsThis>
+
+
+ProfilesDialog::ProfilesDialog(const QString &gamePath, QWidget *parent)
+ : TutorableDialog("Profiles", parent), ui(new Ui::ProfilesDialog), m_GamePath(gamePath), m_FailState(false)
+{
+ ui->setupUi(this);
+
+ QDir profilesDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getProfilesDir())));
+ profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+ m_ProfilesList = findChild<QListWidget*>("profilesList");
+
+ QDirIterator profileIter(profilesDir);
+
+ while (profileIter.hasNext()) {
+ profileIter.next();
+ addItem(profileIter.filePath());
+ }
+
+ QCheckBox *invalidationBox = findChild<QCheckBox*>("invalidationBox");
+ if (!GameInfo::instance().requiresBSAInvalidation()) {
+ invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game."));
+ invalidationBox->setEnabled(false);
+ }
+}
+
+ProfilesDialog::~ProfilesDialog()
+{
+ delete ui;
+}
+
+void ProfilesDialog::showEvent(QShowEvent *event)
+{
+ TutorableDialog::showEvent(event);
+
+ if (m_ProfilesList->count() == 0) {
+ QPoint pos = m_ProfilesList->mapToGlobal(QPoint(0, 0));
+ pos.rx() += m_ProfilesList->width() / 2;
+ pos.ry() += (m_ProfilesList->height() / 2) - 20;
+ QWhatsThis::showText(pos,
+ QObject::tr("Before you can use ModOrganizer, you need to create at least one profile. "
+ "ATTENTION: Run the game at least once before creating a profile!"), m_ProfilesList);
+ }
+}
+
+void ProfilesDialog::on_closeButton_clicked()
+{
+ close();
+}
+
+
+void ProfilesDialog::addItem(const QString &name)
+{
+ try {
+ QVariant temp;
+ QDir profileDir(name);
+ temp.setValue(Profile(profileDir));
+ QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), m_ProfilesList);
+ newItem->setData(Qt::UserRole, temp);
+ m_FailState = false;
+ } catch (const std::exception& e) {
+ reportError(tr("failed to create profile: %1").arg(e.what()));
+ }
+}
+
+
+void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings)
+{
+ try {
+ QVariant temp;
+ temp.setValue(Profile(name, useDefaultSettings));
+ QListWidget *profilesList = findChild<QListWidget*>("profilesList");
+ QListWidgetItem *newItem = new QListWidgetItem(name, profilesList);
+ newItem->setData(Qt::UserRole, temp);
+ profilesList->addItem(newItem);
+ m_FailState = false;
+ } catch (const std::exception&) {
+ m_FailState = true;
+ throw;
+ }
+}
+
+
+void ProfilesDialog::createProfile(const QString &name, const Profile &reference)
+{
+ try {
+ Profile newProfile = Profile::createFrom(name, reference);
+
+ QVariant temp;
+ temp.setValue(newProfile);
+ QListWidget *profilesList = findChild<QListWidget*>("profilesList");
+ QListWidgetItem *newItem = new QListWidgetItem(name, profilesList);
+ newItem->setData(Qt::UserRole, temp);
+ profilesList->addItem(newItem);
+ m_FailState = false;
+ } catch (const std::exception&) {
+ m_FailState = true;
+ throw;
+ }
+}
+
+
+void ProfilesDialog::on_addProfileButton_clicked()
+{
+ ProfileInputDialog dialog(this);
+ bool okClicked = dialog.exec();
+ QString name = dialog.getName();
+
+ if (okClicked && (name.size() > 0)) {
+ try {
+ createProfile(name, dialog.getPreferDefaultSettings());
+ } catch (const std::exception &e) {
+ reportError(tr("failed to create profile: %1").arg(e.what()));
+ }
+ }
+}
+
+void ProfilesDialog::on_copyProfileButton_clicked()
+{
+ bool okClicked;
+ QString name = QInputDialog::getText(this, tr("Name"), tr("Please enter a name for the new profile"), QLineEdit::Normal, QString(), &okClicked);
+ if (okClicked && (name.size() > 0)) {
+ QListWidget *profilesList = findChild<QListWidget*>("profilesList");
+
+ try {
+ const Profile ¤tProfile = profilesList->currentItem()->data(Qt::UserRole).value<Profile>();
+ createProfile(name, currentProfile);
+ } catch (const std::exception &e) {
+ reportError(tr("failed to copy profile: %1").arg(e.what()));
+ }
+ }
+}
+
+void ProfilesDialog::on_removeProfileButton_clicked()
+{
+ QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"), tr("Are you sure you want to remove this profile?"),
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (confirmBox.exec() == QMessageBox::Yes) {
+ QListWidget *profilesList = findChild<QListWidget*>("profilesList");
+
+ const Profile ¤tProfile = profilesList->currentItem()->data(Qt::UserRole).value<Profile>();
+
+ // on destruction, the profile object would write the profile.ini file again, so
+ // we have to get rid of the it before deleting the directory
+ QString profilePath = currentProfile.getPath();
+ QListWidgetItem* item = profilesList->takeItem(profilesList->currentRow());
+ if (item != NULL) {
+ delete item;
+ }
+ removeDir(profilePath);
+ }
+}
+
+
+void ProfilesDialog::on_invalidationBox_stateChanged(int state)
+{
+ QListWidget *profilesList = findChild<QListWidget*>("profilesList");
+
+ QListWidgetItem *currentItem = profilesList->currentItem();
+ if (currentItem == NULL) {
+ return;
+ }
+ if (!ui->invalidationBox->isEnabled()) {
+ return;
+ }
+ try {
+ QVariant currentProfileVariant = currentItem->data(Qt::UserRole);
+ if (!currentProfileVariant.isValid() || currentProfileVariant.isNull()) {
+ return;
+ }
+ const Profile ¤tProfile = currentItem->data(Qt::UserRole).value<Profile>();
+ if (state == Qt::Unchecked) {
+ currentProfile.deactivateInvalidation();
+ } else {
+ currentProfile.activateInvalidation(m_GamePath + "/data");
+ }
+ } catch (const std::exception &e) {
+ reportError(tr("failed to change archive invalidation state: %1").arg(e.what()));
+ }
+}
+
+
+void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*)
+{
+ QCheckBox *invalidationBox = findChild<QCheckBox*>("invalidationBox");
+ QCheckBox *localSavesBox = findChild<QCheckBox*>("localSavesBox");
+ QPushButton *copyButton = findChild<QPushButton*>("copyProfileButton");
+ QPushButton *removeButton = findChild<QPushButton*>("removeProfileButton");
+ QPushButton *transferButton = findChild<QPushButton*>("transferButton");
+
+ if (current != NULL) {
+ const Profile ¤tProfile = current->data(Qt::UserRole).value<Profile>();
+
+ try {
+ bool invalidationSupported = false;
+ invalidationBox->blockSignals(true);
+ invalidationBox->setChecked(currentProfile.invalidationActive(&invalidationSupported));
+ invalidationBox->setEnabled(invalidationSupported);
+ invalidationBox->blockSignals(false);
+
+ bool localSaves = currentProfile.localSavesEnabled();
+ transferButton->setEnabled(localSaves);
+ // prevent the stateChanged-event for the saves-box from triggering, otherwise it may think local saves
+ // were disabled and delete the files/rename the dir
+ localSavesBox->blockSignals(true);
+ localSavesBox->setChecked(localSaves);
+ localSavesBox->blockSignals(false);
+
+ copyButton->setEnabled(true);
+ removeButton->setEnabled(true);
+ } catch (const std::exception& E) {
+ reportError(tr("failed to determine if invalidation is active: %1").arg(E.what()));
+ copyButton->setEnabled(false);
+ removeButton->setEnabled(false);
+ invalidationBox->setChecked(false);
+ }
+ } else {
+ invalidationBox->setChecked(false);
+ copyButton->setEnabled(false);
+ removeButton->setEnabled(false);
+ }
+}
+
+void ProfilesDialog::on_localSavesBox_stateChanged(int state)
+{
+ Profile ¤tProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value<Profile>();
+ if (currentProfile.enableLocalSaves(state == Qt::Checked)) {
+ ui->transferButton->setEnabled(state == Qt::Checked);
+ } else {
+ // revert checkbox-state
+ ui->localSavesBox->setChecked(state != Qt::Checked);
+ }
+}
+
+void ProfilesDialog::on_transferButton_clicked()
+{
+ const Profile ¤tProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value<Profile>();
+ TransferSavesDialog transferDialog(currentProfile, this);
+ transferDialog.exec();
+}
diff --git a/src/profilesdialog.h b/src/profilesdialog.h new file mode 100644 index 00000000..c05340c9 --- /dev/null +++ b/src/profilesdialog.h @@ -0,0 +1,94 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef PROFILESDIALOG_H
+#define PROFILESDIALOG_H
+
+#include "tutorabledialog.h"
+#include <QListWidgetItem>
+#include "profile.h"
+
+
+namespace Ui {
+ class ProfilesDialog;
+}
+
+
+/**
+ * @brief Dialog that can be used to create/delete/modify profiles
+ **/
+class ProfilesDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param gamePath the path to the game directory
+ * @param parent parent widget
+ * @todo the game path could be retrieved from GameInfo just as easily
+ **/
+ explicit ProfilesDialog(const QString &gamePath, QWidget *parent = 0);
+ ~ProfilesDialog();
+
+ /**
+ * @return true if creation of a new profile failed
+ * @todo the notion of a fail state makes little sense in the current dialog
+ **/
+ bool failed() const { return m_FailState; }
+
+protected:
+
+ virtual void showEvent(QShowEvent *event);
+
+private:
+
+ void addItem(const QString &name);
+ void createProfile(const QString &name, bool useDefaultSettings);
+ void createProfile(const QString &name, const Profile &reference);
+
+private slots:
+
+ void on_closeButton_clicked();
+
+ void on_addProfileButton_clicked();
+
+ void on_invalidationBox_stateChanged(int arg1);
+
+ void on_copyProfileButton_clicked();
+
+ void on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+
+ void on_removeProfileButton_clicked();
+
+ void on_localSavesBox_stateChanged(int arg1);
+
+ void on_transferButton_clicked();
+
+private:
+ Ui::ProfilesDialog *ui;
+ QString m_GamePath;
+ QListWidget *m_ProfilesList;
+ bool m_FailState;
+
+};
+
+#endif // PROFILESDIALOG_H
diff --git a/src/profilesdialog.ui b/src/profilesdialog.ui new file mode 100644 index 00000000..a2983436 --- /dev/null +++ b/src/profilesdialog.ui @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProfilesDialog</class>
+ <widget class="QDialog" name="ProfilesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>471</width>
+ <height>318</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Profiles</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QListWidget" name="profilesList">
+ <property name="toolTip">
+ <string>List of Profiles</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the list of profiles. Each Profile contains its own list and installation order of enabled mods (from a shared pool), a configuration of enabled esps/esms, a copy of the games ini-file and an optional savegame filter.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span> For technical reasons it's currently not possible to have seperate load-orders for esps. This means you can't load moda.esp before modb.esp in one profile and the other way around in another.</p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="localSavesBox">
+ <property name="toolTip">
+ <string>If checked, savegames are local to this profile and will not appear when starting with a different profile.</string>
+ </property>
+ <property name="whatsThis">
+ <string>If checked, savegames are local to this profile and will not appear when starting with a different profile.</string>
+ </property>
+ <property name="text">
+ <string>Local Savegames</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="invalidationBox">
+ <property name="toolTip">
+ <string>This ensures data files from mods are actually used. You want to enable this unless you use a different tool for Archive Invalidation.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The games Oblivion, Fallout 3 and Fallout NV contain a bug which prevents texture and mesh replacers (that is: all modifications to meshes and textures already in game) from working.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Mod Organizer uses a workaround called &quot;BSA redirection&quot; (google is your friend) to fix this issue reliably and without further work. Simply activate and forget.</span></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">With Skyrim this bug seems to be fixed to a degree but whether a mod becomes active still depends on file dates. Therefore, it still makes sense to activate this.</span></p></body></html></string>
+ </property>
+ <property name="text">
+ <string>Automatic Archive Invalidation</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="addProfileButton">
+ <property name="toolTip">
+ <string>Create a new profile from scratch</string>
+ </property>
+ <property name="whatsThis">
+ <string>Create a new profile from scratch</string>
+ </property>
+ <property name="text">
+ <string>Create</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="copyProfileButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Clone the selected profile</string>
+ </property>
+ <property name="whatsThis">
+ <string>This creates a new profile with the same settings and active mods as the selected one.</string>
+ </property>
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeProfileButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Delete the selected Profile. This can not be un-done!</string>
+ </property>
+ <property name="whatsThis">
+ <string>Delete the selected Profile. This can not be un-done!</string>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="transferButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Transfer save games to the selected profile.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Transfer save games to the selected profile.</string>
+ </property>
+ <property name="text">
+ <string>Transfer Saves</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/queryoverwritedialog.cpp b/src/queryoverwritedialog.cpp new file mode 100644 index 00000000..df604f5e --- /dev/null +++ b/src/queryoverwritedialog.cpp @@ -0,0 +1,64 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "queryoverwritedialog.h"
+#include "ui_queryoverwritedialog.h"
+
+QueryOverwriteDialog::QueryOverwriteDialog(QWidget *parent)
+ : QDialog(parent), ui(new Ui::QueryOverwriteDialog),
+ m_Action(ACT_NONE)
+{
+ ui->setupUi(this);
+ QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
+ ui->iconLabel->setPixmap(icon.pixmap(128));
+
+}
+
+QueryOverwriteDialog::~QueryOverwriteDialog()
+{
+ delete ui;
+}
+
+bool QueryOverwriteDialog::backup() const
+{
+ return ui->backupBox->isChecked();
+}
+
+void QueryOverwriteDialog::on_mergeBtn_clicked()
+{
+ this->m_Action = ACT_MERGE;
+ this->accept();
+}
+
+void QueryOverwriteDialog::on_replaceBtn_clicked()
+{
+ this->m_Action = ACT_REPLACE;
+ this->accept();
+}
+
+void QueryOverwriteDialog::on_renameBtn_clicked()
+{
+ this->m_Action = ACT_RENAME;
+ this->accept();
+}
+
+void QueryOverwriteDialog::on_cancelBtn_clicked()
+{
+ this->reject();
+}
diff --git a/src/queryoverwritedialog.h b/src/queryoverwritedialog.h new file mode 100644 index 00000000..e6821c38 --- /dev/null +++ b/src/queryoverwritedialog.h @@ -0,0 +1,56 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef QUERYOVERWRITEDIALOG_H
+#define QUERYOVERWRITEDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class QueryOverwriteDialog;
+}
+
+class QueryOverwriteDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ enum Action {
+ ACT_NONE,
+ ACT_MERGE,
+ ACT_REPLACE,
+ ACT_RENAME
+ };
+
+public:
+ explicit QueryOverwriteDialog(QWidget *parent = 0);
+ ~QueryOverwriteDialog();
+ bool backup() const;
+ Action action() const { return m_Action; }
+private slots:
+ void on_mergeBtn_clicked();
+ void on_replaceBtn_clicked();
+ void on_renameBtn_clicked();
+ void on_cancelBtn_clicked();
+
+private:
+ Ui::QueryOverwriteDialog *ui;
+ Action m_Action;
+};
+
+#endif // QUERYOVERWRITEDIALOG_H
diff --git a/src/queryoverwritedialog.ui b/src/queryoverwritedialog.ui new file mode 100644 index 00000000..2fc471bd --- /dev/null +++ b/src/queryoverwritedialog.ui @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QueryOverwriteDialog</class>
+ <widget class="QDialog" name="QueryOverwriteDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>423</width>
+ <height>153</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Mod Exists</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFrame" name="frame_2">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_1" stretch="0,1">
+ <item>
+ <widget class="QLabel" name="iconLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>This mod seems to be installed already. Do you want to add files from this archive (overwriting existing ones) or do you want to completely replace the existing files (old files are deleted)? Alternatively you can install this mod under a different name.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="margin">
+ <number>7</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="backupBox">
+ <property name="text">
+ <string>Keep Backup</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mergeBtn">
+ <property name="text">
+ <string>Merge</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="replaceBtn">
+ <property name="text">
+ <string>Replace</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="renameBtn">
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/questionboxmemory.cpp b/src/questionboxmemory.cpp new file mode 100644 index 00000000..a7bb72b6 --- /dev/null +++ b/src/questionboxmemory.cpp @@ -0,0 +1,72 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "questionboxmemory.h"
+#include "ui_questionboxmemory.h"
+
+#include <QMessageBox>
+#include <QPushButton>
+
+QuestionBoxMemory::QuestionBoxMemory(QWidget *parent, const QString &title, const QString &text,
+ const QDialogButtonBox::StandardButtons buttons, QDialogButtonBox::StandardButton defaultButton)
+ : QDialog(parent), ui(new Ui::QuestionBoxMemory)
+{
+ ui->setupUi(this);
+
+ this->setWindowTitle(title);
+
+ QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
+ ui->iconLabel->setPixmap(icon.pixmap(128));
+ ui->messageLabel->setText(text);
+ ui->buttonBox->setStandardButtons(buttons);
+ if (defaultButton != QDialogButtonBox::NoButton) {
+ ui->buttonBox->button(defaultButton)->setDefault(true);
+ }
+ connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+}
+
+
+QuestionBoxMemory::~QuestionBoxMemory()
+{
+ delete ui;
+}
+
+
+void QuestionBoxMemory::buttonClicked(QAbstractButton *button)
+{
+ m_Button = ui->buttonBox->standardButton(button);
+}
+
+
+QDialogButtonBox::StandardButton QuestionBoxMemory::query(QWidget *parent,
+ QSettings &settings, const QString &name,
+ const QString &title, const QString &text, QDialogButtonBox::StandardButtons buttons,
+ QDialogButtonBox::StandardButton defaultButton)
+{
+ if (settings.contains(QString("DialogChoices/") + name)) {
+ return static_cast<QDialogButtonBox::StandardButton>(settings.value(QString("DialogChoices/") + name).toInt());
+ } else {
+ QuestionBoxMemory dialog(parent, title, text, buttons, defaultButton);
+ dialog.exec();
+ if (dialog.ui->rememberCheckBox->isChecked()) {
+ settings.setValue(QString("DialogChoices/") + name, dialog.m_Button);
+ }
+ return dialog.m_Button;
+ }
+}
diff --git a/src/questionboxmemory.h b/src/questionboxmemory.h new file mode 100644 index 00000000..72351830 --- /dev/null +++ b/src/questionboxmemory.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef QUESTIONBOXMEMORY_H
+#define QUESTIONBOXMEMORY_H
+
+#include <QDialog>
+#include <QSettings>
+#include <QDialogButtonBox>
+
+
+namespace Ui {
+ class QuestionBoxMemory;
+}
+
+
+class QuestionBoxMemory : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ virtual ~QuestionBoxMemory();
+ static QDialogButtonBox::StandardButton query(QWidget *parent,
+ QSettings &settings, const QString &name,
+ const QString &title, const QString &text,
+ QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes | QDialogButtonBox::No,
+ QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::NoButton);
+private slots:
+
+ void buttonClicked(QAbstractButton *button);
+
+private:
+
+ explicit QuestionBoxMemory(QWidget *parent, const QString &title, const QString &text, const QDialogButtonBox::StandardButtons buttons,
+ QDialogButtonBox::StandardButton defaultButton);
+
+private:
+
+ Ui::QuestionBoxMemory *ui;
+ QDialogButtonBox::StandardButton m_Button;
+
+};
+
+#endif // QUESTIONBOXMEMORY_H
+
+
diff --git a/src/questionboxmemory.ui b/src/questionboxmemory.ui new file mode 100644 index 00000000..9c211fe8 --- /dev/null +++ b/src/questionboxmemory.ui @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QuestionBoxMemory</class>
+ <widget class="QDialog" name="QuestionBoxMemory">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>374</width>
+ <height>130</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Placeholder</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
+ <item>
+ <widget class="QLabel" name="iconLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>36</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="messageLabel">
+ <property name="font">
+ <font>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="margin">
+ <number>7</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="rememberCheckBox">
+ <property name="text">
+ <string>Remember selection</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QuestionBoxMemory</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QuestionBoxMemory</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/report.cpp b/src/report.cpp new file mode 100644 index 00000000..6b379a1f --- /dev/null +++ b/src/report.cpp @@ -0,0 +1,49 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "report.h"
+#include "utility.h"
+#include <QMessageBox>
+#include <QApplication>
+#include <Windows.h>
+
+void reportError(QString message)
+{
+ if (QApplication::topLevelWidgets().count() != 0) {
+ QMessageBox messageBox(QMessageBox::Warning, QObject::tr("Error"), message, QMessageBox::Ok);
+ messageBox.exec();
+ } else {
+ ::MessageBoxW(NULL, ToWString(message).c_str(), ToWString(QObject::tr("Error")).c_str(), MB_ICONERROR | MB_OK);
+ }
+}
+
+
+std::tstring toTString(const QString& source)
+{
+#ifdef UNICODE
+ wchar_t* temp = new wchar_t[source.size() + 1];
+ source.toWCharArray(temp);
+ temp[source.size()] = '\0';
+ std::tstring result(temp);
+ delete[] temp;
+ return result;
+#else // UNICODE
+ return source.toAscii();
+#endif // UNICODE
+}
diff --git a/src/report.h b/src/report.h new file mode 100644 index 00000000..97b8b607 --- /dev/null +++ b/src/report.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef REPORT_H
+#define REPORT_H
+
+#include <QString>
+#include <wchar.h>
+
+namespace std {
+#ifdef UNICODE
+typedef wstring tstring;
+#else
+typedef string tstring;
+#endif
+}
+
+void reportError(QString message);
+
+std::tstring toTString(const QString& source);
+
+#endif // REPORT_H
diff --git a/src/resources.qrc b/src/resources.qrc new file mode 100644 index 00000000..855a23fc --- /dev/null +++ b/src/resources.qrc @@ -0,0 +1,54 @@ +<RCC> + <qresource prefix="/MO/gui"> + <file>resources/help-browser.png</file> + <file alias="add">resources/list-add.png</file> + <file>resources/document-save.png</file> + <file>resources/edit-find-replace.png</file> + <file>resources/go-jump.png</file> + <file>resources/media-playback-start.png</file> + <file alias="remove">resources/process-stop.png</file> + <file>resources/system-search.png</file> + <file>resources/view-refresh.png</file> + <file alias="installer">resources/system-installer.png</file> + <file>resources/start-here.png</file> + <file>resources/list-remove.png</file> + <file>resources/document-properties.png</file> + <file>resources/go-up.png</file> + <file>resources/go-down.png</file> + <file alias="profiles">resources/contact-new.png</file> + <file alias="settings">resources/preferences-system.png</file> + <file alias="executable">resources/application-x-executable.png</file> + <file>resources/dialog-information.png</file> + <file alias="locked">resources/emblem-readonly.png</file> + <file alias="next">resources/go-next_16.png</file> + <file alias="previous">resources/go-previous_16.png</file> + <file alias="refresh">resources/view-refresh_16.png</file> + <file alias="update_available">resources/software-update-available.png</file> + <file>resources/emblem-important.png</file> + <file>resources/check.png</file> + <file>mo_icon.ico</file> + <file>resources/dialog-warning.png</file> + <file>resources/dialog-warning_16.png</file> + <file alias="emblem_backup">resources/symbol-backup.png</file> + <file alias="icon_tools">resources/applications-accessories.png</file> + <file alias="emblem_problem">resources/emblem-unreadable.png</file> + <file>resources/internet-web-browser.png</file> + <file alias="update">resources/system-software-update.png</file> + <file alias="help">resources/help-browser_32.png</file> + <file>resources/system-installer.png</file> + <file alias="icon_executable">resources/function.png</file> + <file alias="plugins">resources/plugins.png</file> + <file alias="edit_clear">resources/edit-clear.png</file> + <file alias="link">resources/dynamic-blue-right.png</file> + <file alias="icon_favorite">resources/icon-favorite.png</file> + <file alias="emblem_notendorsed">resources/emblem-favorite.png</file> + <file alias="emblem_conflict">resources/error.png</file> + <file alias="run">resources/show.png</file> + <file alias="splash">splash.png</file> + <file alias="emblem_conflict_mixed">resources/conflict-mixed.png</file> + <file alias="emblem_conflict_overwrite">resources/conflict-overwrite.png</file> + <file alias="emblem_conflict_overwritten">resources/conflict-overwritten.png</file> + <file alias="emblem_conflict_redundant">resources/conflict-redundant.png</file> + <file alias="emblem_notes">resources/accessories-text-editor.png</file> + </qresource> +</RCC> diff --git a/src/resources/accessories-text-editor.png b/src/resources/accessories-text-editor.png Binary files differnew file mode 100644 index 00000000..188e1c12 --- /dev/null +++ b/src/resources/accessories-text-editor.png diff --git a/src/resources/application-x-executable.png b/src/resources/application-x-executable.png Binary files differnew file mode 100644 index 00000000..8a150b84 --- /dev/null +++ b/src/resources/application-x-executable.png diff --git a/src/resources/applications-accessories.png b/src/resources/applications-accessories.png Binary files differnew file mode 100644 index 00000000..fd43de3d --- /dev/null +++ b/src/resources/applications-accessories.png diff --git a/src/resources/branch-closed.png b/src/resources/branch-closed.png Binary files differnew file mode 100644 index 00000000..f4fe6339 --- /dev/null +++ b/src/resources/branch-closed.png diff --git a/src/resources/branch-open.png b/src/resources/branch-open.png Binary files differnew file mode 100644 index 00000000..457dcc0c --- /dev/null +++ b/src/resources/branch-open.png diff --git a/src/resources/check.png b/src/resources/check.png Binary files differnew file mode 100644 index 00000000..0f294a02 --- /dev/null +++ b/src/resources/check.png diff --git a/src/resources/combobox-down.png b/src/resources/combobox-down.png Binary files differnew file mode 100644 index 00000000..b1527887 --- /dev/null +++ b/src/resources/combobox-down.png diff --git a/src/resources/conflict-mixed.png b/src/resources/conflict-mixed.png Binary files differnew file mode 100644 index 00000000..900062c2 --- /dev/null +++ b/src/resources/conflict-mixed.png diff --git a/src/resources/conflict-overwrite.png b/src/resources/conflict-overwrite.png Binary files differnew file mode 100644 index 00000000..b69cd4d1 --- /dev/null +++ b/src/resources/conflict-overwrite.png diff --git a/src/resources/conflict-overwritten.png b/src/resources/conflict-overwritten.png Binary files differnew file mode 100644 index 00000000..386b4b75 --- /dev/null +++ b/src/resources/conflict-overwritten.png diff --git a/src/resources/conflict-redundant.png b/src/resources/conflict-redundant.png Binary files differnew file mode 100644 index 00000000..06cd8237 --- /dev/null +++ b/src/resources/conflict-redundant.png diff --git a/src/resources/contact-new.png b/src/resources/contact-new.png Binary files differnew file mode 100644 index 00000000..8b10c1e9 --- /dev/null +++ b/src/resources/contact-new.png diff --git a/src/resources/dialog-information.png b/src/resources/dialog-information.png Binary files differnew file mode 100644 index 00000000..07cf0102 --- /dev/null +++ b/src/resources/dialog-information.png diff --git a/src/resources/dialog-warning.png b/src/resources/dialog-warning.png Binary files differnew file mode 100644 index 00000000..7233d45d --- /dev/null +++ b/src/resources/dialog-warning.png diff --git a/src/resources/dialog-warning_16.png b/src/resources/dialog-warning_16.png Binary files differnew file mode 100644 index 00000000..a9e4ff39 --- /dev/null +++ b/src/resources/dialog-warning_16.png diff --git a/src/resources/document-properties.png b/src/resources/document-properties.png Binary files differnew file mode 100644 index 00000000..a5ad7287 --- /dev/null +++ b/src/resources/document-properties.png diff --git a/src/resources/document-save.png b/src/resources/document-save.png Binary files differnew file mode 100644 index 00000000..a94e0eab --- /dev/null +++ b/src/resources/document-save.png diff --git a/src/resources/dynamic-blue-right.png b/src/resources/dynamic-blue-right.png Binary files differnew file mode 100644 index 00000000..cb08cae5 --- /dev/null +++ b/src/resources/dynamic-blue-right.png diff --git a/src/resources/edit-clear.png b/src/resources/edit-clear.png Binary files differnew file mode 100644 index 00000000..e6c8e8b9 --- /dev/null +++ b/src/resources/edit-clear.png diff --git a/src/resources/edit-find-replace.png b/src/resources/edit-find-replace.png Binary files differnew file mode 100644 index 00000000..de3a75f8 --- /dev/null +++ b/src/resources/edit-find-replace.png diff --git a/src/resources/emblem-favorite.png b/src/resources/emblem-favorite.png Binary files differnew file mode 100644 index 00000000..c777c757 --- /dev/null +++ b/src/resources/emblem-favorite.png diff --git a/src/resources/emblem-important.png b/src/resources/emblem-important.png Binary files differnew file mode 100644 index 00000000..81e9ed29 --- /dev/null +++ b/src/resources/emblem-important.png diff --git a/src/resources/emblem-readonly.png b/src/resources/emblem-readonly.png Binary files differnew file mode 100644 index 00000000..04666196 --- /dev/null +++ b/src/resources/emblem-readonly.png diff --git a/src/resources/emblem-redundant.png b/src/resources/emblem-redundant.png Binary files differnew file mode 100644 index 00000000..048942dd --- /dev/null +++ b/src/resources/emblem-redundant.png diff --git a/src/resources/emblem-unreadable.png b/src/resources/emblem-unreadable.png Binary files differnew file mode 100644 index 00000000..5c08b05c --- /dev/null +++ b/src/resources/emblem-unreadable.png diff --git a/src/resources/error.png b/src/resources/error.png Binary files differnew file mode 100644 index 00000000..b1c4764f --- /dev/null +++ b/src/resources/error.png diff --git a/src/resources/function.png b/src/resources/function.png Binary files differnew file mode 100644 index 00000000..0a7eba56 --- /dev/null +++ b/src/resources/function.png diff --git a/src/resources/go-down.png b/src/resources/go-down.png Binary files differnew file mode 100644 index 00000000..af237881 --- /dev/null +++ b/src/resources/go-down.png diff --git a/src/resources/go-jump.png b/src/resources/go-jump.png Binary files differnew file mode 100644 index 00000000..373dce95 --- /dev/null +++ b/src/resources/go-jump.png diff --git a/src/resources/go-next_16.png b/src/resources/go-next_16.png Binary files differnew file mode 100644 index 00000000..6ef8de76 --- /dev/null +++ b/src/resources/go-next_16.png diff --git a/src/resources/go-previous_16.png b/src/resources/go-previous_16.png Binary files differnew file mode 100644 index 00000000..659cd90d --- /dev/null +++ b/src/resources/go-previous_16.png diff --git a/src/resources/go-up.png b/src/resources/go-up.png Binary files differnew file mode 100644 index 00000000..b0a0cd72 --- /dev/null +++ b/src/resources/go-up.png diff --git a/src/resources/help-browser.png b/src/resources/help-browser.png Binary files differnew file mode 100644 index 00000000..c67c7a60 --- /dev/null +++ b/src/resources/help-browser.png diff --git a/src/resources/help-browser_32.png b/src/resources/help-browser_32.png Binary files differnew file mode 100644 index 00000000..d60425f7 --- /dev/null +++ b/src/resources/help-browser_32.png diff --git a/src/resources/icon-favorite.png b/src/resources/icon-favorite.png Binary files differnew file mode 100644 index 00000000..c22b26b8 --- /dev/null +++ b/src/resources/icon-favorite.png diff --git a/src/resources/internet-web-browser.png b/src/resources/internet-web-browser.png Binary files differnew file mode 100644 index 00000000..10d2ed4f --- /dev/null +++ b/src/resources/internet-web-browser.png diff --git a/src/resources/list-add.png b/src/resources/list-add.png Binary files differnew file mode 100644 index 00000000..306d3d89 --- /dev/null +++ b/src/resources/list-add.png diff --git a/src/resources/list-remove.png b/src/resources/list-remove.png Binary files differnew file mode 100644 index 00000000..45e5c2a8 --- /dev/null +++ b/src/resources/list-remove.png diff --git a/src/resources/media-playback-start.png b/src/resources/media-playback-start.png Binary files differnew file mode 100644 index 00000000..10102d82 --- /dev/null +++ b/src/resources/media-playback-start.png diff --git a/src/resources/plugins.png b/src/resources/plugins.png Binary files differnew file mode 100644 index 00000000..8426df9f --- /dev/null +++ b/src/resources/plugins.png diff --git a/src/resources/preferences-system.png b/src/resources/preferences-system.png Binary files differnew file mode 100644 index 00000000..6e52db7c --- /dev/null +++ b/src/resources/preferences-system.png diff --git a/src/resources/process-stop.png b/src/resources/process-stop.png Binary files differnew file mode 100644 index 00000000..b68290bf --- /dev/null +++ b/src/resources/process-stop.png diff --git a/src/resources/show.png b/src/resources/show.png Binary files differnew file mode 100644 index 00000000..ac8b68e6 --- /dev/null +++ b/src/resources/show.png diff --git a/src/resources/software-update-available.png b/src/resources/software-update-available.png Binary files differnew file mode 100644 index 00000000..ab8d494b --- /dev/null +++ b/src/resources/software-update-available.png diff --git a/src/resources/start-here.png b/src/resources/start-here.png Binary files differnew file mode 100644 index 00000000..1e54d01f --- /dev/null +++ b/src/resources/start-here.png diff --git a/src/resources/symbol-backup.png b/src/resources/symbol-backup.png Binary files differnew file mode 100644 index 00000000..f1d7a198 --- /dev/null +++ b/src/resources/symbol-backup.png diff --git a/src/resources/system-installer.png b/src/resources/system-installer.png Binary files differnew file mode 100644 index 00000000..c26576ee --- /dev/null +++ b/src/resources/system-installer.png diff --git a/src/resources/system-search.png b/src/resources/system-search.png Binary files differnew file mode 100644 index 00000000..4e522b23 --- /dev/null +++ b/src/resources/system-search.png diff --git a/src/resources/system-software-update.png b/src/resources/system-software-update.png Binary files differnew file mode 100644 index 00000000..470b5d46 --- /dev/null +++ b/src/resources/system-software-update.png diff --git a/src/resources/view-refresh.png b/src/resources/view-refresh.png Binary files differnew file mode 100644 index 00000000..cab4d02c --- /dev/null +++ b/src/resources/view-refresh.png diff --git a/src/resources/view-refresh_16.png b/src/resources/view-refresh_16.png Binary files differnew file mode 100644 index 00000000..3fd71d6e --- /dev/null +++ b/src/resources/view-refresh_16.png diff --git a/src/savegame.cpp b/src/savegame.cpp new file mode 100644 index 00000000..0ddd5fd2 --- /dev/null +++ b/src/savegame.cpp @@ -0,0 +1,84 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "savegame.h"
+#include <QFile>
+#include <QBuffer>
+#include <set>
+#include "gameinfo.h"
+#include <QFileInfo>
+#include <QDateTime>
+#include <limits>
+
+
+SaveGame::SaveGame(QObject *parent)
+ : QObject(parent), m_FileName(), m_PCName(), m_PCLevel(0), m_PCLocation(), m_SaveNumber(0), m_Screenshot()
+{
+}
+
+
+SaveGame::SaveGame(QObject *parent, const QString &filename)
+ : QObject(parent), m_FileName(filename), m_PCName(), m_PCLevel(0), m_PCLocation(), m_SaveNumber(0), m_Screenshot()
+{
+}
+
+
+SaveGame::SaveGame(const SaveGame& reference)
+ : m_FileName(reference.m_FileName), m_PCName(reference.m_PCName), m_PCLevel(reference.m_PCLevel),
+ m_PCLocation(reference.m_PCLocation), m_SaveNumber(reference.m_SaveNumber),
+ m_Screenshot(reference.m_Screenshot)
+{
+}
+
+
+SaveGame& SaveGame::operator=(const SaveGame &reference)
+{
+ if (&reference != this) {
+ m_FileName = reference.m_FileName;
+ m_PCName = reference.m_PCName;
+ m_PCLevel = reference.m_PCLevel;
+ m_PCLocation = reference.m_PCLocation;
+ m_SaveNumber = reference.m_SaveNumber;
+ m_Screenshot = reference.m_Screenshot;
+ }
+ return *this;
+}
+
+
+SaveGame::~SaveGame()
+{
+}
+
+
+void SaveGame::setCreationTime(const QString &fileName)
+{
+ QFileInfo creationTime(fileName);
+ QDateTime modified = creationTime.lastModified();
+ memset(&m_CreationTime, 0, sizeof(SYSTEMTIME));
+
+ m_CreationTime.wDay = static_cast<WORD>(modified.date().day());
+ m_CreationTime.wDayOfWeek = static_cast<WORD>(modified.date().dayOfWeek());
+ m_CreationTime.wMonth = static_cast<WORD>(modified.date().month());
+ m_CreationTime.wYear =static_cast<WORD>( modified.date().year());
+
+ m_CreationTime.wHour = static_cast<WORD>(modified.time().hour());
+ m_CreationTime.wMinute = static_cast<WORD>(modified.time().minute());
+ m_CreationTime.wSecond = static_cast<WORD>(modified.time().second());
+ m_CreationTime.wMilliseconds = static_cast<WORD>(modified.time().msec());
+}
diff --git a/src/savegame.h b/src/savegame.h new file mode 100644 index 00000000..e3eb8546 --- /dev/null +++ b/src/savegame.h @@ -0,0 +1,126 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SAVEGAME_H
+#define SAVEGAME_H
+
+
+#include <QString>
+#include <QObject>
+#include <QImage>
+#include <QMetaType>
+#include <QFile>
+#include <QStringList>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+
+/**
+ * @brief represents a single save game
+ **/
+class SaveGame : public QObject {
+
+Q_OBJECT
+
+public:
+
+ /**
+ * @brief construct an empty object
+ **/
+ SaveGame(QObject *parent = 0);
+
+ /**
+ * @brief construct a save game and immediately read out information from the file
+ *
+ * @param filename absolute path of the save game file
+ **/
+ SaveGame(QObject *parent, const QString &filename);
+
+ SaveGame(const SaveGame& reference);
+
+ SaveGame& operator=(const SaveGame &reference);
+
+ ~SaveGame();
+
+ /**
+ * @brief read out information from a savegame
+ *
+ * @param fileName absolute path of the save game file
+ **/
+ virtual void readFile(const QString &fileName) = 0;
+
+ /**
+ * @return filename of this savegame
+ */
+ const QString &fileName() const { return m_FileName; }
+
+ /**
+ * @return a list of additional files that belong to this savegame
+ */
+ virtual QStringList attachedFiles() const { return QStringList(); }
+
+ /**
+ * @return name of the player character
+ **/
+ const QString &pcName() const { return m_PCName; }
+
+ /**
+ * @return level of the player character
+ **/
+ unsigned short pcLevel() const { return m_PCLevel; }
+
+ /**
+ * @return location of the player character
+ **/
+ const QString &pcLocation() const { return m_PCLocation; }
+
+ /**
+ * @return index of the save game
+ **/
+ unsigned long saveNumber() const { return m_SaveNumber; }
+
+ /**
+ * @return creation time of the save game
+ **/
+ SYSTEMTIME creationTime() const { return m_CreationTime; }
+
+ /**
+ * @return screenshot in the savegame
+ **/
+ const QImage &screenshot() const { return m_Screenshot; }
+
+private:
+
+ void setCreationTime(const QString &fileName);
+
+protected:
+
+ QString m_FileName;
+ QString m_PCName;
+ unsigned short m_PCLevel;
+ QString m_PCLocation;
+ unsigned long m_SaveNumber;
+ SYSTEMTIME m_CreationTime;
+ QImage m_Screenshot;
+
+};
+
+
+#endif // SAVEGAME_H
diff --git a/src/savegamegamebryo.cpp b/src/savegamegamebryo.cpp new file mode 100644 index 00000000..3b7ef017 --- /dev/null +++ b/src/savegamegamebryo.cpp @@ -0,0 +1,344 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "savegamegamebyro.h"
+#include <QFile>
+#include <QBuffer>
+#include <set>
+#include "gameinfo.h"
+#include <QFileInfo>
+#include <QDateTime>
+#include <limits>
+
+
+template <typename T>
+void FileRead(QFile &file, T &value)
+{
+ int read = file.read(reinterpret_cast<char*>(&value), sizeof(T));
+ if (read != sizeof(T)) {
+ throw std::runtime_error("unexpected end of file");
+ }
+}
+
+
+template <typename T>
+void FileSkip(QFile &file, int count = 1)
+{
+ char ignore[sizeof(T)];
+ for (int i = 0; i < count; ++i) {
+ if (file.read(ignore, sizeof(T)) != sizeof(T)) {
+ throw std::runtime_error("unexpected end of file");
+ }
+ }
+}
+
+
+QString ReadBString(QFile &file)
+{
+ char buffer[256];
+ file.read(buffer, 1); // size including zero termination
+ unsigned char size = buffer[0];
+ file.read(buffer, size);
+ return QString::fromLatin1(buffer, size);
+}
+
+
+QString ReadFOSString(QFile &file, bool delimiter)
+{
+ union {
+ char lengthBuffer[2];
+ unsigned short length;
+ };
+
+ file.read(lengthBuffer, 2);
+ if (delimiter) {
+ FileSkip<char>(file); // 0x7c
+ }
+ char *buffer = new char[length];
+ file.read(buffer, length);
+
+ QString result = QString::fromLatin1(buffer, length);
+ delete [] buffer;
+
+ return result;
+}
+
+
+SaveGameGamebryo::SaveGameGamebryo(QObject *parent)
+ : SaveGame(parent), m_Plugins()
+{
+}
+
+
+SaveGameGamebryo::SaveGameGamebryo(QObject *parent, const QString &fileName)
+ : SaveGame(parent, fileName), m_Plugins()
+{
+ readFile(fileName);
+}
+
+
+SaveGameGamebryo::SaveGameGamebryo(const SaveGameGamebryo& reference)
+ : SaveGame(reference), m_Plugins(reference.m_Plugins)
+{
+}
+
+
+SaveGameGamebryo& SaveGameGamebryo::operator=(const SaveGameGamebryo &reference)
+{
+ if (&reference != this) {
+ SaveGame::operator =(reference);
+ m_Plugins = reference.m_Plugins;
+ }
+ return *this;
+}
+
+
+SaveGameGamebryo::~SaveGameGamebryo()
+{
+}
+
+
+QStringList SaveGameGamebryo::attachedFiles() const
+{
+ QStringList result;
+ QString seFileFile = fileName().mid(0).replace(".ess", ".skse");
+ QFileInfo seFile(seFileFile);
+ if (seFile.exists()) {
+ result.append(seFile.absoluteFilePath());
+ }
+ return result;
+}
+
+
+void SaveGameGamebryo::readSkyrimFile(QFile &saveFile)
+{
+ char fileID[14];
+
+ saveFile.read(fileID, 13);
+ fileID[13] = '\0';
+ if (strncmp(fileID, "TESV_SAVEGAME", 13) != 0) {
+ throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
+ }
+
+ FileSkip<unsigned long>(saveFile); // header size
+ FileSkip<unsigned long>(saveFile); // header version, -> 8
+ FileRead(saveFile, m_SaveNumber);
+
+ m_PCName = ReadFOSString(saveFile, false);
+
+ unsigned long temp;
+ FileRead(saveFile, temp); // player level
+ m_PCLevel = static_cast<unsigned short>(temp);
+
+ m_PCLocation = ReadFOSString(saveFile, false);
+ ReadFOSString(saveFile, false); // playtime as ascii hhh.mm.ss
+ ReadFOSString(saveFile, false); // race name (i.e. BretonRace)
+
+
+ FileSkip<unsigned short>(saveFile); // ???
+ FileSkip<float>(saveFile, 2); // ???
+ FileSkip<unsigned char>(saveFile, 8); // filetime
+
+// FileSkip<unsigned char>(saveFile, 18); // ??? 18 bytes of data. not completely random, maybe a time stamp? maybe
+
+ unsigned long width, height;
+ FileRead(saveFile, width); // 320
+ FileRead(saveFile, height); // 192
+
+ QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
+ saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
+ // why do I have to copy here? without the copy, the buffer seems to get deleted after the
+ // temporary vanishes, but Qts implicit sharing should handle that?
+ m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).copy();
+
+ FileSkip<unsigned char>(saveFile); // form version
+ FileSkip<unsigned long>(saveFile); // plugin info size
+
+ unsigned char pluginCount;
+ FileRead(saveFile, pluginCount);
+
+ for (int i = 0; i < pluginCount; ++i) {
+ m_Plugins.push_back(ReadFOSString(saveFile, false));
+ }
+}
+
+
+void SaveGameGamebryo::readESSFile(QFile &saveFile)
+{
+ char fileID[13];
+ unsigned char versionMinor;
+ unsigned long headerVersion, saveHeaderSize;
+// *** format is different for fallout!
+ saveFile.read(fileID, 12);
+ fileID[12] = '\0';
+ FileSkip<unsigned char>(saveFile); FileRead(saveFile, versionMinor);
+ FileSkip<SYSTEMTIME>(saveFile); // modified time
+ FileRead(saveFile, headerVersion); FileRead(saveFile, saveHeaderSize);
+
+ if (strncmp(fileID, "TES4SAVEGAME", 12) != 0) {
+ throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
+ }
+
+ FileRead(saveFile, m_SaveNumber);
+
+ m_PCName = ReadBString(saveFile);
+
+ FileRead(saveFile, m_PCLevel);
+ m_PCLocation = ReadBString(saveFile);
+ FileSkip<float>(saveFile); // game days
+ FileSkip<unsigned long>(saveFile); // game ticks
+ FileRead(saveFile, m_CreationTime);
+
+ unsigned long size;
+ FileRead(saveFile, size); // screenshot size
+
+ unsigned long width, height;
+ FileRead(saveFile, width); FileRead(saveFile, height);
+ QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
+ saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
+ // why do I have to copy here? without the copy, the buffer seems to get deleted after the
+ // temporary vanishes, but Qts implicit sharing should handle that?
+ m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).copy();
+
+ unsigned char pluginCount;
+ FileRead(saveFile, pluginCount);
+
+ for (int i = 0; i < pluginCount; ++i) {
+ QString name = ReadBString(saveFile);
+ m_Plugins.push_back(name);
+ }
+}
+
+
+void SaveGameGamebryo::readFOSFile(QFile &saveFile, bool newVegas)
+{
+ char fileID[13];
+ saveFile.read(fileID, 12);
+ // the signature is only 11 characters, the 12th is random?
+ fileID[11] = '\0';
+
+ if (strncmp(fileID, "FO3SAVEGAME", 11) != 0) {
+ throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
+ }
+
+ char ignore = 0x00;
+ while (ignore != 0x7c) {
+ FileRead<char>(saveFile, ignore); // unknown
+ }
+ if (newVegas) {
+ ignore = 0x00;
+ // in new vegas there is another block of uninteresting (?) information
+ FileSkip<char>(saveFile); // 0x7c
+ while (ignore != 0x7c) {
+ FileRead<char>(saveFile, ignore); // unknown
+ }
+ }
+
+ unsigned long width, height;
+ FileRead(saveFile, width);
+ FileSkip<char>(saveFile); // 0x7c
+ FileRead(saveFile, height);
+ FileSkip<char>(saveFile); // 0x7c
+
+ FileRead(saveFile, m_SaveNumber);
+ FileSkip<char>(saveFile); // 0x7c
+
+ m_PCName = ReadFOSString(saveFile, true);
+ FileSkip<char>(saveFile); // 0x7c
+
+ ReadFOSString(saveFile, true);
+ FileSkip<char>(saveFile); // 0x7c
+
+ long Level;
+ FileRead(saveFile, Level);
+ m_PCLevel = Level;
+ FileSkip<char>(saveFile); // 0x7c
+
+ m_PCLocation = ReadFOSString(saveFile, true);
+ FileSkip<char>(saveFile); // 0x7c
+
+ ReadFOSString(saveFile, true); // playtime
+
+ FileSkip<char>(saveFile);
+
+ QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
+ saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
+ // why do I have to copy here? without the copy, the buffer seems to get deleted after the
+ // temporary vanishes, but Qts implicit sharing should handle that?
+ m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).scaledToWidth(256);
+
+ FileSkip<char>(saveFile, 5); // unknown
+
+ unsigned char pluginCount = 0;
+ FileRead(saveFile, pluginCount);
+ FileSkip<char>(saveFile); // 0x7c
+
+ for (int i = 0; i < pluginCount; ++i) {
+ QString name = ReadFOSString(saveFile, true);
+ m_Plugins.push_back(name);
+ FileSkip<char>(saveFile); // 0x7c
+ }
+}
+
+
+void SaveGameGamebryo::setCreationTime(const QString &fileName)
+{
+ QFileInfo creationTime(fileName);
+ QDateTime modified = creationTime.lastModified();
+ memset(&m_CreationTime, 0, sizeof(SYSTEMTIME));
+
+ m_CreationTime.wDay = static_cast<WORD>(modified.date().day());
+ m_CreationTime.wDayOfWeek = static_cast<WORD>(modified.date().dayOfWeek());
+ m_CreationTime.wMonth = static_cast<WORD>(modified.date().month());
+ m_CreationTime.wYear =static_cast<WORD>( modified.date().year());
+
+ m_CreationTime.wHour = static_cast<WORD>(modified.time().hour());
+ m_CreationTime.wMinute = static_cast<WORD>(modified.time().minute());
+ m_CreationTime.wSecond = static_cast<WORD>(modified.time().second());
+ m_CreationTime.wMilliseconds = static_cast<WORD>(modified.time().msec());
+}
+
+
+void SaveGameGamebryo::readFile(const QString &fileName)
+{
+ m_FileName = fileName;
+ QFile saveFile(fileName);
+ if (!saveFile.open(QIODevice::ReadOnly)) {
+ throw std::runtime_error(QObject::tr("failed to open %1").arg(fileName).toUtf8().constData());
+ }
+ switch (GameInfo::instance().getType()) {
+ case GameInfo::TYPE_FALLOUT3: {
+ setCreationTime(fileName);
+ readFOSFile(saveFile, false);
+ } break;
+ case GameInfo::TYPE_FALLOUTNV: {
+ setCreationTime(fileName);
+ readFOSFile(saveFile, true);
+ } break;
+ case GameInfo::TYPE_OBLIVION: {
+ readESSFile(saveFile);
+ } break;
+ case GameInfo::TYPE_SKYRIM: {
+ setCreationTime(fileName);
+ readSkyrimFile(saveFile);
+ } break;
+ }
+
+ saveFile.close();
+}
diff --git a/src/savegamegamebyro.h b/src/savegamegamebyro.h new file mode 100644 index 00000000..25822b0c --- /dev/null +++ b/src/savegamegamebyro.h @@ -0,0 +1,107 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SAVEGAMEGAMEBRYO_H
+#define SAVEGAMEGAMEBRYO_H
+
+
+#include "savegame.h"
+#include <gameinfo.h>
+#include <QString>
+#include <QObject>
+#include <QImage>
+#include <QMetaType>
+#include <QFile>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+
+/**
+ * @brief represents a single save game
+ **/
+class SaveGameGamebryo : public SaveGame {
+
+Q_OBJECT
+
+public:
+
+ /**
+ * @brief construct an empty object
+ **/
+ SaveGameGamebryo(QObject *parent = 0);
+
+ /**
+ * @brief construct a save game and immediately read out information from the file
+ *
+ * @param filename absolute path of the save game file
+ **/
+ SaveGameGamebryo(QObject *parent, const QString &filename);
+
+
+ SaveGameGamebryo(const SaveGameGamebryo &reference);
+
+ SaveGameGamebryo &operator=(const SaveGameGamebryo &reference);
+
+ ~SaveGameGamebryo();
+
+ /**
+ * @return a list of additional files that belong to this savegame
+ */
+ virtual QStringList attachedFiles() const;
+
+ /**
+ * @brief read out information from a savegame
+ *
+ * @param fileName absolute path of the save game file
+ **/
+ virtual void readFile(const QString &fileName);
+
+ /**
+ * @return number of plugins that were enabled when the save game was created
+ **/
+ int numPlugins() const { return m_Plugins.size(); }
+
+ /**
+ * retrieve the name of one of the plugins that were enabled when the save game
+ * was created. valid indices are in the range between [0, numPlugins()[
+ * @param index plugin index
+ * @return name of the plugin
+ **/
+ const QString &plugin(int index) const { return m_Plugins.at(index); }
+
+
+private:
+
+ void readESSFile(QFile &saveFile);
+ void readFOSFile(QFile &saveFile, bool newVegas);
+ void readSkyrimFile(QFile &saveFile);
+
+ void setCreationTime(const QString &fileName);
+
+private:
+
+ std::vector<QString> m_Plugins;
+
+};
+
+Q_DECLARE_METATYPE(SaveGameGamebryo)
+Q_DECLARE_METATYPE(SaveGameGamebryo*)
+
+#endif // SAVEGAMEGAMEBRYO_H
diff --git a/src/savegameinfowidget.cpp b/src/savegameinfowidget.cpp new file mode 100644 index 00000000..34a0f358 --- /dev/null +++ b/src/savegameinfowidget.cpp @@ -0,0 +1,62 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "savegameinfowidget.h"
+#include "ui_savegameinfowidget.h"
+#include "utility.h"
+#include <QGraphicsDropShadowEffect>
+
+
+SaveGameInfoWidget::SaveGameInfoWidget(QWidget *parent)
+ : QWidget(parent), ui(new Ui::SaveGameInfoWidget)
+{
+ ui->setupUi(this);
+ this->setWindowFlags(Qt::ToolTip | Qt::BypassGraphicsProxyWidget);
+ setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / qreal(255.0));
+// installEventFilter(this);
+}
+
+SaveGameInfoWidget::~SaveGameInfoWidget()
+{
+ delete ui;
+}
+
+
+void SaveGameInfoWidget::setSave(const SaveGame *saveGame)
+{
+ ui->saveNumLabel->setText(QString("%1").arg(saveGame->saveNumber()));
+ ui->characterLabel->setText(saveGame->pcName());
+ ui->locationLabel->setText(saveGame->pcLocation());
+ ui->levelLabel->setText(QString("%1").arg(saveGame->pcLevel()));
+ ui->dateLabel->setText(ToString(saveGame->creationTime()));
+ ui->screenshotLabel->setPixmap(QPixmap::fromImage(saveGame->screenshot()));
+ if (ui->gameFrame->layout() != NULL) {
+ QLayoutItem *item = NULL;
+ while ((item = ui->gameFrame->layout()->takeAt(0)) != NULL) {
+ delete item->widget();
+ delete item;
+ }
+ ui->gameFrame->layout()->setSizeConstraint(QLayout::SetFixedSize);
+ }
+}
+
+QFrame *SaveGameInfoWidget::getGameFrame()
+{
+ return ui->gameFrame;
+}
diff --git a/src/savegameinfowidget.h b/src/savegameinfowidget.h new file mode 100644 index 00000000..318108c4 --- /dev/null +++ b/src/savegameinfowidget.h @@ -0,0 +1,60 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SAVEGAMEINFOWIDGET_H
+#define SAVEGAMEINFOWIDGET_H
+
+#include <QWidget>
+#include <QFrame>
+#include "savegame.h"
+
+namespace Ui {
+class SaveGameInfoWidget;
+}
+
+class SaveGameInfoWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ explicit SaveGameInfoWidget(QWidget *parent = 0);
+ ~SaveGameInfoWidget();
+
+ virtual void setSave(const SaveGame *saveGame);
+
+signals:
+
+ void closeSaveInfo();
+
+protected:
+
+// virtual bool eventFilter(QObject *object, QEvent *event);
+
+ QFrame *getGameFrame();
+
+private:
+
+private:
+
+ Ui::SaveGameInfoWidget *ui;
+
+};
+
+#endif // SAVEGAMEINFOWIDGET_H
diff --git a/src/savegameinfowidget.ui b/src/savegameinfowidget.ui new file mode 100644 index 00000000..2b0c921b --- /dev/null +++ b/src/savegameinfowidget.ui @@ -0,0 +1,624 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SaveGameInfoWidget</class>
+ <widget class="QWidget" name="SaveGameInfoWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string/>
+ </property>
+ <property name="toolTip">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Save #</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Character</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Level</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Location</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="saveNumLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="characterLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="levelLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="locationLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="dateLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QFrame" name="gameFrame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="palette">
+ <palette>
+ <active>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>191</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Midlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>212</red>
+ <green>0</green>
+ <blue>159</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Dark">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Mid">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>113</red>
+ <green>0</green>
+ <blue>84</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="BrightText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Shadow">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="AlternateBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>212</red>
+ <green>127</green>
+ <blue>191</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>220</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </active>
+ <inactive>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>191</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Midlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>212</red>
+ <green>0</green>
+ <blue>159</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Dark">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Mid">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>113</red>
+ <green>0</green>
+ <blue>84</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="BrightText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Shadow">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="AlternateBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>212</red>
+ <green>127</green>
+ <blue>191</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>220</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </inactive>
+ <disabled>
+ <colorrole role="WindowText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Button">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Light">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>0</green>
+ <blue>191</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Midlight">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>212</red>
+ <green>0</green>
+ <blue>159</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Dark">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Mid">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>113</red>
+ <green>0</green>
+ <blue>84</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Text">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="BrightText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>255</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ButtonText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>85</red>
+ <green>0</green>
+ <blue>63</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Base">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Window">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="Shadow">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="AlternateBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>170</red>
+ <green>0</green>
+ <blue>127</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipBase">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>255</red>
+ <green>255</green>
+ <blue>220</blue>
+ </color>
+ </brush>
+ </colorrole>
+ <colorrole role="ToolTipText">
+ <brush brushstyle="SolidPattern">
+ <color alpha="255">
+ <red>0</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </brush>
+ </colorrole>
+ </disabled>
+ </palette>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="screenshotLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/savegameinfowidgetgamebryo.cpp b/src/savegameinfowidgetgamebryo.cpp new file mode 100644 index 00000000..d4f80e87 --- /dev/null +++ b/src/savegameinfowidgetgamebryo.cpp @@ -0,0 +1,73 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "savegameinfowidgetgamebryo.h"
+#include <QLabel>
+#include <QVBoxLayout>
+
+
+SaveGameInfoWidgetGamebryo::SaveGameInfoWidgetGamebryo(const SaveGame *saveGame, PluginList *pluginList, QWidget *parent)
+ : SaveGameInfoWidget(parent), m_PluginList(pluginList)
+{
+ QVBoxLayout *gameLayout = new QVBoxLayout();
+ gameLayout->setMargin(0);
+ gameLayout->setSpacing(2);
+ getGameFrame()->setLayout(gameLayout);
+ setSave(saveGame);
+}
+
+
+void SaveGameInfoWidgetGamebryo::setSave(const SaveGame *saveGame)
+{
+ SaveGameInfoWidget::setSave(saveGame);
+ const SaveGameGamebryo *gamebryoSave = qobject_cast<const SaveGameGamebryo*>(saveGame);
+ QLayout *layout = getGameFrame()->layout();
+ QLabel *header = new QLabel(tr("Missing ESPs"));
+ QFont headerFont = header->font();
+ QFont contentFont = headerFont;
+ headerFont.setItalic(true);
+ contentFont.setBold(true);
+ contentFont.setPointSize(7);
+ header->setFont(headerFont);
+ layout->addWidget(header);
+ int count = 0;
+ for (int i = 0; i < gamebryoSave->numPlugins(); ++i) {
+ const QString &pluginName = gamebryoSave->plugin(i);
+ if (m_PluginList->isEnabled(pluginName)) {
+ continue;
+ } else {
+ ++count;
+ }
+
+ if (count > 10) {
+ break;
+ }
+
+ QLabel *pluginLabel = new QLabel(gamebryoSave->plugin(i));
+ pluginLabel->setIndent(10);
+ pluginLabel->setFont(contentFont);
+ layout->addWidget(pluginLabel);
+ }
+ if (count > 10) {
+ QLabel *dotDotLabel = new QLabel("...");
+ dotDotLabel->setIndent(10);
+ dotDotLabel->setFont(contentFont);
+ layout->addWidget(dotDotLabel);
+ }
+}
diff --git a/src/savegameinfowidgetgamebryo.h b/src/savegameinfowidgetgamebryo.h new file mode 100644 index 00000000..b60de8ea --- /dev/null +++ b/src/savegameinfowidgetgamebryo.h @@ -0,0 +1,43 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SAVEGAMEINFOWIDGETGAMEBRYO_H
+#define SAVEGAMEINFOWIDGETGAMEBRYO_H
+
+
+#include "savegamegamebyro.h"
+#include "savegameinfowidget.h"
+#include "pluginlist.h"
+
+
+class SaveGameInfoWidgetGamebryo : public SaveGameInfoWidget
+{
+public:
+
+ explicit SaveGameInfoWidgetGamebryo(const SaveGame *saveGame, PluginList *pluginList, QWidget *parent = 0);
+
+ virtual void setSave(const SaveGame *saveGame);
+
+private:
+
+ PluginList *m_PluginList;
+
+};
+
+#endif // SAVEGAMEINFOWIDGETGAMEBRYO_H
diff --git a/src/selectiondialog.cpp b/src/selectiondialog.cpp new file mode 100644 index 00000000..dbc10791 --- /dev/null +++ b/src/selectiondialog.cpp @@ -0,0 +1,78 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "selectiondialog.h"
+#include "ui_selectiondialog.h"
+
+#include <QCommandLinkButton>
+
+SelectionDialog::SelectionDialog(const QString &description, QWidget *parent)
+ : QDialog(parent), ui(new Ui::SelectionDialog), m_Choice(NULL), m_ValidateByData(false)
+{
+ ui->setupUi(this);
+
+ ui->descriptionLabel->setText(description);
+}
+
+SelectionDialog::~SelectionDialog()
+{
+ delete ui;
+}
+
+
+void SelectionDialog::addChoice(const QString &buttonText, const QString &description, const QVariant &data)
+{
+ QCommandLinkButton *button = new QCommandLinkButton(buttonText, description, ui->buttonBox);
+ button->setProperty("data", data);
+ ui->buttonBox->addButton(button, QDialogButtonBox::AcceptRole);
+ if (data.isValid()) m_ValidateByData = true;
+}
+
+
+QVariant SelectionDialog::getChoiceData()
+{
+ return m_Choice->property("data");
+}
+
+
+QString SelectionDialog::getChoiceString()
+{
+ if ((m_Choice == NULL) ||
+ (m_ValidateByData && !m_Choice->property("data").isValid())) {
+ return QString();
+ } else {
+ return m_Choice->text();
+ }
+}
+
+
+void SelectionDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+ m_Choice = button;
+ if (!m_ValidateByData || m_Choice->property("data").isValid()) {
+ this->accept();
+ } else {
+ this->reject();
+ }
+}
+
+void SelectionDialog::on_cancelButton_clicked()
+{
+ this->reject();
+}
diff --git a/src/selectiondialog.h b/src/selectiondialog.h new file mode 100644 index 00000000..a2844e97 --- /dev/null +++ b/src/selectiondialog.h @@ -0,0 +1,66 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SELECTIONDIALOG_H
+#define SELECTIONDIALOG_H
+
+#include <QDialog>
+#include <QAbstractButton>
+
+namespace Ui {
+class SelectionDialog;
+}
+
+class SelectionDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ explicit SelectionDialog(const QString &description, QWidget *parent = 0);
+
+ ~SelectionDialog();
+
+ /**
+ * @brief add a choice to the dialog
+ * @param buttonText the text to be displayed on the button
+ * @param description the description that shows up under in small letters inside the button
+ * @param data data to be stored with the button. Please note that as soon as one choice has data associated with it (non-invalid QVariant)
+ * all buttons that contain no data will be treated as "cancel" buttons
+ */
+ void addChoice(const QString &buttonText, const QString &description, const QVariant &data);
+
+ QVariant getChoiceData();
+ QString getChoiceString();
+
+private slots:
+
+ void on_buttonBox_clicked(QAbstractButton *button);
+
+ void on_cancelButton_clicked();
+
+private:
+
+ Ui::SelectionDialog *ui;
+ QAbstractButton *m_Choice;
+ bool m_ValidateByData;
+
+};
+
+#endif // SELECTIONDIALOG_H
diff --git a/src/selectiondialog.ui b/src/selectiondialog.ui new file mode 100644 index 00000000..77cfa44e --- /dev/null +++ b/src/selectiondialog.ui @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SelectionDialog</class>
+ <widget class="QDialog" name="SelectionDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>527</width>
+ <height>327</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Select</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>20</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string>Placeholder</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>503</width>
+ <height>219</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::NoButton</set>
+ </property>
+ <property name="centerButtons">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp new file mode 100644 index 00000000..884f9647 --- /dev/null +++ b/src/selfupdater.cpp @@ -0,0 +1,455 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "selfupdater.h"
+#include "utility.h"
+#include "installationmanager.h"
+#include "report.h"
+#include "messagedialog.h"
+#include "downloadmanager.h"
+
+#include <versioninfo.h>
+#include <gameinfo.h>
+#include <skyriminfo.h>
+#include <QMessageBox>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QDir>
+#include <QLibrary>
+#include <QProcess>
+#include <QApplication>
+#include <util.h>
+
+
+typedef Archive* (*CreateArchiveType)();
+
+
+template <typename T> T resolveFunction(QLibrary &lib, const char *name)
+{
+ T temp = reinterpret_cast<T>(lib.resolve(name));
+ if (temp == NULL) {
+ throw std::runtime_error(QObject::tr("invalid 7-zip32.dll: %1").arg(lib.errorString()).toLatin1().constData());
+ }
+ return temp;
+}
+
+
+SelfUpdater::SelfUpdater(NexusInterface *nexusInterface, QWidget *parent)
+ : QObject(parent), m_Parent(parent), m_Interface(nexusInterface), m_UpdateRequestID(-1),
+ m_Reply(NULL), m_Progress(parent), m_Attempts(3)
+{
+ m_Progress.setMaximum(100);
+
+ QLibrary archiveLib("dlls\\archive.dll");
+ if (!archiveLib.load()) {
+ throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString()));
+ }
+
+ CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive");
+
+ m_CurrentArchive = CreateArchiveFunc();
+ if (!m_CurrentArchive->isValid()) {
+ throw MyException(InstallationManager::getErrorString(m_CurrentArchive->getLastError()));
+ }
+
+ connect(&m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel()));
+
+ VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
+
+ m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
+ version.dwFileVersionMS & 0xFFFF,
+ version.dwFileVersionLS >> 16);
+}
+
+
+SelfUpdater::~SelfUpdater()
+{
+ delete m_CurrentArchive;
+}
+
+
+void SelfUpdater::testForUpdate()
+{
+/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) {
+ emit updateAvailable();
+ return;
+ }*/
+
+ if (m_UpdateRequestID == -1) {
+ m_UpdateRequestID = m_Interface->requestDescription(
+ SkyrimInfo::getNexusModIDStatic(), this, QVariant(),
+ ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ }
+}
+
+void SelfUpdater::startUpdate()
+{
+/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) {
+ m_UpdateFile.setFileName(QCoreApplication::applicationDirPath() + "/mo_test_update.7z");
+ installUpdate();
+ return;
+ }*/
+
+ if ((m_UpdateRequestID == -1) &&
+ (!m_NewestVersion.isEmpty())) {
+ if (QMessageBox::question(m_Parent, tr("Update"),
+ tr("An update is available (newest version: %1), do you want to install it?").arg(m_NewestVersion),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ m_UpdateRequestID = m_Interface->requestFiles(SkyrimInfo::getNexusModIDStatic(),
+ this, m_NewestVersion,
+ ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ }
+ }
+}
+
+
+void SelfUpdater::download(const QString &downloadLink, const QString &fileName)
+{
+ qDebug("download: %s", downloadLink.toUtf8().constData());
+ QNetworkAccessManager *accessManager = m_Interface->getAccessManager();
+ QUrl dlUrl(downloadLink);
+ QNetworkRequest request(dlUrl);
+ m_Canceled = false;
+ m_Reply = accessManager->get(request);
+ m_UpdateFile.setFileName(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()).append("\\").append(fileName)));
+ m_UpdateFile.open(QIODevice::WriteOnly);
+ m_Progress.setModal(true);
+ m_Progress.show();
+ m_Progress.setValue(0);
+ m_Progress.setWindowTitle(tr("Update"));
+ m_Progress.setLabelText(tr("Download in progress"));
+
+ connect(m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)));
+ connect(m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ connect(m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
+}
+
+
+void SelfUpdater::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ if (m_Reply != NULL) {
+ if (m_Canceled) {
+ m_Reply->abort();
+ } else {
+ if (bytesTotal != 0) {
+ m_Progress.setValue((bytesReceived * 100) / bytesTotal);
+ }
+ }
+ }
+}
+
+
+void SelfUpdater::downloadReadyRead()
+{
+ if (m_Reply != NULL) {
+ m_UpdateFile.write(m_Reply->readAll());
+ }
+}
+
+
+void SelfUpdater::downloadFinished()
+{
+ int error = QNetworkReply::NoError;
+
+ if (m_Reply != NULL) {
+ m_UpdateFile.write(m_Reply->readAll());
+
+ error = m_Reply->error();
+
+ if (m_Reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) {
+ m_Canceled = true;
+ }
+
+ m_Progress.hide();
+ m_Reply->close();
+ m_Reply->deleteLater();
+ m_Reply = NULL;
+ }
+
+ m_UpdateFile.close();
+
+ if ((m_UpdateFile.size() == 0) ||
+ (error != QNetworkReply::NoError) ||
+ m_Canceled) {
+ if (!m_Canceled) {
+ reportError(tr("Download failed: %1").arg(error));
+ }
+ m_UpdateFile.remove();
+ return;
+ }
+
+ qDebug("download: %s", m_UpdateFile.fileName().toUtf8().constData());
+
+ try {
+ installUpdate();
+ } catch (const std::exception &e) {
+ reportError(tr("Failed to install update: %1").arg(e.what()));
+ }
+}
+
+
+void SelfUpdater::downloadCancel()
+{
+ m_Canceled = true;
+}
+
+
+void SelfUpdater::installUpdate()
+{
+ const QString mopath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()));
+
+ QString backupPath = mopath.mid(0).append("/update_backup");
+ QDir().mkdir(backupPath);
+
+ // rename files that are currently open so we can unpack the update
+ if (!m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(m_UpdateFile.fileName())).c_str(),
+ new MethodCallback<SelfUpdater, void, LPSTR>(this, &SelfUpdater::queryPassword))) {
+ throw MyException(tr("failed to open archive \"%1\": %2")
+ .arg(m_UpdateFile.fileName())
+ .arg(InstallationManager::getErrorString(m_CurrentArchive->getLastError())));
+ }
+
+ // move all files contained in the archive out of the way,
+ // otherwise we can't overwrite everything
+ FileData* const *data;
+ size_t size;
+ m_CurrentArchive->getFileList(data, size);
+
+ for (size_t i = 0; i < size; ++i) {
+ QString outputName = ToQString(data[i]->getFileName());
+ if (outputName.startsWith("ModOrganizer\\", Qt::CaseInsensitive)) {
+ outputName = outputName.mid(13);
+ data[i]->setOutputFileName(ToWString(outputName).c_str());
+ } else if (outputName == "ModOrganizer") {
+ data[i]->setSkip(true);
+ }
+ QFile file(mopath.mid(0).append("/").append(outputName));
+ if (file.exists()) {
+ file.rename(backupPath.mid(0).append("/").append(outputName));
+ }
+ }
+
+ // now unpack the archive into the mo directory
+ if (!m_CurrentArchive->extract(GameInfo::instance().getOrganizerDirectory().c_str(),
+ new MethodCallback<SelfUpdater, void, float>(this, &SelfUpdater::updateProgress),
+ new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::updateProgressFile),
+ new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::report7ZipError))) {
+ throw std::runtime_error("extracting failed");
+ }
+
+ m_CurrentArchive->close();
+
+ m_UpdateFile.remove();
+
+ QMessageBox::information(m_Parent, tr("Update"), tr("Update installed, Mod Organizer will now be restarted."));
+
+ QProcess newProcess;
+ if (QFile::exists(mopath.mid(0).append("/ModOrganizer.exe"))) {
+ newProcess.startDetached(mopath.mid(0).append("/ModOrganizer.exe"), QStringList("update"));
+ } else {
+ newProcess.startDetached(mopath.mid(0).append("/ModOrganiser.exe"), QStringList("update"));
+ }
+ emit restart();
+}
+
+void SelfUpdater::queryPassword(LPSTR)
+{
+ // nop
+}
+
+void SelfUpdater::updateProgress(float)
+{
+ // nop
+}
+
+void SelfUpdater::updateProgressFile(LPCWSTR)
+{
+ // nop
+}
+
+void SelfUpdater::report7ZipError(LPCWSTR errorMessage)
+{
+ QMessageBox::critical(m_Parent, tr("Error"), ToQString(errorMessage));
+}
+
+
+QString SelfUpdater::retrieveNews(const QString &description)
+{
+ QStringList temp = description.split("[s][/s]");
+ if (temp.length() < 2) {
+ return QString();
+ } else {
+ return temp.at(1);
+ }
+}
+
+
+void SelfUpdater::nxmDescriptionAvailable(int, QVariant, QVariant resultData, int requestID)
+{
+ if (requestID == m_UpdateRequestID) {
+ m_UpdateRequestID = -1;
+
+ QVariantMap result = resultData.toMap();
+ QString motd = retrieveNews(result["description"].toString()).trimmed();
+ if (motd.length() != 0) {
+ emit motdAvailable(motd);
+ }
+
+ m_NewestVersion = result["version"].toString();
+ if (m_NewestVersion.isEmpty()) {
+ QTimer::singleShot(5000, this, SLOT(testForUpdate()));
+ }
+
+ VersionInfo currentVersion(m_MOVersion);
+ VersionInfo newestVersion(m_NewestVersion);
+
+ if (!m_NewestVersion.isEmpty() && (currentVersion < newestVersion)) {
+ emit updateAvailable();
+ } else if (newestVersion < currentVersion) {
+ qDebug("this version is newer than the current version on nexus (%s vs %s)",
+ currentVersion.canonicalString().toUtf8().constData(),
+ newestVersion.canonicalString().toUtf8().constData());
+ }
+ }
+}
+
+
+void SelfUpdater::nxmFilesAvailable(int, QVariant userData, QVariant resultData, int requestID)
+{
+ if (requestID != m_UpdateRequestID) {
+ return;
+ }
+ QString version = userData.toString();
+
+ m_UpdateRequestID = -1;
+
+ if (!resultData.canConvert<QVariantList>()) {
+ qCritical("invalid files result: %s", resultData.toString().toUtf8().constData());
+ reportError(tr("Failed to parse response. Please report this as a bug and include the file mo_interface.log."));
+ return;
+ }
+
+ QVariantList result = resultData.toList();
+
+ QRegExp updateExpList(QString("updates version ([0-9., ]*) to %1").arg(version));
+ QRegExp updateExpRange(QString("updates version ([0-9.]*) - ([0-9.]*) to %1").arg(version));
+ int updateFileID = -1;
+ QString updateFileName;
+ int mainFileID = -1;
+ QString mainFileName;
+ int mainFileSize = 0;
+
+ foreach(QVariant file, result) {
+ QVariantMap fileInfo = file.toMap();
+ if (!fileInfo["uri"].toString().endsWith(".7z")) {
+ continue;
+ }
+
+ if (fileInfo["version"].toString() == version) {
+ if (fileInfo["category_id"].toInt() == 2) {
+ QString description = fileInfo["description"].toString();
+ // update
+ if (updateExpList.indexIn(description) != -1) {
+ // there is an update for the newest version of MO, but does
+ // it apply to the current version?
+ QStringList supportedVersions = updateExpList.cap(1).split(QRegExp(",[ ]*"), QString::SkipEmptyParts);
+ if (supportedVersions.contains(m_MOVersion.canonicalString())) {
+ updateFileID = fileInfo["id"].toInt();
+ updateFileName = fileInfo["uri"].toString();
+ } else {
+ qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData());
+ }
+ } else if (updateExpRange.indexIn(description) != -1) {
+ VersionInfo rangeLowEnd(updateExpRange.cap(1));
+ VersionInfo rangeHighEnd(updateExpRange.cap(2));
+ if ((rangeLowEnd <= m_MOVersion) &&
+ (m_MOVersion <= rangeHighEnd)) {
+ updateFileID = fileInfo["id"].toInt();
+ updateFileName = fileInfo["uri"].toString();
+ break;
+ } else {
+ qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData());
+ }
+ } else {
+ qWarning("invalid update description: %s",
+ description.toUtf8().constData());
+ }
+ } else if (fileInfo["category_id"].toInt() == 1) {
+ mainFileID = fileInfo["id"].toInt();
+ mainFileName = fileInfo["uri"].toString();
+ mainFileSize = fileInfo["size"].toInt();
+ }
+ }
+ }
+
+ if (updateFileID != -1) {
+ qDebug("update available: %d", updateFileID);
+ m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
+ updateFileID, this, updateFileName,
+ ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ } else if (mainFileID != -1) {
+ qDebug("full download required: %d", mainFileID);
+ if (QMessageBox::question(m_Parent, tr("Update"),
+ tr("No incremental update available for this version, "
+ "the complete package needs to be downloaded (%1 kB)").arg(mainFileSize),
+ QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
+ m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
+ mainFileID, this, mainFileName,
+ ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ }
+ } else {
+ qCritical("no file for update found");
+ MessageDialog::showMessage(tr("no file for update found. Please update manually."), m_Parent);
+ m_Progress.hide();
+ }
+}
+
+
+void SelfUpdater::nxmRequestFailed(int, QVariant, int requestID, const QString &errorMessage)
+{
+ if (requestID == m_UpdateRequestID) {
+ m_UpdateRequestID = -1;
+ if (m_Attempts > 0) {
+ QTimer::singleShot(60000, this, SLOT(testForUpdate()));
+ --m_Attempts;
+ } else {
+ MessageDialog::showMessage(tr("Failed to retrieve update information: %1").arg(errorMessage), m_Parent);
+ }
+ }
+}
+
+
+void SelfUpdater::nxmDownloadURLsAvailable(int, int, QVariant userData, QVariant resultData, int requestID)
+{
+ if (requestID == m_UpdateRequestID) {
+ m_UpdateRequestID = -1;
+ QVariantList serverList = resultData.toList();
+ if (serverList.count() != 0) {
+ qSort(serverList.begin(), serverList.end(), DownloadManager::ServerByPreference);
+
+ QVariantMap dlServer = serverList.first().toMap();
+
+ download(dlServer["URI"].toString(), userData.toString());
+ } else {
+ MessageDialog::showMessage(tr("No download server available. Please try again later."), m_Parent);
+ m_Progress.hide();
+ }
+ }
+}
+
diff --git a/src/selfupdater.h b/src/selfupdater.h new file mode 100644 index 00000000..3a92b769 --- /dev/null +++ b/src/selfupdater.h @@ -0,0 +1,145 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SELFUPDATER_H
+#define SELFUPDATER_H
+
+
+#include "nexusinterface.h"
+#include <archive.h>
+#include <versioninfo.h>
+
+#include <QObject>
+#include <QNetworkReply>
+#include <QFile>
+#include <QProgressDialog>
+
+
+/**
+ * @brief manages updates for Mod Organizer itself
+ * This class is used to update the Mod Organizer
+ * The process looks like this:
+ * 1. call testForUpdate() to determine is available
+ * 2. if the updateAvailable() signal is received, allow the user to start the update
+ * 3. if the user start the update, call startUpdate()
+ * 4. startUpdate() will first query a list of files, try to determine if there is an
+ * incremental update. If not, the user will have to confirm the download of a full download.
+ * Once the correct file is selected, it is downloaded.
+ * 5. before the downloaded file is extracted, existing files that are going to be replaced are
+ * moved to "update_backup" on because files that are currently open can't be replaced.
+ * 6. the update is extracted and then deleted
+ * 7. finally, a restart is requested via signal.
+ * 8. at restart, Mod Organizer will remove the update_backup directory since none of the files
+ * should now be open
+ *
+ * @todo use NexusBridge
+ **/
+class SelfUpdater : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param nexusInterface interface to query information from nexus
+ * @param parent parent widget
+ * @todo passing the nexus interface is unneccessary
+ **/
+ SelfUpdater(NexusInterface *nexusInterface, QWidget *parent);
+ ~SelfUpdater();
+
+ /**
+ * @brief start the update process
+ * @note this should not be called if there is no update available
+ **/
+ void startUpdate();
+
+ /**
+ * @return current version of Mod Organizer
+ **/
+ VersionInfo getVersion() const { return m_MOVersion; }
+
+public slots:
+
+ /**
+ * @brief request information about the current version
+ **/
+ void testForUpdate();
+
+ void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
+ void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorMessage);
+ void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
+
+signals:
+
+ /**
+ * @brief emitted if a restart of the client is necessary to complete the update
+ **/
+ void restart();
+
+ /**
+ * @brief emitted if an update is available
+ **/
+ void updateAvailable();
+
+ /**
+ * @brief emitted if a message of the day was received
+ **/
+ void motdAvailable(const QString &motd);
+
+private:
+
+ void download(const QString &downloadLink, const QString &fileName);
+ void installUpdate();
+ void queryPassword(LPSTR password);
+ void updateProgress(float percentage);
+ void updateProgressFile(LPCWSTR fileName);
+ void report7ZipError(LPCWSTR errorMessage);
+ QString retrieveNews(const QString &description);
+
+private slots:
+
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void downloadReadyRead();
+ void downloadFinished();
+ void downloadCancel();
+
+private:
+
+ QWidget *m_Parent;
+ VersionInfo m_MOVersion;
+ NexusInterface *m_Interface;
+ int m_UpdateRequestID;
+ QString m_NewestVersion;
+ QFile m_UpdateFile;
+ QNetworkReply *m_Reply;
+ QProgressDialog m_Progress;
+ bool m_Canceled;
+ int m_Attempts;
+
+ Archive *m_CurrentArchive;
+
+};
+
+
+#endif // SELFUPDATER_H
diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 00000000..7c12e815 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,510 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "settings.h"
+
+#include "settingsdialog.h"
+#include "utility.h"
+#include "helper.h"
+#include <gameinfo.h>
+#include <appconfig.h>
+#include <utility.h>
+
+#include <QCheckBox>
+#include <QLineEdit>
+#include <QDirIterator>
+#include <QRegExp>
+#include <QCoreApplication>
+#include <QMessageBox>
+
+
+static const unsigned char Key2[20] = { 0x99, 0xb8, 0x76, 0x42, 0x3e, 0xc1, 0x60, 0xa4, 0x5b, 0x01,
+ 0xdb, 0xf8, 0x43, 0x3a, 0xb7, 0xb6, 0x98, 0xd4, 0x7d, 0xa2 };
+
+Settings *Settings::s_Instance = NULL;
+
+
+Settings::Settings()
+ : m_Settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat)
+{
+ if (s_Instance != NULL) {
+ throw std::runtime_error("second instance of \"Settings\" created");
+ } else {
+ s_Instance = this;
+ }
+}
+
+
+Settings::~Settings()
+{
+ s_Instance = NULL;
+}
+
+
+Settings &Settings::instance()
+{
+ if (s_Instance == NULL) {
+ throw std::runtime_error("no instance of \"Settings\"");
+ }
+ return *s_Instance;
+}
+
+void Settings::clearPlugins()
+{
+ m_Plugins.clear();
+ m_PluginSettings.clear();
+}
+
+void Settings::registerPlugin(IPlugin *plugin)
+{
+ m_Plugins.push_back(plugin);
+ foreach (const PluginSetting &setting, plugin->settings()) {
+ QVariant temp = m_Settings.value("Plugins/" + plugin->name() + "/" + setting.key, setting.defaultValue);
+ if (!temp.convert(setting.defaultValue.type())) {
+ qWarning("failed to interpret \"%s\" as correct type for \"%s\" in plugin \"%s\", using default",
+ qPrintable(temp.toString()), qPrintable(setting.key), qPrintable(plugin->name()));
+ temp = setting.defaultValue;
+ }
+ m_PluginSettings[plugin->name()][setting.key] = temp;
+ }
+}
+
+
+QString Settings::obfuscate(const QString &password) const
+{
+ QByteArray temp = password.toUtf8();
+
+ QByteArray buffer;
+ for (int i = 0; i < temp.length(); ++i) {
+ buffer.append(temp.at(i) ^ Key2[i % 20]);
+ }
+ return buffer.toBase64();
+}
+
+
+QString Settings::deObfuscate(const QString &password) const
+{
+ QByteArray temp(QByteArray::fromBase64(password.toUtf8()));
+
+ QByteArray buffer;
+ for (int i = 0; i < temp.length(); ++i) {
+ buffer.append(temp.at(i) ^ Key2[i % 20]);
+ }
+ return QString::fromUtf8(buffer.constData());
+}
+
+
+bool Settings::hideUncheckedPlugins() const
+{
+ return m_Settings.value("Settings/hide_unchecked_plugins", false).toBool();
+}
+
+bool Settings::forceEnableCoreFiles() const
+{
+ return m_Settings.value("Settings/force_enable_core_files", true).toBool();
+}
+
+bool Settings::automaticLoginEnabled() const
+{
+ return m_Settings.value("Settings/nexus_login", false).toBool();
+}
+
+QString Settings::getSteamAppID() const
+{
+ return m_Settings.value("Settings/app_id", ToQString(GameInfo::instance().getSteamAPPId())).toString();
+}
+
+QString Settings::getDownloadDirectory() const
+{
+ return QDir::toNativeSeparators(m_Settings.value("Settings/download_directory", ToQString(GameInfo::instance().getDownloadDir())).toString());
+}
+
+QString Settings::getCacheDirectory() const
+{
+ return QDir::toNativeSeparators(m_Settings.value("Settings/cache_directory", ToQString(GameInfo::instance().getCacheDir())).toString());
+}
+
+QString Settings::getModDirectory() const
+{
+ return QDir::toNativeSeparators(m_Settings.value("Settings/mod_directory", ToQString(GameInfo::instance().getModsDir())).toString());
+}
+
+QString Settings::getNMMVersion() const
+{
+ return m_Settings.value("Settings/nmm_version", "0.34.0").toString();
+}
+
+bool Settings::getNexusLogin(QString &username, QString &password) const
+{
+ if (m_Settings.value("Settings/nexus_login", false).toBool()) {
+ username = m_Settings.value("Settings/nexus_username", "").toString();
+ password = deObfuscate(m_Settings.value("Settings/nexus_password", "").toString());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int Settings::logLevel() const
+{
+ return m_Settings.value("Settings/log_level", 0).toInt();
+}
+
+
+void Settings::setNexusLogin(QString username, QString password)
+{
+ m_Settings.setValue("Settings/nexus_login", true);
+ m_Settings.setValue("Settings/nexus_username", username);
+ m_Settings.setValue("Settings/nexus_password", obfuscate(password));
+}
+
+
+LoadMechanism::EMechanism Settings::getLoadMechanism() const
+{
+ switch (m_Settings.value("Settings/load_mechanism").toInt()) {
+ case LoadMechanism::LOAD_MODORGANIZER: return LoadMechanism::LOAD_MODORGANIZER;
+ case LoadMechanism::LOAD_SCRIPTEXTENDER: return LoadMechanism::LOAD_SCRIPTEXTENDER;
+ case LoadMechanism::LOAD_PROXYDLL: return LoadMechanism::LOAD_PROXYDLL;
+ }
+ throw std::runtime_error("invalid load mechanism");
+}
+
+
+void Settings::setupLoadMechanism()
+{
+ m_LoadMechanism.activate(getLoadMechanism());
+}
+
+
+bool Settings::preferIntegratedInstallers()
+{
+ return m_Settings.value("Settings/prefer_integrated_installer").toBool();
+}
+
+
+bool Settings::enableQuickInstaller()
+{
+ return m_Settings.value("Settings/enable_quick_installer").toBool();
+}
+
+
+bool Settings::preferExternalBrowser()
+{
+ return m_Settings.value("Settings/prefer_external_browser").toBool();
+}
+
+
+void Settings::setMotDHash(uint hash)
+{
+ m_Settings.setValue("motd_hash", hash);
+}
+
+uint Settings::getMotDHash() const
+{
+ return m_Settings.value("motd_hash", 0).toUInt();
+}
+
+QVariant Settings::pluginSetting(const QString &pluginName, const QString &key) const
+{
+ auto iterPlugin = m_PluginSettings.find(pluginName);
+ if (iterPlugin == m_PluginSettings.end()) {
+ throw MyException(tr("setting for invalid plugin \"%1\" requested").arg(key));
+ }
+ auto iterSetting = iterPlugin->find(key);
+ if (iterSetting == iterPlugin->end()) {
+ throw MyException(tr("invalid setting \"%1\" requested for plugin \"%2\"").arg(key).arg(pluginName));
+ }
+
+ return *iterSetting;
+}
+
+
+void Settings::addLanguages(QComboBox *languageBox)
+{
+ languageBox->addItem("English", "en_US");
+
+ QDirIterator langIter(QCoreApplication::applicationDirPath() + "/translations", QDir::Files);
+ QString pattern = ToQString(AppConfig::translationPrefix()) + "_([a-z]{2,3}(_[A-Z]{2,2})?).qm";
+ QRegExp exp(pattern);
+ while (langIter.hasNext()) {
+ langIter.next();
+ QString file = langIter.fileName();
+ if (exp.exactMatch(file)) {
+ QString languageCode = exp.cap(1);
+ QLocale locale(languageCode);
+ QString languageString = QLocale::languageToString(locale.language());
+ if (locale.language() == QLocale::Chinese) {
+ if (languageCode == "zh_TW") {
+ languageString = "Chinese (traditional)";
+ } else {
+ languageString = "Chinese (simplified)";
+ }
+ }
+
+ languageBox->addItem(QString("%1").arg(languageString), exp.cap(1));
+ }
+ }
+}
+
+void Settings::addStyles(QComboBox *styleBox)
+{
+ styleBox->addItem("None", "");
+ QDirIterator langIter(QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()), QStringList("*.qss"), QDir::Files);
+ while (langIter.hasNext()) {
+ langIter.next();
+ QString style = langIter.fileName();
+ styleBox->addItem(style, style);
+ }
+}
+
+bool Settings::isNXMHandler(bool *modifyable)
+{
+ QSettings handlerReg("HKEY_CLASSES_ROOT\\nxm\\shell\\open\\command",
+ QSettings::NativeFormat);
+
+ QString currentExe = handlerReg.value("Default", "").toString().toUtf8().constData();
+ QString myExe = QString("\"%1\" ").arg(QDir::toNativeSeparators(QCoreApplication::applicationFilePath())).append("\"%1\"");
+ if (modifyable != NULL) {
+ handlerReg.setValue("Default", currentExe);
+ handlerReg.sync();
+
+ *modifyable = handlerReg.status() == QSettings::NoError;
+ // QSettings::isWritable returns wrong results...
+ }
+ return currentExe == myExe;
+}
+
+
+void Settings::setNXMHandlerActive(bool active, bool writable)
+{
+ QSettings handlerReg("HKEY_CLASSES_ROOT\\nxm\\",
+ QSettings::NativeFormat);
+
+ if (writable) {
+ QString myExe = QString("\"%1\" ").arg(QDir::toNativeSeparators(QCoreApplication::applicationFilePath())).append("\"%1\"");
+ handlerReg.setValue("Default", "URL:NXM Protocol");
+ handlerReg.setValue("URL Protocol", "");
+ handlerReg.setValue("shell/open/command/Default", active ? myExe : "");
+ handlerReg.sync();
+ } else {
+ Helper::setNXMHandler(GameInfo::instance().getOrganizerDirectory(), active);
+ }
+}
+
+
+void Settings::resetDialogs()
+{
+ m_Settings.beginGroup("DialogChoices");
+ QStringList keys = m_Settings.childKeys();
+ foreach (QString key, keys) {
+ m_Settings.remove(key);
+ }
+
+ m_Settings.endGroup();
+}
+
+
+void Settings::query(QWidget *parent)
+{
+ SettingsDialog dialog(parent);
+
+ connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs()));
+
+ QCheckBox *hideUncheckedBox = dialog.findChild<QCheckBox*>("hideUncheckedBox");
+ QCheckBox *forceEnableBox = dialog.findChild<QCheckBox*>("forceEnableBox");
+ QComboBox *mechanismBox = dialog.findChild<QComboBox*>("mechanismBox");
+
+ QCheckBox *loginCheckBox = dialog.findChild<QCheckBox*>("loginCheckBox");
+ QLineEdit *usernameEdit = dialog.findChild<QLineEdit*>("usernameEdit");
+ QLineEdit *passwordEdit = dialog.findChild<QLineEdit*>("passwordEdit");
+
+ QLineEdit *appIDEdit = dialog.findChild<QLineEdit*>("appIDEdit");
+
+ QComboBox *languageBox = dialog.findChild<QComboBox*>("languageBox");
+ QComboBox *styleBox = dialog.findChild<QComboBox*>("styleBox");
+ QComboBox *logLevelBox = dialog.findChild<QComboBox*>("logLevelBox");
+ QCheckBox *handleNXMBox = dialog.findChild<QCheckBox*>("handleNXMBox");
+
+ QLineEdit *downloadDirEdit = dialog.findChild<QLineEdit*>("downloadDirEdit");
+ QLineEdit *modDirEdit = dialog.findChild<QLineEdit*>("modDirEdit");
+ QLineEdit *cacheDirEdit = dialog.findChild<QLineEdit*>("cacheDirEdit");
+
+ QCheckBox *preferIntegratedCheckBox = dialog.findChild<QCheckBox*>("preferIntegratedBox");
+ QCheckBox *preferExternalBox = dialog.findChild<QCheckBox*>("preferExternalBox");
+ QCheckBox *quickInstallerBox = dialog.findChild<QCheckBox*>("quickInstallerBox");
+ QLineEdit *nmmVersionEdit = dialog.findChild<QLineEdit*>("nmmVersionEdit");
+
+ QListWidget *pluginsList = dialog.findChild<QListWidget*>("pluginsList");
+
+ //
+ // set up current settings
+ //
+ LoadMechanism::EMechanism mechanismID = getLoadMechanism();
+ int index = 0;
+
+ if (m_LoadMechanism.isDirectLoadingSupported()) {
+ mechanismBox->addItem(QObject::tr("Mod Organizer"), LoadMechanism::LOAD_MODORGANIZER);
+ if (mechanismID == LoadMechanism::LOAD_MODORGANIZER) {
+ index = mechanismBox->count() - 1;
+ }
+ }
+
+ if (m_LoadMechanism.isScriptExtenderSupported()) {
+ mechanismBox->addItem(QObject::tr("Script Extender"), LoadMechanism::LOAD_SCRIPTEXTENDER);
+ if (mechanismID == LoadMechanism::LOAD_SCRIPTEXTENDER) {
+ index = mechanismBox->count() - 1;
+ }
+ }
+
+ if (m_LoadMechanism.isProxyDLLSupported()) {
+ mechanismBox->addItem(QObject::tr("Proxy DLL"), LoadMechanism::LOAD_PROXYDLL);
+ if (mechanismID == LoadMechanism::LOAD_PROXYDLL) {
+ index = mechanismBox->count() - 1;
+ }
+ }
+
+ mechanismBox->setCurrentIndex(index);
+
+ {
+ addLanguages(languageBox);
+ int currentID = languageBox->findData(m_Settings.value("Settings/language", QLocale::system().name()).toString());
+ if (currentID != -1) {
+ languageBox->setCurrentIndex(currentID);
+ }
+ }
+
+ {
+ addStyles(styleBox);
+ int currentID = styleBox->findData(m_Settings.value("Settings/style", "").toString());
+ if (currentID != -1) {
+ styleBox->setCurrentIndex(currentID);
+ }
+ }
+
+ hideUncheckedBox->setChecked(hideUncheckedPlugins());
+ forceEnableBox->setChecked(forceEnableCoreFiles());
+
+ appIDEdit->setText(getSteamAppID());
+
+ if (automaticLoginEnabled()) {
+ loginCheckBox->setChecked(true);
+ usernameEdit->setText(m_Settings.value("Settings/nexus_username", "").toString());
+ passwordEdit->setText(deObfuscate(m_Settings.value("Settings/nexus_password", "").toString()));
+ }
+
+ bool registryWritable = false;
+ bool nxmHandler = isNXMHandler(®istryWritable);
+ handleNXMBox->setChecked(nxmHandler);
+ if (!registryWritable) {
+ handleNXMBox->setIcon(QIcon(":/MO/gui/locked"));
+ handleNXMBox->setToolTip(tr("Administrative rights required to change this."));
+ }
+
+ downloadDirEdit->setText(getDownloadDirectory());
+ modDirEdit->setText(getModDirectory());
+ cacheDirEdit->setText(getCacheDirectory());
+ preferIntegratedCheckBox->setChecked(m_Settings.value("Settings/prefer_integrated_installer", false).toBool());
+ preferExternalBox->setChecked(m_Settings.value("Settings/prefer_external_browser", false).toBool());
+ quickInstallerBox->setChecked(m_Settings.value("Settings/enable_quick_installer", true).toBool());
+ nmmVersionEdit->setText(m_Settings.value("Settings/nmm_version", "0.33.1").toString());
+ logLevelBox->setCurrentIndex(logLevel());
+
+ foreach (IPlugin *plugin, m_Plugins) {
+ QListWidgetItem *listItem = new QListWidgetItem(plugin->name(), pluginsList);
+ listItem->setData(Qt::UserRole, QVariant::fromValue((void*)plugin));
+ listItem->setData(Qt::UserRole + 1, m_PluginSettings[plugin->name()]);
+ pluginsList->addItem(listItem);
+ }
+
+ if (dialog.exec() == QDialog::Accepted) {
+ //
+ // transfer modified settings to configuration file
+ //
+
+ m_Settings.setValue("Settings/hide_unchecked_plugins", hideUncheckedBox->checkState() ? true : false);
+ m_Settings.setValue("Settings/force_enable_core_files", forceEnableBox->checkState() ? true : false);
+ m_Settings.setValue("Settings/load_mechanism", mechanismBox->itemData(mechanismBox->currentIndex()).toInt());
+ if (QDir(downloadDirEdit->text()).exists()) {
+ m_Settings.setValue("Settings/download_directory", QDir::toNativeSeparators(downloadDirEdit->text()));
+ }
+ if (!QDir(cacheDirEdit->text()).exists()) {
+ QDir().mkpath(cacheDirEdit->text());
+ }
+ m_Settings.setValue("Settings/cache_directory", QDir::toNativeSeparators(cacheDirEdit->text()));
+ if (QDir(modDirEdit->text()).exists()) {
+ if ((QDir::fromNativeSeparators(modDirEdit->text()) != QDir::fromNativeSeparators(getModDirectory())) &&
+ (QMessageBox::question(NULL, tr("Confirm"), tr("Changing the mod directory affects all your profiles! "
+ "Mods not present (or named differently) in the new location will be disabled in all profiles. "
+ "There is no way to undo this unless you backed up your profiles manually. Proceed?"),
+ QMessageBox::Yes | QMessageBox::No))) {
+ m_Settings.setValue("Settings/mod_directory", QDir::toNativeSeparators(modDirEdit->text()));
+ }
+ }
+ QString oldLanguage = m_Settings.value("Settings/language", "en_US").toString();
+ QString newLanguage = languageBox->itemData(languageBox->currentIndex()).toString();
+ if (newLanguage != oldLanguage) {
+ m_Settings.setValue("Settings/language", newLanguage);
+ emit languageChanged(newLanguage);
+ }
+
+ QString oldStyle = m_Settings.value("Settings/style", "").toString();
+ QString newStyle = styleBox->itemData(styleBox->currentIndex()).toString();
+ if (oldStyle != newStyle) {
+ m_Settings.setValue("Settings/style", newStyle);
+ emit styleChanged(newStyle);
+ }
+
+ m_Settings.setValue("Settings/log_level", logLevelBox->currentIndex());
+
+ if (appIDEdit->text() != ToQString(GameInfo::instance().getSteamAPPId())) {
+ m_Settings.setValue("Settings/app_id", appIDEdit->text());
+ } else {
+ m_Settings.remove("Settings/app_id");
+ }
+ if (loginCheckBox->isChecked()) {
+ m_Settings.setValue("Settings/nexus_login", true);
+ m_Settings.setValue("Settings/nexus_username", usernameEdit->text());
+ m_Settings.setValue("Settings/nexus_password", obfuscate(passwordEdit->text()));
+ } else {
+ m_Settings.setValue("Settings/nexus_login", false);
+ m_Settings.remove("Settings/nexus_username");
+ m_Settings.remove("Settings/nexus_password");
+ }
+ if (nxmHandler != handleNXMBox->isChecked()) {
+ setNXMHandlerActive(handleNXMBox->isChecked(), registryWritable);
+ }
+ m_Settings.setValue("Settings/prefer_integrated_installer", preferIntegratedCheckBox->isChecked());
+ m_Settings.setValue("Settings/prefer_external_browser", preferExternalBox->isChecked());
+ m_Settings.setValue("Settings/enable_quick_installer", quickInstallerBox->isChecked());
+
+ m_Settings.setValue("Settings/nmm_version", nmmVersionEdit->text());
+
+ // transfer plugin settings to in-memory structure
+ for (int i = 0; i < pluginsList->count(); ++i) {
+ QListWidgetItem *item = pluginsList->item(i);
+ m_PluginSettings[item->text()] = item->data(Qt::UserRole + 1).toMap();
+ }
+ // store plugin settings on disc
+ for (auto iterPlugins = m_PluginSettings.begin(); iterPlugins != m_PluginSettings.end(); ++iterPlugins) {
+ for (auto iterSettings = iterPlugins->begin(); iterSettings != iterPlugins->end(); ++iterSettings) {
+ m_Settings.setValue("Plugins/" + iterPlugins.key() + "/" + iterSettings.key(), iterSettings.value());
+ }
+ }
+ }
+}
diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 00000000..d02de1a6 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,223 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef WORKAROUNDS_H
+#define WORKAROUNDS_H
+
+#include "loadmechanism.h"
+
+#include <iplugin.h>
+
+#include <QSettings>
+#include <QListWidget>
+#include <QComboBox>
+
+
+/**
+ * manages the settings for Mod Organizer. The settings are not cached
+ * inside the class but read/written directly from/to disc
+ **/
+class Settings : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ **/
+ Settings();
+
+ virtual ~Settings();
+
+ static Settings &instance();
+
+ /**
+ * unregister all plugins from settings
+ */
+ void clearPlugins();
+
+ /**
+ * @brief register plugin to be configurable
+ * @param plugin the plugin to register
+ */
+ void registerPlugin(IPlugin *plugin);
+
+ /**
+ * displays a SettingsDialog that allows the user to change settings. If the
+ * user accepts the changes, the settings are immediately written
+ **/
+ void query(QWidget *parent);
+
+ /**
+ * set up the settings for the specified plugins
+ **/
+ void addPluginSettings(const std::vector<IPlugin*> &plugins);
+
+ /**
+ * @return true if the user wants unchecked plugins (esp, esm) should be hidden from
+ * the virtual dat adirectory
+ **/
+ bool hideUncheckedPlugins() const;
+
+ /**
+ * @return true if files of the core game are forced-enabled so the user can't accidentally disable them
+ */
+ bool forceEnableCoreFiles() const;
+
+ /**
+ * the steam appid is assigned by the steam platform to each product sold there.
+ * The appid may differ between different versions of a game so it may be impossible
+ * for Mod Organizer to automatically recognize it, though usually it does
+ * @return the steam appid for the game
+ **/
+ QString getSteamAppID() const;
+
+ /**
+ * retrieve the directory where downloads are stored (with native separators)
+ **/
+ QString getDownloadDirectory() const;
+
+ /**
+ * retrieve the directory where mods are stored (with native separators)
+ **/
+ QString getModDirectory() const;
+
+ /**
+ * returns the version of nmm to impersonate when connecting to nexus
+ **/
+ QString getNMMVersion() const;
+
+ /**
+ * retrieve the directory where the web cache is stored (with native separators)
+ **/
+ QString getCacheDirectory() const;
+
+ /**
+ * @return true if the user has set up automatic login to nexus
+ **/
+ bool automaticLoginEnabled() const;
+
+ /**
+ * @brief retrieve the login information for nexus
+ *
+ * @param username (out) receives the user name for nexus
+ * @param password (out) received the password for nexus
+ * @return true if automatic login is active, false otherwise
+ **/
+ bool getNexusLogin(QString &username, QString &password) const;
+
+ /**
+ * @return the configured log level
+ */
+ int logLevel() const;
+
+ /**
+ * @brief set the nexus login information
+ *
+ * @param username username
+ * @param password password
+ */
+ void setNexusLogin(QString username, QString password);
+
+ /**
+ * @return the load mechanism to be used
+ **/
+ LoadMechanism::EMechanism getLoadMechanism() const;
+
+ /**
+ * @brief activate the load mechanism selected by the user
+ **/
+ void setupLoadMechanism();
+
+ /**
+ * @return true if the user prefers the integrated installer over external variants
+ **/
+ bool preferIntegratedInstallers();
+
+ /**
+ * @return true if the user prefers to use an external browser over the integrated one
+ **/
+ bool preferExternalBrowser();
+
+ /**
+ * @return true if the user has enabled the quick installer (default true)
+ **/
+ bool enableQuickInstaller();
+
+ /**
+ * @brief sets the new motd hash
+ **/
+ void setMotDHash(uint hash);
+
+ /**
+ * @return hash of the last displayed message of the day
+ **/
+ uint getMotDHash() const;
+
+ /**
+ * @brief allows direct access to the wrapped QSettings object
+ * @return the wrapped QSettings object
+ */
+ QSettings &directInterface() { return m_Settings; }
+
+ /**
+ * @brief retrieve a setting for one of the installed plugins
+ * @param pluginName name of the plugin
+ * @param key name of the setting to retrieve
+ * @return the requested value as a QVariant
+ * @throws an exception is thrown if this setting doesn't exist
+ */
+ QVariant pluginSetting(const QString &pluginName, const QString &key) const;
+
+private:
+
+ QString obfuscate(const QString &password) const;
+ QString deObfuscate(const QString &password) const;
+
+ void addLanguages(QComboBox *languageBox);
+ void addStyles(QComboBox *styleBox);
+ bool isNXMHandler(bool *modifyable);
+ void setNXMHandlerActive(bool active, bool writable);
+
+private slots:
+
+ void resetDialogs();
+
+signals:
+
+ void languageChanged(const QString &newLanguage);
+ void styleChanged(const QString &newStyle);
+
+private:
+
+ static Settings *s_Instance;
+
+ QSettings m_Settings;
+
+ LoadMechanism m_LoadMechanism;
+
+ std::vector<IPlugin*> m_Plugins;
+
+ QMap<QString, QMap<QString, QVariant> > m_PluginSettings;
+
+};
+
+#endif // WORKAROUNDS_H
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp new file mode 100644 index 00000000..855acdf1 --- /dev/null +++ b/src/settingsdialog.cpp @@ -0,0 +1,149 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "settingsdialog.h"
+#include "ui_settingsdialog.h"
+#include "categoriesdialog.h"
+#include "helper.h"
+#include <gameinfo.h>
+#include <QDirIterator>
+#include <QFileDialog>
+#include <QMessageBox>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : TutorableDialog("SettingsDialog", parent), ui(new Ui::SettingsDialog)
+{
+ ui->setupUi(this);
+}
+
+SettingsDialog::~SettingsDialog()
+{
+ delete ui;
+}
+
+void SettingsDialog::addPlugins(const std::vector<IPlugin*> &plugins)
+{
+ foreach (IPlugin *plugin, plugins) {
+ ui->pluginsList->addItem(plugin->name());
+ }
+}
+
+void SettingsDialog::accept()
+{
+ storeSettings(ui->pluginsList->currentItem());
+ TutorableDialog::accept();
+}
+
+
+void SettingsDialog::on_loginCheckBox_toggled(bool checked)
+{
+ QLineEdit *usernameEdit = findChild<QLineEdit*>("usernameEdit");
+ QLineEdit *passwordEdit = findChild<QLineEdit*>("passwordEdit");
+ if (checked) {
+ passwordEdit->setEnabled(true);
+ usernameEdit->setEnabled(true);
+ } else {
+ passwordEdit->setEnabled(false);
+ usernameEdit->setEnabled(false);
+ }
+}
+
+void SettingsDialog::on_categoriesBtn_clicked()
+{
+ CategoriesDialog dialog(this);
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.commitChanges();
+ }
+}
+
+void SettingsDialog::on_bsaDateBtn_clicked()
+{
+ Helper::backdateBSAs(GameInfo::instance().getOrganizerDirectory(), GameInfo::instance().getGameDirectory().append(L"\\data"));
+}
+
+void SettingsDialog::on_browseDownloadDirBtn_clicked()
+{
+ QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), ui->downloadDirEdit->text());
+ if (!temp.isEmpty()) {
+ ui->downloadDirEdit->setText(temp);
+ }
+}
+
+void SettingsDialog::on_browseModDirBtn_clicked()
+{
+ QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->downloadDirEdit->text());
+ if (!temp.isEmpty()) {
+ ui->modDirEdit->setText(temp);
+ }
+}
+
+void SettingsDialog::on_browseCacheDirBtn_clicked()
+{
+ QString temp = QFileDialog::getExistingDirectory(this, tr("Select cache directory"), ui->cacheDirEdit->text());
+ if (!temp.isEmpty()) {
+ ui->cacheDirEdit->setText(temp);
+ }
+}
+
+void SettingsDialog::on_resetDialogsButton_clicked()
+{
+ if (QMessageBox::question(this, tr("Confirm?"),
+ tr("This will make all dialogs show up again where you checked the \"Remember selection\"-box. Continue?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ emit resetDialogs();
+ }
+}
+
+void SettingsDialog::storeSettings(QListWidgetItem *pluginItem)
+{
+ if (pluginItem != NULL) {
+ QMap<QString, QVariant> settings = pluginItem->data(Qt::UserRole + 1).toMap();
+
+ for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) {
+ const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i);
+ settings[item->text(0)] = item->data(1, Qt::DisplayRole);
+ }
+
+ pluginItem->setData(Qt::UserRole + 1, settings);
+ }
+}
+
+void SettingsDialog::on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
+{
+ storeSettings(previous);
+
+ ui->pluginSettingsList->clear();
+ IPlugin *plugin = static_cast<IPlugin*>(current->data(Qt::UserRole).value<void*>());
+ ui->authorLabel->setText(plugin->author());
+ ui->versionLabel->setText(plugin->version().canonicalString());
+ ui->descriptionLabel->setText(plugin->description());
+
+ QMap<QString, QVariant> settings = current->data(Qt::UserRole + 1).toMap();
+ ui->pluginSettingsList->setEnabled(settings.count() != 0);
+ for (auto iter = settings.begin(); iter != settings.end(); ++iter) {
+ QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key()));
+ newItem->setData(1, Qt::DisplayRole, *iter);
+ newItem->setData(1, Qt::EditRole, *iter);
+ newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
+ ui->pluginSettingsList->addTopLevelItem(newItem);
+ }
+}
diff --git a/src/settingsdialog.h b/src/settingsdialog.h new file mode 100644 index 00000000..5cb3470a --- /dev/null +++ b/src/settingsdialog.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef WORKAROUNDDIALOG_H
+#define WORKAROUNDDIALOG_H
+
+#include "tutorabledialog.h"
+#include <iplugin.h>
+#include <QDialog>
+#include <QListWidgetItem>
+
+namespace Ui {
+ class SettingsDialog;
+}
+
+/**
+ * dialog used to change settings for Mod Organizer. On top of the
+ * settings managed by the "Settings" class, this offers a button to open the
+ * CategoriesDialog
+ **/
+class SettingsDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsDialog(QWidget *parent = 0);
+ ~SettingsDialog();
+
+ void addPlugins(const std::vector<IPlugin*> &plugins);
+
+public slots:
+
+ virtual void accept();
+
+signals:
+
+ void resetDialogs();
+
+private:
+
+ void storeSettings(QListWidgetItem *pluginItem);
+
+private slots:
+ void on_loginCheckBox_toggled(bool checked);
+
+ void on_categoriesBtn_clicked();
+
+ void on_bsaDateBtn_clicked();
+
+ void on_browseDownloadDirBtn_clicked();
+
+ void on_browseModDirBtn_clicked();
+
+ void on_browseCacheDirBtn_clicked();
+
+ void on_resetDialogsButton_clicked();
+
+ void on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+
+private:
+ Ui::SettingsDialog *ui;
+};
+
+#endif // WORKAROUNDDIALOG_H
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui new file mode 100644 index 00000000..cd8a5ffd --- /dev/null +++ b/src/settingsdialog.ui @@ -0,0 +1,785 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>586</width>
+ <height>462</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="generalTab">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Language</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="languageBox">
+ <property name="toolTip">
+ <string>The display language</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>Style</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="styleBox">
+ <property name="toolTip">
+ <string>graphical style</string>
+ </property>
+ <property name="whatsThis">
+ <string>graphical style of the MO user interface</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label_12">
+ <property name="text">
+ <string>Log Level</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="logLevelBox">
+ <property name="toolTip">
+ <string>Decides the amount of data printed to "ModOrganizer.log"</string>
+ </property>
+ <property name="whatsThis">
+ <string>Decides the amount of data printed to "ModOrganizer.log".
+"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty.</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>Debug</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Info</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Error</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Advanced</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="downloadDirEdit">
+ <property name="toolTip">
+ <string>Directory where downloads are stored.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Directory where downloads are stored.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="browseDownloadDirBtn">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Mod Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="modDirEdit">
+ <property name="toolTip">
+ <string>Directory where mods are stored.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name).</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="browseModDirBtn">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Download Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Cache Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="cacheDirEdit"/>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="browseCacheDirBtn">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="resetDialogsButton">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Reset stored information from dialogs.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This will make all dialogs show up again where you checked the "Remember selection"-box.</string>
+ </property>
+ <property name="text">
+ <string>Reset Dialogs</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="categoriesBtn">
+ <property name="toolTip">
+ <string>Modify the categories available to arrange your mods.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Modify the categories available to arrange your mods.</string>
+ </property>
+ <property name="text">
+ <string>Configure Mod Categories</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="instalerTab">
+ <attribute name="title">
+ <string>Installer</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <widget class="QCheckBox" name="preferIntegratedBox">
+ <property name="toolTip">
+ <string>Choose the integrated fomod installer over the external one wherever possible.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Use the integrated fomod installer if possible. This installer is only able to handle archives scripted using an xml-file (that's maybe half the fomods out there), other files are still installed using the external installer if it's available.</string>
+ </property>
+ <property name="text">
+ <string>Prefer integrated fomod installer</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="quickInstallerBox">
+ <property name="toolTip">
+ <string>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Use a very simple installation dialog if MO recognizes the structure of the installation archive. If you prefer your life complicated, uncheck this box.</string>
+ </property>
+ <property name="text">
+ <string>Enable "Quick Installer"</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="nexusTab">
+ <attribute name="title">
+ <string>Nexus</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QGroupBox" name="nexusBox">
+ <property name="toolTip">
+ <string>Allows automatic log-in when the Nexus-Page for the game is clicked.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Allows automatic log-in when the Nexus-Page for the game is clicked. Please note that the obfuscation with which the password is stored in modorganizer.ini is not very strong. If you're worried someone might steal your password, don't store it here.</span></p></body></html></string>
+ </property>
+ <property name="title">
+ <string>Nexus</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="loginCheckBox">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="whatsThis">
+ <string>If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic.</string>
+ </property>
+ <property name="text">
+ <string>Automatically Log-In to Nexus</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="usernameEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="passwordEdit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="handleNXMBox">
+ <property name="toolTip">
+ <string>Sets up MO as the global handler for NXM links.</string>
+ </property>
+ <property name="whatsThis">
+ <string>NXM Links are the green Download-buttons on Nexus. If this is checked, MO will be set up to handle those links.
+On some systems this will require administrative rights.</string>
+ </property>
+ <property name="text">
+ <string>Handle NXM Links</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="preferExternalBox">
+ <property name="toolTip">
+ <string>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</string>
+ </property>
+ <property name="whatsThis">
+ <string>If checked, MO will use an external browser for buttons like "Visit on Nexus" instead of the integrated one.</string>
+ </property>
+ <property name="text">
+ <string>Prefer external browser</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="pluginsTab">
+ <attribute name="title">
+ <string>Plugins</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,1">
+ <item>
+ <widget class="QListWidget" name="pluginsList">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,1">
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="versionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="pluginSettingsList">
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>100</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Key</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="workaroundTab">
+ <attribute name="title">
+ <string>Workarounds</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Steam App ID</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="appIDEdit">
+ <property name="toolTip">
+ <string>The Steam AppID for your game</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The Steam App ID is required to directly start some games. For Skyrim, if this is not set or wrong, the &quot;Mod Organizer&quot; load mechanism may not work properly.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The preset for this is the App ID of the &quot;regular&quot; version so in most cases, you should be set.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you think you have a different version (GotY or something), follow these steps to get to the id:</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">1. Navigate to the game library in steam</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">2. right-click on the game you need the id for and choose </span><span style=" font-size:8pt; font-weight:600;">Create desktop shortcut</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">3. right-click on the newly created shortcut on your desktop and select </span><span style=" font-size:8pt; font-weight:600;">Properties</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">4. in the URL-field you should see something like this: </span><span style=" font-size:8pt; font-style:italic;">steam://rungameid/22380</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">22380 is the id you're looking for.</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,1">
+ <property name="spacing">
+ <number>7</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Load Mechanism</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="mechanismBox">
+ <property name="toolTip">
+ <string>Select loading mechanism. See help for details.</string>
+ </property>
+ <property name="whatsThis">
+ <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Mod Organizer needs a dll to be injected into the game so all mods are visible to it.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">There are several means to do this:</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Mod Organizer</span><span style=" font-size:8pt;"> (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. This does not work for the Steam version of Oblivion!</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Script Extender</span><span style=" font-size:8pt;"> In this mode, MO is installed as a Script Extender (obse, fose, nvse, skse) plugin. (recommended if you have a script extender installed)</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Proxy DLL</span><span style=" font-size:8pt;"> In this mode, MO replaces one of the game's dlls with one that loads MO (and the original dll of course). This will ONLY work with Steam games and it has only been tested with Skyrim. Please use this only if the other mechanisms don't work.</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="0,0,0">
+ <item>
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>NMM Version</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="nmmVersionEdit">
+ <property name="toolTip">
+ <string>The Version of Nexus Mod Manager to impersonate.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in.
+On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here.
+Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent.
+
+tl;dr-version: If Nexus-features don't work, insert the current version number of NMM here and try again.</string>
+ </property>
+ <property name="inputMask">
+ <string notr="true">009.009.009; </string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="hideUncheckedBox">
+ <property name="toolTip">
+ <string>Enforces that inactive ESPs and ESMs are never loaded.</string>
+ </property>
+ <property name="whatsThis">
+ <string>It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins.
+I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded.</string>
+ </property>
+ <property name="text">
+ <string>Hide inactive ESPs/ESMs</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="forceEnableBox">
+ <property name="toolTip">
+ <string>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)</string>
+ </property>
+ <property name="whatsThis">
+ <string>If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on)
+Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled.</string>
+ </property>
+ <property name="text">
+ <string>Force-enable game files</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="bsaDateBtn">
+ <property name="toolTip">
+ <string>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles.
+For the other games this is not a sufficient replacement for AI!</string>
+ </property>
+ <property name="whatsThis">
+ <string>For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles.
+For the other games this is not a sufficient replacement for AI!</string>
+ </property>
+ <property name="text">
+ <string>Back-date BSAs</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/resources/emblem-readonly.png</normaloff>:/MO/gui/resources/emblem-readonly.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/shared/appconfig.cpp b/src/shared/appconfig.cpp new file mode 100644 index 00000000..0d933d0a --- /dev/null +++ b/src/shared/appconfig.cpp @@ -0,0 +1,30 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "appconfig.h"
+
+namespace AppConfig {
+
+#define PARWSTRING wstring
+#define APPPARAM(partype, parid, value) partype parid ## () { return value; }
+#include "appconfig.inc"
+#undef PARWSTRING
+#undef APPPARAM
+
+}
diff --git a/src/shared/appconfig.h b/src/shared/appconfig.h new file mode 100644 index 00000000..b10ecc3c --- /dev/null +++ b/src/shared/appconfig.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef APPCONFIG_H
+#define APPCONFIG_H
+
+#include <string>
+
+namespace AppConfig {
+
+
+#define PARWSTRING wstring
+#define APPPARAM(partype, parid, value) partype parid ## ();
+#include "appconfig.inc"
+#undef PARWSTRING
+#undef APPPARAM
+
+}
+
+#endif // APPCONFIG_H
diff --git a/src/shared/appconfig.inc b/src/shared/appconfig.inc new file mode 100644 index 00000000..7710925a --- /dev/null +++ b/src/shared/appconfig.inc @@ -0,0 +1,12 @@ +APPPARAM(std::wstring, translationPrefix, L"organizer")
+APPPARAM(std::wstring, pluginPath, L"plugins")
+APPPARAM(std::wstring, stylesheetsPath, L"stylesheets")
+APPPARAM(std::wstring, logFile, L"ModOrganizer.log")
+APPPARAM(std::wstring, proxyDLLTarget, L"steam_api.dll")
+APPPARAM(std::wstring, proxyDLLOrig, L"steam_api_orig.dll") // needs to be identical to the value used in proxydll-project
+APPPARAM(std::wstring, proxyDLLSource, L"proxy.dll")
+APPPARAM(std::wstring, hookDLLName, L"hook.dll") // needs to be identical to the value used in proxydll-project
+APPPARAM(const wchar_t*, localSavePlaceholder, L"__MOProfileSave__\\")
+
+APPPARAM(std::wstring, firstStepsTutorial, L"tutorial_firststeps_main.js")
+APPPARAM(int, numLogFiles, 5) // number of log files to keep
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp new file mode 100644 index 00000000..748ead99 --- /dev/null +++ b/src/shared/directoryentry.cpp @@ -0,0 +1,799 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "directoryentry.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <sstream>
+#include <algorithm>
+#include <bsatk.h>
+#include "error_report.h"
+#include "util.h"
+#include "windows_error.h"
+#include <boost/bind.hpp>
+
+
+
+class OriginConnection {
+
+public:
+
+ typedef int Index;
+ static const int INVALID_INDEX = INT_MIN;
+
+public:
+
+ OriginConnection()
+ : m_NextID(0)
+ {}
+
+ FilesOrigin& createOrigin(const std::wstring &originName, const std::wstring &directory, int priority,
+ boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection) {
+ int newID = createID();
+ m_Origins[newID] = FilesOrigin(newID, originName, directory, priority, fileRegister, originConnection);
+ m_OriginsNameMap[originName] = newID;
+ m_OriginsPriorityMap[priority] = newID;
+ return m_Origins[newID];
+ }
+
+ bool exists(const std::wstring &name) {
+ std::map<std::wstring, int>::iterator iter = m_OriginsNameMap.find(name);
+ return iter != m_OriginsNameMap.end();
+ }
+
+ FilesOrigin &getByID(Index ID) {
+ return m_Origins[ID];
+ }
+
+ FilesOrigin &getByName(const std::wstring &name) {
+ std::map<std::wstring, int>::iterator iter = m_OriginsNameMap.find(name);
+ if (iter != m_OriginsNameMap.end()) {
+ return m_Origins[iter->second];
+ } else {
+ std::ostringstream stream;
+ stream << "invalid origin name: " << ToString(name, false);
+ throw std::runtime_error(stream.str());
+ }
+ }
+
+ void changePriorityLookup(int oldPriority, int newPriority)
+ {
+ auto iter = m_OriginsPriorityMap.find(oldPriority);
+ if (iter != m_OriginsPriorityMap.end()) {
+ Index idx = iter->second;
+ m_OriginsPriorityMap.erase(iter);
+ m_OriginsPriorityMap[newPriority] = idx;
+ }
+ }
+
+ void changeNameLookup(const std::wstring &oldName, const std::wstring &newName)
+ {
+ auto iter = m_OriginsNameMap.find(oldName);
+ if (iter != m_OriginsNameMap.end()) {
+ Index idx = iter->second;
+ m_OriginsNameMap.erase(iter);
+ m_OriginsNameMap[newName] = idx;
+ } else {
+ log("failed to change name lookup from %ls to %ls", oldName.c_str(), newName.c_str());
+ }
+ }
+
+private:
+
+ Index createID() {
+ return m_NextID++;
+ }
+
+private:
+
+ Index m_NextID;
+
+ std::map<Index, FilesOrigin> m_Origins;
+ std::map<std::wstring, Index> m_OriginsNameMap;
+ std::map<int, Index> m_OriginsPriorityMap;
+
+};
+
+
+//
+// FilesOrigin
+//
+
+
+void FilesOrigin::enable(bool enabled)
+{
+ if (!enabled) {
+ std::set<FileEntry::Index> copy = m_Files;
+ for (auto iter = copy.begin(); iter != copy.end(); ++iter) {
+ m_FileRegister->removeOrigin(*iter, m_ID);
+ }
+ m_Files.clear();
+ }
+ m_Disabled = !enabled;
+}
+
+
+void FilesOrigin::removeFile(FileEntry::Index index)
+{
+ auto iter = m_Files.find(index);
+ if (iter != m_Files.end()) {
+ m_Files.erase(iter);
+ }
+}
+
+
+
+std::wstring tail(const std::wstring &source, const size_t count)
+{
+ if (count >= source.length()) {
+ return source;
+ }
+
+ return source.substr(source.length() - count);
+}
+
+
+void FilesOrigin::setPriority(int priority)
+{
+ m_OriginConnection->changePriorityLookup(m_Priority, priority);
+
+ m_Priority = priority;
+}
+
+
+void FilesOrigin::setName(const std::wstring &name)
+{
+ m_OriginConnection->changeNameLookup(m_Name, name);
+ // change path too
+ if (tail(m_Path, m_Name.length()) == m_Name) {
+ m_Path = m_Path.substr(0, m_Path.length() - m_Name.length()).append(name);
+ }
+ m_Name = name;
+}
+
+std::vector<FileEntry*> FilesOrigin::getFiles() const
+{
+ std::vector<FileEntry*> result;
+
+ for (auto iter = m_Files.begin(); iter != m_Files.end(); ++iter) {
+ result.push_back(m_FileRegister->getFile(*iter));
+ }
+
+ return result;
+}
+
+
+
+//
+// FileEntry
+//
+
+void FileEntry::addOrigin(int origin, FILETIME fileTime, const std::wstring &archive)
+{
+ if (m_Origin == -1) {
+ m_Origin = origin;
+ m_FileTime = fileTime;
+ m_Archive = archive;
+// } else if (FilesOrigin::getByID(origin).getPriority() > FilesOrigin::getByID(m_Origin).getPriority()) {
+ } else if (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority()) {
+ if (std::find(m_Alternatives.begin(), m_Alternatives.end(), m_Origin) == m_Alternatives.end()) {
+ m_Alternatives.push_back(m_Origin);
+ }
+ m_Origin = origin;
+ m_FileTime = fileTime;
+ m_Archive = archive;
+ } else {
+ bool found = false;
+ if (m_Origin == origin) {
+ // already an origin
+ return;
+ }
+ for (std::vector<int>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
+ if (*iter == origin) {
+ // already an origin
+ return;
+ }
+ if (m_Parent->getOriginByID(*iter).getPriority() < m_Parent->getOriginByID(origin).getPriority()) {
+ m_Alternatives.insert(iter, origin);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ m_Alternatives.push_back(origin);
+ }
+ }
+}
+
+bool FileEntry::removeOrigin(int origin)
+{
+ if (m_Origin == origin) {
+ if (!m_Alternatives.empty()) {
+ // find alternative with the highest priority
+ std::vector<int>::iterator currentIter = m_Alternatives.begin();
+ for (std::vector<int>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) {
+ if ((m_Parent->getOriginByID(*iter).getPriority() > m_Parent->getOriginByID(*currentIter).getPriority()) &&
+ (*iter != origin)) {
+ currentIter = iter;
+ }
+ }
+ int currentID = *currentIter;
+ m_Alternatives.erase(currentIter);
+
+ m_Origin = currentID;
+
+ // now we need to update the file time...
+ std::wstring filePath = getFullPath();
+ HANDLE file = ::CreateFile(filePath.c_str(), GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (!::GetFileTime(file, NULL, NULL, &m_FileTime)) {
+ // maybe this file is in a bsa, but there is no easy way to find out which. User should refresh
+ // the view to find out
+ m_Archive = L"bsa?";
+ } else {
+ m_Archive = L"";
+ }
+
+ ::CloseHandle(file);
+
+ } else {
+ m_Origin = -1;
+ return true;
+ }
+ } else {
+ std::vector<int>::iterator newEnd = std::remove(m_Alternatives.begin(), m_Alternatives.end(), origin);
+ m_Alternatives.erase(newEnd, m_Alternatives.end());
+ }
+ return false;
+}
+
+
+// sorted by priority descending
+static bool ByOriginPriority(DirectoryEntry *entry, int LHS, int RHS)
+{
+ return entry->getOriginByID(LHS).getPriority() < entry->getOriginByID(RHS).getPriority();
+}
+
+
+FileEntry::FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent)
+ : m_Index(index), m_Name(name), m_Parent(parent), m_Origin(-1), m_Archive(L"")
+{
+}
+
+
+void FileEntry::sortOrigins()
+{
+ m_Alternatives.push_back(m_Origin);
+ std::sort(m_Alternatives.begin(), m_Alternatives.end(), boost::bind(ByOriginPriority, m_Parent, _1, _2));
+ m_Origin = m_Alternatives[m_Alternatives.size() - 1];
+ m_Alternatives.pop_back();
+}
+
+
+bool FileEntry::recurseParents(std::wstring &path, const DirectoryEntry *parent) const
+{
+ if (parent == NULL) {
+ return false;
+ } else {
+ // don't append the topmost parent because it is the virtual data-root
+ if (recurseParents(path, parent->getParent())) {
+ path.append(L"\\").append(parent->getName());
+ }
+ return true;
+ }
+}
+
+std::wstring FileEntry::getFullPath() const
+{
+ std::wstring result;
+ bool ignore = false;
+ result = m_Parent->getOriginByID(getOrigin(ignore)).getPath(); //base directory for origin
+ recurseParents(result, m_Parent); // all intermediate directories
+ result.append(L"\\").append(m_Name); // the actual filename
+ return result;
+}
+
+std::wstring FileEntry::getRelativePath() const
+{
+ std::wstring result;
+ recurseParents(result, m_Parent); // all intermediate directories
+ result.append(L"\\").append(m_Name); // the actual filename
+ return result;
+}
+
+
+
+
+
+//
+// DirectoryEntry
+//
+DirectoryEntry::DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID)
+ : m_OriginConnection(new OriginConnection),
+ m_Name(name), m_Parent(parent), m_Populated(false), m_Origin(originID)
+{
+ m_FileRegister.reset(new FileRegister(m_OriginConnection));
+}
+
+DirectoryEntry::DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID,
+ boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection)
+ : m_FileRegister(fileRegister), m_OriginConnection(originConnection),
+ m_Name(name), m_Parent(parent), m_Populated(false), m_Origin(originID)
+{}
+
+
+DirectoryEntry::~DirectoryEntry()
+{
+ clear();
+}
+
+
+const std::wstring &DirectoryEntry::getName() const
+{
+ return m_Name;
+}
+
+
+void DirectoryEntry::clear()
+{
+ m_Files.clear();
+ for (std::vector<DirectoryEntry*>::iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ delete *iter;
+ }
+ m_SubDirectories.clear();
+}
+
+
+FilesOrigin &DirectoryEntry::createOrigin(const std::wstring &originName, const std::wstring &directory, int priority)
+{
+ if (m_OriginConnection->exists(originName)) {
+ FilesOrigin &origin = m_OriginConnection->getByName(originName);
+ origin.enable(true);
+ return origin;
+ } else {
+ return m_OriginConnection->createOrigin(originName, directory, priority, m_FileRegister, m_OriginConnection);
+ }
+}
+
+
+void DirectoryEntry::addFromOrigin(const std::wstring &originName, const std::wstring &directory, int priority)
+{
+ FilesOrigin &origin = createOrigin(originName, directory, priority);
+ wchar_t *buffer = new wchar_t[MAXPATH_UNICODE + 1];
+ memset(buffer, L'\0', MAXPATH_UNICODE + 1);
+ try {
+ int offset = _snwprintf(buffer, MAXPATH_UNICODE, L"%ls", directory.c_str());
+ addFiles(origin, buffer, offset);
+ } catch (...) {
+ delete [] buffer;
+ buffer = NULL;
+ }
+ delete [] buffer;
+ m_Populated = true;
+}
+
+
+void DirectoryEntry::addFromBSA(const std::wstring &originName, std::wstring &directory, const std::wstring &fileName, int priority)
+{
+ FilesOrigin &origin = createOrigin(originName, directory, priority);
+
+ WIN32_FILE_ATTRIBUTE_DATA fileData;
+ if (::GetFileAttributesExW(fileName.c_str(), GetFileExInfoStandard, &fileData) == 0) {
+ throw windows_error("failed to determine file time");
+ }
+
+ BSA::Archive archive;
+ BSA::EErrorCode res = archive.read(ToString(fileName, false).c_str());
+ if ((res != BSA::ERROR_NONE) && (res != BSA::ERROR_INVALIDHASHES)) {
+ std::ostringstream stream;
+ stream << "invalid bsa file: " << ToString(fileName, false) << " errorcode " << res << " - " << ::GetLastError();
+ throw std::runtime_error(stream.str());
+ }
+ size_t namePos = fileName.find_last_of(L"\\/");
+ if (namePos == std::wstring::npos) {
+ namePos = 0;
+ } else {
+ ++namePos;
+ }
+
+ addFiles(origin, archive.getRoot(), fileData.ftLastWriteTime, fileName.substr(namePos));
+ m_Populated = true;
+}
+
+
+void DirectoryEntry::addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset)
+{
+ WIN32_FIND_DATAW findData;
+
+ _snwprintf(buffer + bufferOffset, MAXPATH_UNICODE - bufferOffset, L"\\*");
+ HANDLE searchHandle = ::FindFirstFileExW(buffer, FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE);
+ if (searchHandle != INVALID_HANDLE_VALUE) {
+ BOOL result = true;
+ while (result) {
+ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if ((wcscmp(findData.cFileName, L".") != 0) &&
+ (wcscmp(findData.cFileName, L"..") != 0)) {
+ int offset = _snwprintf(buffer + bufferOffset, MAXPATH_UNICODE, L"\\%ls", findData.cFileName);
+ // recurse into subdirectories
+ getSubDirectory(findData.cFileName, true, origin.getID())->addFiles(origin, buffer, bufferOffset + offset);
+ }
+ } else {
+ insert(findData.cFileName, origin, findData.ftLastWriteTime, L"");
+ }
+ result = ::FindNextFileW(searchHandle, &findData);
+ }
+ }
+ ::FindClose(searchHandle);
+}
+
+
+void DirectoryEntry::addFiles(FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName)
+{
+ // add files
+ for (unsigned int fileIdx = 0; fileIdx < archiveFolder->getNumFiles(); ++fileIdx) {
+ BSA::File::Ptr file = archiveFolder->getFile(fileIdx);
+ insert(ToWString(file->getName(), true), origin, fileTime, archiveName);
+ }
+
+ // recurse into subdirectories
+ for (unsigned int folderIdx = 0; folderIdx < archiveFolder->getNumSubFolders(); ++folderIdx) {
+ BSA::Folder::Ptr folder = archiveFolder->getSubFolder(folderIdx);
+ DirectoryEntry *folderEntry = getSubDirectoryRecursive(ToWString(folder->getName(), true), true, origin.getID());
+
+ folderEntry->addFiles(origin, folder, fileTime, archiveName);
+ }
+}
+
+
+void DirectoryEntry::removeFile(const std::wstring &filePath, int *origin)
+{
+ size_t pos = filePath.find_first_of(L"\\/");
+ if (pos == std::string::npos) {
+ this->remove(filePath, origin);
+ } else {
+ std::wstring dirName = filePath.substr(0, pos);
+ std::wstring rest = filePath.substr(pos + 1);
+ DirectoryEntry *entry = getSubDirectoryRecursive(dirName, false);
+ if (entry != NULL) {
+ entry->removeFile(rest, origin);
+ }
+ }
+}
+
+void DirectoryEntry::removeDirRecursive()
+{
+ while (!m_Files.empty()) {
+ m_FileRegister->removeFile(m_Files.begin()->second);
+ }
+
+ for (auto iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ (*iter)->removeDirRecursive();
+ }
+ m_SubDirectories.clear();
+}
+
+void DirectoryEntry::removeDir(const std::wstring &path)
+{
+ size_t pos = path.find_first_of(L"\\/");
+ if (pos == std::string::npos) {
+ for (auto iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ if (_wcsicmp((*iter)->getName().c_str(), path.c_str()) == 0) {
+ (*iter)->removeDirRecursive();
+ m_SubDirectories.erase(iter);
+ break;
+ }
+ }
+ } else {
+ std::wstring dirName = path.substr(0, pos);
+ std::wstring rest = path.substr(pos + 1);
+ DirectoryEntry *entry = getSubDirectoryRecursive(dirName, false);
+ if (entry != NULL) {
+ entry->removeDir(rest);
+ }
+ }
+}
+
+
+void DirectoryEntry::insertFile(const std::wstring &filePath, FilesOrigin &origin, FILETIME fileTime)
+{
+ size_t pos = filePath.find_first_of(L"\\/");
+ if (pos == std::string::npos) {
+ this->insert(filePath, origin, fileTime, L"");
+ } else {
+ std::wstring dirName = filePath.substr(0, pos);
+ std::wstring rest = filePath.substr(pos + 1);
+ getSubDirectoryRecursive(dirName, true, origin.getID())->insertFile(rest, origin, fileTime);
+ }
+}
+
+
+void DirectoryEntry::removeFile(FileEntry::Index index)
+{
+ if (m_Files.size() != 0) {
+ auto iter = std::find_if(m_Files.begin(), m_Files.end(),
+ [&index](const std::pair<std::wstring, FileEntry::Index> &iter) -> bool {
+ return iter.second == index; } );
+ if (iter != m_Files.end()) {
+ m_Files.erase(iter);
+ } else {
+ log("file \"%ls\" not in directory \"%ls\"",
+ m_FileRegister->getFile(index)->getName().c_str(),
+ this->getName().c_str());
+ }
+ } else {
+ log("file \"%ls\" not in directory \"%ls\", directory empty",
+ m_FileRegister->getFile(index)->getName().c_str(),
+ this->getName().c_str());
+ }
+}
+
+
+int DirectoryEntry::anyOrigin() const
+{
+ bool ignore;
+ for (auto iter = m_Files.begin(); iter != m_Files.end(); ++iter) {
+ FileEntry *entry = m_FileRegister->getFile(iter->second);
+ if (!entry->isFromArchive()) {
+ return entry->getOrigin(ignore);
+ }
+ }
+
+ // if we got here, no file directly within this directory is a valid indicator for a mod, thus
+ // we continue looking in subdirectories
+ for (std::vector<DirectoryEntry*>::const_iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ int res = (*iter)->anyOrigin();
+ if (res != -1){
+ return res;
+ }
+ }
+ return m_Origin;
+}
+
+
+bool DirectoryEntry::originExists(const std::wstring &name) const
+{
+ return m_OriginConnection->exists(name);
+}
+
+
+FilesOrigin &DirectoryEntry::getOriginByID(int ID) const
+{
+ return m_OriginConnection->getByID(ID);
+}
+
+
+FilesOrigin &DirectoryEntry::getOriginByName(const std::wstring &name) const
+{
+ return m_OriginConnection->getByName(name);
+}
+
+
+int DirectoryEntry::getOrigin(const std::wstring &path, bool &archive)
+{
+ const DirectoryEntry *directory = NULL;
+ const FileEntry *file = searchFile(path, &directory);
+ if (file != NULL) {
+ return file->getOrigin(archive);
+ } else {
+ if (directory != NULL) {
+ return directory->anyOrigin();
+ } else {
+ return -1;
+ }
+ }
+}
+
+std::vector<FileEntry*> DirectoryEntry::getFiles() const
+{
+ std::vector<FileEntry*> result;
+ for (auto iter = m_Files.begin(); iter != m_Files.end(); ++iter) {
+ result.push_back(m_FileRegister->getFile(iter->second));
+ }
+ return result;
+}
+
+
+const FileEntry *DirectoryEntry::searchFile(const std::wstring &path, const DirectoryEntry **directory) const
+{
+ if (directory != NULL) {
+ *directory = NULL;
+ }
+
+ if ((path.length() == 0) ||
+ (path == L"*")) {
+ // no file name -> the path ended on a (back-)slash
+ *directory = this;
+
+ return NULL;
+ }
+
+ size_t len = path.find_first_of(L"\\/");
+
+ if (len == std::string::npos) {
+ // no more path components
+ auto iter = m_Files.find(path);
+ if (iter != m_Files.end()) {
+ return m_FileRegister->getFile(iter->second);
+ } else if (directory != NULL) {
+ DirectoryEntry *temp = findSubDirectory(path);
+ if (temp != NULL) {
+ *directory = temp;
+ }
+ }
+ } else {
+ // file is in in a subdirectory, recurse into the matching subdirectory
+ std::wstring pathComponent = path.substr(0, len);
+ DirectoryEntry *temp = findSubDirectory(pathComponent);
+ if (temp != NULL) {
+ return temp->searchFile(path.substr(len + 1), directory);
+ }
+ }
+ return NULL;
+}
+
+/*
+void DirectoryEntry::sortOrigins()
+{
+ for (std::set<FileEntry>::iterator iter = m_Files.begin(); iter != m_Files.end(); ++iter) {
+ const_cast<FileEntry&>(*iter).sortOrigins();
+ }
+ for (std::vector<DirectoryEntry*>::iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ (*iter)->sortOrigins();
+ }
+}
+*/
+
+DirectoryEntry *DirectoryEntry::findSubDirectory(const std::wstring &name) const
+{
+ for (std::vector<DirectoryEntry*>::const_iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ if (_wcsicmp((*iter)->getName().c_str(), name.c_str()) == 0) {
+ return *iter;
+ }
+ }
+ return NULL;
+}
+
+
+
+const FileEntry *DirectoryEntry::findFile(const std::wstring &name)
+{
+ auto iter = m_Files.find(name);
+ if (iter != m_Files.end()) {
+ return m_FileRegister->getFile(iter->second);
+ } else {
+ return NULL;
+ }
+}
+
+DirectoryEntry *DirectoryEntry::getSubDirectory(const std::wstring &name, bool create, int originID)
+{
+ for (std::vector<DirectoryEntry*>::iterator iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) {
+ if (_wcsicmp((*iter)->getName().c_str(), name.c_str()) == 0) {
+ return *iter;
+ }
+ }
+ if (create) {
+ std::vector<DirectoryEntry*>::iterator iter = m_SubDirectories.insert(m_SubDirectories.end(),
+ new DirectoryEntry(name, this, originID, m_FileRegister, m_OriginConnection));
+ return *iter;
+ } else {
+ return NULL;
+ }
+}
+
+
+DirectoryEntry *DirectoryEntry::getSubDirectoryRecursive(const std::wstring &path, bool create, int originID)
+{
+ if (path.length() == 0) {
+ // path ended with a backslash?
+ return this;
+ }
+
+ size_t pos = path.find_first_of(L"\\/");
+ if (pos == std::wstring::npos) {
+ return getSubDirectory(path, create);
+ } else {
+ DirectoryEntry *nextChild = getSubDirectory(path.substr(0, pos), create, originID);
+ if (nextChild == NULL) {
+ return NULL;
+ } else {
+ return nextChild->getSubDirectoryRecursive(path.substr(pos + 1), create, originID);
+ }
+ }
+}
+
+
+
+FileRegister::FileRegister(boost::shared_ptr<OriginConnection> originConnection)
+ : m_OriginConnection(originConnection)
+{
+}
+
+FileEntry::Index FileRegister::generateIndex()
+{
+ static FileEntry::Index sIndex = 0;
+ return sIndex++;
+}
+
+bool FileRegister::indexValid(FileEntry::Index index) const
+{
+ return m_Files.find(index) != m_Files.end();
+}
+
+FileEntry &FileRegister::createFile(const std::wstring &name, DirectoryEntry *parent)
+{
+ FileEntry::Index index = generateIndex();
+ m_Files[index] = FileEntry(index, name, parent);
+ return m_Files[index];
+}
+
+
+FileEntry *FileRegister::getFile(FileEntry::Index index)
+{
+ auto iter = m_Files.find(index);
+ if (iter != m_Files.end()) {
+ return &iter->second;
+ }
+ return NULL;
+}
+
+
+void FileRegister::unregisterFile(FileEntry &file)
+{
+ bool ignore;
+ // unregister from origin
+ int originID = file.getOrigin(ignore);
+ m_OriginConnection->getByID(originID).removeFile(file.getIndex());
+ const std::vector<int> &alternatives = file.getAlternatives();
+ for (auto iter = alternatives.begin(); iter != alternatives.end(); ++iter) {
+ m_OriginConnection->getByID(*iter).removeFile(file.getIndex());
+ }
+
+ // unregister from directory
+ if (file.getParent() != NULL) {
+ file.getParent()->removeFile(file.getIndex());
+ }
+}
+
+
+void FileRegister::removeFile(FileEntry::Index index)
+{
+ auto iter = m_Files.find(index);
+ if (iter != m_Files.end()) {
+ unregisterFile(iter->second);
+ m_Files.erase(index);
+ }
+}
+
+void FileRegister::removeOrigin(FileEntry::Index index, int originID)
+{
+ auto iter = m_Files.find(index);
+ if (iter != m_Files.end()) {
+ if (iter->second.removeOrigin(originID)) {
+ unregisterFile(iter->second);
+ }
+ }
+}
+
+void FileRegister::sortOrigins()
+{
+ for (auto iter = m_Files.begin(); iter != m_Files.end(); ++iter) {
+ iter->second.sortOrigins();
+ }
+}
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h new file mode 100644 index 00000000..72e96357 --- /dev/null +++ b/src/shared/directoryentry.h @@ -0,0 +1,313 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef DIRECTORYENTRY_H
+#define DIRECTORYENTRY_H
+
+#include <string>
+#include <set>
+#include <vector>
+#include <map>
+#include <cassert>
+#define WIN32_MEAN_AND_LEAN
+#include <Windows.h>
+#include <bsatk.h>
+#include <boost/shared_ptr.hpp>
+#include "util.h"
+
+
+class DirectoryEntry;
+class OriginConnection;
+class FileRegister;
+
+
+class FileEntry {
+
+public:
+
+ typedef unsigned int Index;
+
+public:
+
+ FileEntry() : m_Index(UINT_MAX), m_Name(), m_Parent(NULL) {}
+
+ FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent);
+
+ Index getIndex() const { return m_Index; }
+
+ void addOrigin(int origin, FILETIME fileTime, const std::wstring &archive);
+ // remove the specified origin from the list of origins that contain this file. if no origin is left,
+ // the file is effectively deleted and true is returned. otherwise, false is returned
+ bool removeOrigin(int origin);
+ void sortOrigins();
+
+ // gets the list of alternative origins (origins with lower priority than the primary one).
+ // if sortOrigins has been called, it is sorted by priority (ascending)
+ const std::vector<int> &getAlternatives() const { return m_Alternatives; }
+
+ const std::wstring &getName() const { return m_Name; }
+ int getOrigin(bool &archive) const { archive = (m_Archive.length() != 0); return m_Origin; }
+ const std::wstring &getArchive() const { return m_Archive; }
+ bool isFromArchive() const { return m_Archive.length() != 0; }
+ std::wstring getFullPath() const;
+ std::wstring getRelativePath() const;
+ DirectoryEntry *getParent() { return m_Parent; }
+
+ void setFileTime(FILETIME fileTime) const { m_FileTime = fileTime; }
+ FILETIME getFileTime() const { return m_FileTime; }
+
+private:
+
+ bool recurseParents(std::wstring &path, const DirectoryEntry *parent) const;
+
+ void determineTime();
+
+private:
+
+ Index m_Index;
+ std::wstring m_Name;
+ int m_Origin;
+ std::wstring m_Archive;
+ std::vector<int> m_Alternatives;
+ DirectoryEntry *m_Parent;
+ mutable FILETIME m_FileTime;
+
+ friend bool operator<(const FileEntry &lhs, const FileEntry &rhs) {
+ return _wcsicmp(lhs.m_Name.c_str(), rhs.m_Name.c_str()) < 0;
+ }
+ friend bool operator==(const FileEntry &lhs, const FileEntry &rhs) {
+ return _wcsicmp(lhs.m_Name.c_str(), rhs.m_Name.c_str()) == 0;
+ }
+};
+
+
+// represents a mod or the data directory, providing files to the tree
+class FilesOrigin {
+ friend class OriginConnection;
+public:
+
+ FilesOrigin()
+ : m_ID(0), m_Disabled(false), m_Name(), m_Path(), m_Priority(0) { }
+
+ // sets priority for this origin, but it will overwrite the exisiting mapping for this priority,
+ // the previous origin will no longer be referenced
+ void setPriority(int priority);
+
+ int getPriority() const { return m_Priority; }
+
+ void setName(const std::wstring &name);
+ const std::wstring &getName() const { return m_Name; }
+
+ int getID() const { return m_ID; }
+ const std::wstring &getPath() const { return m_Path; }
+
+ std::vector<FileEntry*> getFiles() const;
+
+ void enable(bool enabled);
+ bool isDisabled() const { return m_Disabled; }
+
+ void addFile(FileEntry::Index index) { m_Files.insert(index); }
+ void removeFile(FileEntry::Index index);
+
+private:
+
+ FilesOrigin(int ID, const std::wstring &name, const std::wstring &path, int priority,
+ boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection)
+ : m_ID(ID), m_Disabled(false), m_Name(name), m_Path(path), m_Priority(priority),
+ m_FileRegister(fileRegister), m_OriginConnection(originConnection) {}
+
+private:
+
+ int m_ID;
+
+ bool m_Disabled;
+
+ std::set<FileEntry::Index> m_Files;
+ std::wstring m_Name;
+ std::wstring m_Path;
+ int m_Priority;
+ boost::shared_ptr<FileRegister> m_FileRegister;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+};
+
+
+class FileRegister
+{
+
+public:
+
+ FileRegister(boost::shared_ptr<OriginConnection> originConnection);
+
+ bool indexValid(FileEntry::Index index) const;
+
+ FileEntry &createFile(const std::wstring &name, DirectoryEntry *parent);
+ FileEntry *getFile(FileEntry::Index index);
+
+ void removeFile(FileEntry::Index index);
+ void removeOrigin(FileEntry::Index index, int originID);
+
+ void sortOrigins();
+
+private:
+
+ FileEntry::Index generateIndex();
+
+ void unregisterFile(FileEntry &file);
+
+private:
+
+ std::map<FileEntry::Index, FileEntry> m_Files;
+
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+};
+
+
+class DirectoryEntry
+{
+public:
+
+ DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID);
+
+ DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID,
+ boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection);
+
+ ~DirectoryEntry();
+
+ void clear();
+ bool isPopulated() const { return m_Populated; }
+
+ boost::shared_ptr<FileRegister> getRegister() { return m_FileRegister; }
+ const DirectoryEntry *getParent() const { return m_Parent; }
+
+ // add files to this directory (and subdirectories) from the specified origin. That origin may exist or not
+ void addFromOrigin(const std::wstring &originName, const std::wstring &directory, int priority);
+ void addFromBSA(const std::wstring &originName, std::wstring &directory, const std::wstring &fileName, int priority);
+
+ const std::wstring &getName() const;
+
+ boost::shared_ptr<FileRegister> getFileRegister() { return m_FileRegister; }
+
+ bool originExists(const std::wstring &name) const;
+ FilesOrigin &getOriginByID(int ID) const;
+ FilesOrigin &getOriginByName(const std::wstring &name) const;
+
+ int getOrigin(const std::wstring &path, bool &archive);
+
+ std::vector<FileEntry*> getFiles() const;
+
+ void getSubDirectories(std::vector<DirectoryEntry*>::const_iterator &begin, std::vector<DirectoryEntry*>::const_iterator &end) const {
+ begin = m_SubDirectories.begin(); end = m_SubDirectories.end();
+ }
+
+ DirectoryEntry *findSubDirectory(const std::wstring &name) const;
+
+ /** retrieve a file in this directory by name.
+ * @param name name of the file
+ * @return fileentry object for the file or NULL if no file matches
+ */
+ const FileEntry *findFile(const std::wstring &name);
+
+ /** search through this directory and all subdirectories for a file by the specified name.
+ if directory is not NULL, the referenced variable will be set to true if the path refers to a directory.
+ the returned pointer is NULL in that case */
+ const FileEntry *searchFile(const std::wstring &path, const DirectoryEntry **directory) const;
+
+ void insertFile(const std::wstring &filePath, FilesOrigin &origin, FILETIME fileTime);
+
+ void removeFile(FileEntry::Index index);
+
+ // remove the specified file from the tree. This can be a path leading to a file in a subdirectory
+ void removeFile(const std::wstring &filePath, int *origin = NULL);
+
+ /**
+ * @brief remove the specified directory
+ * @param path directory to remove
+ */
+ void removeDir(const std::wstring &path);
+
+ void remove(const std::wstring &fileName, int *origin) {
+ auto iter = m_Files.find(fileName);
+ if (iter != m_Files.end()) {
+ if (origin != NULL) {
+ FileEntry *entry = m_FileRegister->getFile(iter->second);
+ if (entry != NULL) {
+ bool ignore;
+ *origin = entry->getOrigin(ignore);
+ }
+ }
+ m_FileRegister->removeFile(iter->second);
+ }
+ }
+
+private:
+
+ void insert(const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime, const std::wstring &archive) {
+ auto iter = m_Files.find(fileName);
+ FileEntry *file = NULL;
+ if (iter != m_Files.end()) {
+ file = m_FileRegister->getFile(iter->second);
+ } else {
+ file = &m_FileRegister->createFile(fileName, this);
+ m_Files[fileName] = file->getIndex();
+ }
+ file->addOrigin(origin.getID(), fileTime, archive);
+ origin.addFile(file->getIndex());
+ }
+
+ FilesOrigin &createOrigin(const std::wstring &originName, const std::wstring &directory, int priority);
+ void addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset);
+ void addFiles(FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, const std::wstring &archiveName);
+
+ DirectoryEntry *getSubDirectory(const std::wstring &name, bool create, int originID = -1);
+
+ DirectoryEntry *getSubDirectoryRecursive(const std::wstring &path, bool create, int originID = -1);
+
+ int anyOrigin() const;
+
+ void removeDirRecursive();
+
+private:
+
+ struct WStrLess {
+ bool operator()(const std::wstring &LHS, const std::wstring &RHS) const {
+ return _wcsicmp(LHS.c_str(), RHS.c_str()) < 0;
+ }
+ };
+
+
+private:
+
+ boost::shared_ptr<FileRegister> m_FileRegister;
+ boost::shared_ptr<OriginConnection> m_OriginConnection;
+
+ std::wstring m_Name;
+ std::map<std::wstring, FileEntry::Index, WStrLess> m_Files;
+ std::vector<DirectoryEntry*> m_SubDirectories;
+
+ DirectoryEntry *m_Parent;
+ int m_Origin;
+
+ bool m_Populated;
+
+};
+
+
+#endif // DIRECTORYENTRY_H
diff --git a/src/shared/error_report.cpp b/src/shared/error_report.cpp new file mode 100644 index 00000000..49fdba85 --- /dev/null +++ b/src/shared/error_report.cpp @@ -0,0 +1,99 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "error_report.h"
+#include <sstream>
+#include <stdio.h>
+
+
+void reportError(LPCSTR format, ...)
+{
+ char buffer[1025];
+ memset(buffer, 0, sizeof(char) * 1025);
+
+ va_list argList;
+ va_start(argList, format);
+
+ vsnprintf(buffer, 1024, format, argList);
+ va_end(argList);
+
+ MessageBoxA(NULL, buffer, "Error", MB_OK | MB_ICONERROR);
+ LocalFree(buffer);
+}
+
+void reportError(LPCWSTR format, ...)
+{
+ WCHAR buffer[1025];
+ memset(buffer, 0, sizeof(WCHAR) * 1025);
+
+ va_list argList;
+ va_start(argList, format);
+
+
+ _vsnwprintf(buffer, 1024, format, argList);
+ va_end(argList);
+
+ MessageBoxW(NULL, buffer, L"Error", MB_OK | MB_ICONERROR);
+ LocalFree(buffer);
+}
+
+
+std::string getCurrentErrorStringA()
+{
+ LPSTR buffer = NULL;
+
+ DWORD errorCode = ::GetLastError();
+
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, NULL) == 0) {
+ ::SetLastError(errorCode);
+ return std::string();
+ } else {
+ LPSTR lastChar = buffer + strlen(buffer) - 2;
+ *lastChar = '\0';
+
+ std::string result(buffer);
+
+ LocalFree(buffer);
+ ::SetLastError(errorCode);
+ return result;
+ }
+}
+
+std::wstring getCurrentErrorStringW()
+{
+ LPWSTR buffer = NULL;
+
+ DWORD errorCode = ::GetLastError();
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&buffer, 0, NULL) == 0) {
+ ::SetLastError(errorCode);
+ return std::wstring();
+ } else {
+ LPWSTR lastChar = buffer + wcslen(buffer) - 2;
+ *lastChar = '\0';
+
+ std::wstring result(buffer);
+
+ LocalFree(buffer);
+ ::SetLastError(errorCode);
+ return result;
+ }
+}
diff --git a/src/shared/error_report.h b/src/shared/error_report.h new file mode 100644 index 00000000..6ee296df --- /dev/null +++ b/src/shared/error_report.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once
+
+#include <tchar.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <string>
+
+namespace std {
+#ifdef UNICODE
+typedef wstring tstring;
+#else
+typedef string tstring;
+#endif
+}
+
+void reportError(LPCSTR format, ...);
+void reportError(LPCWSTR format, ...);
+
+extern void log(const char* format, ...);
+
+std::string getCurrentErrorStringA();
+std::wstring getCurrentErrorStringW();
+
+#ifdef UNICODE
+#define getCurrentErrorString getCurrentErrorStringW
+#else
+#define getCurrentErrorString getCurrentErrorStringA
+#endif
diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp new file mode 100644 index 00000000..f9699145 --- /dev/null +++ b/src/shared/fallout3info.cpp @@ -0,0 +1,244 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "fallout3info.h"
+#include "util.h"
+#include <tchar.h>
+#include <ShlObj.h>
+#include <sstream>
+#include "windows_error.h"
+#include "error_report.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <boost/assign.hpp>
+
+Fallout3Info::Fallout3Info(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
+ : GameInfo(omoDirectory, gameDirectory)
+{
+ identifyMyGamesDirectory(L"fallout3");
+}
+
+bool Fallout3Info::identifyGame(const std::wstring &searchPath)
+{
+ return FileExists(searchPath, L"Fallout3.exe") &&
+ FileExists(searchPath, L"FalloutLauncher.exe");
+}
+
+unsigned long Fallout3Info::getBSAVersion()
+{
+ return 0x68;
+}
+
+std::wstring Fallout3Info::getRegPathStatic()
+{
+ HKEY key;
+ LONG errorcode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Bethesda Softworks\\Fallout3",
+ 0, KEY_QUERY_VALUE, &key);
+
+ if (errorcode != ERROR_SUCCESS) {
+ return L"";
+ }
+
+ WCHAR temp[MAX_PATH];
+ DWORD bufferSize = MAX_PATH;
+
+ errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize);
+
+ return std::wstring(temp);
+}
+
+std::wstring Fallout3Info::getInvalidationBSA()
+{
+ return L"Fallout - Invalidation.bsa";
+}
+
+bool Fallout3Info::isInvalidationBSA(const std::wstring &bsaName)
+{
+ static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", NULL };
+
+ for (int i = 0; invalidation[i] != NULL; ++i) {
+ if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::wstring Fallout3Info::getDocumentsDir()
+{
+ std::wostringstream temp;
+ temp << getMyGamesDirectory() << L"\\Fallout3";
+
+ return temp.str();
+}
+
+std::wstring Fallout3Info::getSaveGameDir()
+{
+ std::wostringstream temp;
+ temp << getDocumentsDir() << L"\\Saves";
+ return temp.str();
+}
+
+std::vector<std::wstring> Fallout3Info::getPrimaryPlugins()
+{
+ return boost::assign::list_of(L"fallout3.esm");
+}
+
+std::vector<std::wstring> Fallout3Info::getIniFileNames()
+{
+ return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
+}
+
+std::wstring Fallout3Info::getSaveGameExtension()
+{
+ return L"*.fos";
+}
+
+std::wstring Fallout3Info::getReferenceDataFile()
+{
+ return L"Fallout - Meshes.bsa";
+}
+
+
+std::wstring Fallout3Info::getOMODExt()
+{
+ return L"fomod";
+}
+
+
+std::wstring Fallout3Info::getSteamAPPId()
+{
+ return L"22300";
+}
+
+
+std::wstring Fallout3Info::getSEName()
+{
+ return L"fose";
+}
+
+
+std::wstring Fallout3Info::getNexusPage()
+{
+ return L"http://fallout3.nexusmods.com";
+}
+
+
+std::wstring Fallout3Info::getNexusInfoUrlStatic()
+{
+ return L"http://fallout3.nexusmods.com";
+}
+
+
+int Fallout3Info::getNexusModIDStatic()
+{
+ return 16348;
+}
+
+
+void Fallout3Info::createProfile(const std::wstring &directory, bool useDefaults)
+{
+ std::wostringstream target;
+
+ // copy plugins.txt
+ target << directory << "\\plugins.txt";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ source << getLocalAppFolder() << "\\Fallout3\\plugins.txt";
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CloseHandle(file);
+ }
+ }
+
+ // copy ini-file
+ target.str(L""); target.clear();
+ target << directory << L"\\fallout.ini";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ if (useDefaults) {
+ source << getGameDirectory() << L"\\fallout_default.ini";
+ } else {
+ source << getMyGamesDirectory() << L"\\Fallout3";
+ if (::FileExists(source.str(), L"fallout.ini")) {
+ source << L"\\fallout.ini";
+ } else {
+ source.str(L"");
+ source << getGameDirectory() << L"\\fallout_default.ini";
+ }
+ }
+
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ { // copy falloutprefs.ini-file
+ std::wstring target = directory.substr().append(L"\\falloutprefs.ini");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getMyGamesDirectory() << L"\\Fallout3\\falloutprefs.ini";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ }
+}
+
+
+void Fallout3Info::repairProfile(const std::wstring &directory)
+{
+ createProfile(directory, false);
+}
+
+
+bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+{
+ static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", NULL };
+
+ for (int i = 0; profileFiles[i] != NULL; ++i) {
+ if (_wcsicmp(fileName, profileFiles[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+std::vector<ExecutableInfo> Fallout3Info::getExecutables()
+{
+ std::vector<ExecutableInfo> result;
+ result.push_back(ExecutableInfo(L"FOSE", L"fose_loader.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Fallout 3", L"fallout3.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Fallout Mod Manager", L"fomm/fomm.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Construction Kit", L"geck.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Fallout Launcher", L"FalloutLauncher.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE));
+
+ return result;
+}
diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h new file mode 100644 index 00000000..bc9ab82d --- /dev/null +++ b/src/shared/fallout3info.h @@ -0,0 +1,94 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef FALLOUT3INFO_H
+#define FALLOUT3INFO_H
+
+
+#include "gameinfo.h"
+
+
+class Fallout3Info : public GameInfo
+{
+
+ friend class GameInfo;
+
+public:
+
+ virtual ~Fallout3Info() {}
+
+ virtual unsigned long getBSAVersion();
+
+ static std::wstring getRegPathStatic();
+ virtual std::wstring getRegPath() { return Fallout3Info::getRegPathStatic(); }
+ virtual std::wstring getBinaryName() { return L"Fallout3.exe"; }
+
+ virtual GameInfo::Type getType() { return TYPE_FALLOUT3; }
+
+ virtual std::wstring getGameName() const { return L"Fallout 3"; }
+ virtual std::wstring getGameShortName() const { return L"Fallout3"; }
+
+ virtual std::wstring getInvalidationBSA();
+
+ virtual bool isInvalidationBSA(const std::wstring &bsaName);
+
+ // full path to this games "My Games"-directory
+ virtual std::wstring getDocumentsDir();
+
+ virtual std::wstring getSaveGameDir();
+
+ virtual std::vector<std::wstring> getPrimaryPlugins();
+
+ // file name of this games ini (no path)
+ virtual std::vector<std::wstring> getIniFileNames();
+
+ virtual std::wstring getSaveGameExtension();
+ virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getOMODExt();
+
+ virtual std::wstring getSteamAPPId();
+
+ virtual std::wstring getSEName();
+
+ virtual std::wstring getNexusPage();
+ static std::wstring getNexusInfoUrlStatic();
+ virtual std::wstring getNexusInfoUrl() { return Fallout3Info::getNexusInfoUrlStatic(); }
+ static int getNexusModIDStatic();
+ virtual int getNexusModID() { return Fallout3Info::getNexusModIDStatic(); }
+
+ virtual void createProfile(const std::wstring &directory, bool useDefaults);
+ virtual void repairProfile(const std::wstring &directory);
+
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+
+ // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
+ // the game directory
+ virtual std::vector<ExecutableInfo> getExecutables();
+
+ virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+
+private:
+
+ Fallout3Info(const std::wstring &omoDirectory, const std::wstring &gameDirectory);
+
+ static bool identifyGame(const std::wstring &searchPath);
+
+};
+
+#endif // FALLOUT3INFO_H
diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp new file mode 100644 index 00000000..380940b7 --- /dev/null +++ b/src/shared/falloutnvinfo.cpp @@ -0,0 +1,246 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "falloutnvinfo.h"
+#include "util.h"
+#include <tchar.h>
+#include <ShlObj.h>
+#include <sstream>
+#include "windows_error.h"
+#include "error_report.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <boost/assign.hpp>
+
+
+FalloutNVInfo::FalloutNVInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
+ : GameInfo(omoDirectory, gameDirectory)
+{
+ identifyMyGamesDirectory(L"falloutnv");
+}
+
+bool FalloutNVInfo::identifyGame(const std::wstring &searchPath)
+{
+ return FileExists(searchPath, L"FalloutNV.exe") &&
+ FileExists(searchPath, L"FalloutNVLauncher.exe");
+}
+
+unsigned long FalloutNVInfo::getBSAVersion()
+{
+ return 0x68;
+}
+
+std::wstring FalloutNVInfo::getRegPathStatic()
+{
+ HKEY key;
+ LONG errorcode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Bethesda Softworks\\FalloutNV",
+ 0, KEY_QUERY_VALUE, &key);
+
+ if (errorcode != ERROR_SUCCESS) {
+ return L"";
+ }
+
+ WCHAR temp[MAX_PATH];
+ DWORD bufferSize = MAX_PATH;
+
+ errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize);
+
+ return std::wstring(temp);
+}
+
+std::wstring FalloutNVInfo::getInvalidationBSA()
+{
+ return L"Fallout - Invalidation.bsa";
+}
+
+bool FalloutNVInfo::isInvalidationBSA(const std::wstring &bsaName)
+{
+ static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", NULL };
+
+ for (int i = 0; invalidation[i] != NULL; ++i) {
+ if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::wstring FalloutNVInfo::getDocumentsDir()
+{
+ std::wostringstream temp;
+ temp << getMyGamesDirectory() << L"\\FalloutNV";
+
+ return temp.str();
+}
+
+std::wstring FalloutNVInfo::getSaveGameDir()
+{
+ std::wostringstream temp;
+ temp << getDocumentsDir() << L"\\Saves";
+ return temp.str();
+}
+
+std::vector<std::wstring> FalloutNVInfo::getPrimaryPlugins()
+{
+ return boost::assign::list_of(L"falloutnv.esm");
+}
+
+std::vector<std::wstring> FalloutNVInfo::getIniFileNames()
+{
+ return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
+}
+
+
+std::wstring FalloutNVInfo::getSaveGameExtension()
+{
+ return L"*.fos";
+}
+
+std::wstring FalloutNVInfo::getReferenceDataFile()
+{
+ return L"Fallout - Meshes.bsa";
+}
+
+
+std::wstring FalloutNVInfo::getOMODExt()
+{
+ return L"fomod";
+}
+
+
+std::wstring FalloutNVInfo::getSteamAPPId()
+{
+ return L"22380";
+}
+
+
+void FalloutNVInfo::createProfile(const std::wstring &directory, bool useDefaults)
+{
+ std::wostringstream target;
+
+ // copy plugins.txt
+ target << directory << "\\plugins.txt";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ source << getLocalAppFolder() << "\\FalloutNV\\plugins.txt";
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CloseHandle(file);
+ }
+ }
+
+ // copy ini-file
+ target.str(L""); target.clear();
+ target << directory << L"\\fallout.ini";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ if (useDefaults) {
+ source << getGameDirectory() << L"\\fallout_default.ini";
+ } else {
+ source << getMyGamesDirectory() << L"\\FalloutNV";
+ if (::FileExists(source.str(), L"fallout.ini")) {
+ source << L"\\fallout.ini";
+ } else {
+ source.str(L"");
+ source << getGameDirectory() << L"\\fallout_default.ini";
+ }
+ }
+
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ { // copy falloutprefs.ini-file
+ std::wstring target = directory.substr().append(L"\\falloutprefs.ini");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getMyGamesDirectory() << L"\\FalloutNV\\falloutprefs.ini";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ }
+}
+
+
+std::wstring FalloutNVInfo::getSEName()
+{
+ return L"nvse";
+}
+
+
+std::wstring FalloutNVInfo::getNexusPage()
+{
+ return L"http://newvegas.nexusmods.com";
+}
+
+
+std::wstring FalloutNVInfo::getNexusInfoUrlStatic()
+{
+ return L"http://newvegas.nexusmods.com";
+}
+
+
+int FalloutNVInfo::getNexusModIDStatic()
+{
+ return 42572;
+}
+
+
+void FalloutNVInfo::repairProfile(const std::wstring &directory)
+{
+ createProfile(directory, false);
+}
+
+
+bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+{
+ static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", NULL };
+
+ for (int i = 0; profileFiles[i] != NULL; ++i) {
+ if (_wcsicmp(fileName, profileFiles[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+std::vector<ExecutableInfo> FalloutNVInfo::getExecutables()
+{
+ std::vector<ExecutableInfo> result;
+ result.push_back(ExecutableInfo(L"NVSE", L"nvse_loader.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"New Vegas", L"falloutnv.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Fallout Mod Manager", L"fomm/fomm.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Construction Kit", L"geck.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Fallout Launcher", L"FalloutNVLauncher.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE));
+
+ return result;
+}
diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h new file mode 100644 index 00000000..aa02ac30 --- /dev/null +++ b/src/shared/falloutnvinfo.h @@ -0,0 +1,95 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef FALLOUTNVINFO_H
+#define FALLOUTNVINFO_H
+
+
+#include "gameinfo.h"
+
+
+class FalloutNVInfo : public GameInfo
+{
+
+ friend class GameInfo;
+
+public:
+
+ virtual ~FalloutNVInfo() {}
+
+ virtual unsigned long getBSAVersion();
+
+ static std::wstring getRegPathStatic();
+ virtual std::wstring getRegPath() { return FalloutNVInfo::getRegPathStatic(); }
+ virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; }
+
+ virtual GameInfo::Type getType() { return TYPE_FALLOUTNV; }
+
+ virtual std::wstring getGameName() const { return L"New Vegas"; }
+ virtual std::wstring getGameShortName() const { return L"FalloutNV"; }
+
+// virtual bool requiresSteam() const { return true; }
+
+ virtual std::wstring getInvalidationBSA();
+
+ virtual bool isInvalidationBSA(const std::wstring &bsaName);
+
+ // full path to this games "My Games"-directory
+ virtual std::wstring getDocumentsDir();
+
+ virtual std::wstring getSaveGameDir();
+
+ virtual std::vector<std::wstring> getPrimaryPlugins();
+
+ // file name of this games ini (no path)
+ virtual std::vector<std::wstring> getIniFileNames();
+
+ virtual std::wstring getSaveGameExtension();
+ virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getOMODExt();
+
+ virtual std::wstring getSteamAPPId();
+
+ virtual std::wstring getSEName();
+
+ virtual std::wstring getNexusPage();
+ static std::wstring getNexusInfoUrlStatic();
+ virtual std::wstring getNexusInfoUrl() { return FalloutNVInfo::getNexusInfoUrlStatic(); }
+ static int getNexusModIDStatic();
+ virtual int getNexusModID() { return FalloutNVInfo::getNexusModIDStatic(); }
+
+ virtual void createProfile(const std::wstring &directory, bool useDefaults);
+ virtual void repairProfile(const std::wstring &directory);
+
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+
+ // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
+ // the game directory
+ virtual std::vector<ExecutableInfo> getExecutables();
+
+ virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+
+private:
+
+ FalloutNVInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory);
+
+ static bool identifyGame(const std::wstring &searchPath);
+};
+
+#endif // FALLOUTNVINFO_H
diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp new file mode 100644 index 00000000..6054df8b --- /dev/null +++ b/src/shared/gameinfo.cpp @@ -0,0 +1,204 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "gameinfo.h"
+
+#include "windows_error.h"
+
+#include "oblivioninfo.h"
+#include "fallout3info.h"
+#include "falloutnvinfo.h"
+#include "skyriminfo.h"
+#include "util.h"
+
+#include <shlobj.h>
+#include <sstream>
+#include <cassert>
+
+
+GameInfo* GameInfo::s_Instance = NULL;
+
+
+GameInfo::GameInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
+ : m_GameDirectory(gameDirectory), m_OrganizerDirectory(omoDirectory)
+{
+}
+
+
+void GameInfo::identifyMyGamesDirectory(const std::wstring &file)
+{
+ wchar_t myDocuments[MAX_PATH];
+ memset(myDocuments, '\0', MAX_PATH);
+
+ ::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocuments);
+
+ m_MyGamesDirectory.assign(myDocuments).append(L"\\My Games");
+ if (!FileExists(m_MyGamesDirectory.substr().append(L"/").append(file))) {
+ if (::SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_DEFAULT, myDocuments) != S_OK) {
+ m_MyGamesDirectory.assign(myDocuments).append(L"\\My Games");
+ }
+ }
+ if (!FileExists(m_MyGamesDirectory.substr().append(L"/").append(file))) {
+ m_MyGamesDirectory.assign(getSpecialPath(L"Personal")).append(L"\\My Games");
+ }
+}
+
+
+bool GameInfo::identifyGame(const std::wstring &omoDirectory, const std::wstring &searchPath)
+{
+ if (OblivionInfo::identifyGame(searchPath)) {
+ s_Instance = new OblivionInfo(omoDirectory, searchPath);
+ } else if (Fallout3Info::identifyGame(searchPath)) {
+ s_Instance = new Fallout3Info(omoDirectory, searchPath);
+ } else if (FalloutNVInfo::identifyGame(searchPath)) {
+ s_Instance = new FalloutNVInfo(omoDirectory, searchPath);
+ } else if (SkyrimInfo::identifyGame(searchPath)) {
+ s_Instance = new SkyrimInfo(omoDirectory, searchPath);
+ }
+
+ return s_Instance != NULL;
+}
+
+
+bool GameInfo::init(const std::wstring &omoDirectory, const std::wstring &gamePath)
+{
+ if (s_Instance == NULL) {
+ if (gamePath.length() == 0) {
+ // search upward in the directory until a recognized game-binary is found
+ std::wstring searchPath(omoDirectory);
+ while (!identifyGame(omoDirectory, searchPath)) {
+ size_t lastSep = searchPath.find_last_of(L"/\\");
+ if (lastSep == std::string::npos) {
+ return false;
+ }
+ searchPath.erase(lastSep);
+ }
+ } else if (!identifyGame(omoDirectory, gamePath)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+GameInfo &GameInfo::instance()
+{
+ assert(s_Instance != NULL);
+ return *s_Instance;
+}
+
+std::wstring GameInfo::getGameDirectory() const
+{
+ return m_GameDirectory;
+}
+
+std::wstring GameInfo::getModsDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << L"\\mods";
+ return temp.str();
+}
+
+std::wstring GameInfo::getProfilesDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << L"\\profiles";
+ return temp.str();
+}
+
+std::wstring GameInfo::getIniFilename() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << L"\\ModOrganizer.ini";
+ return temp.str();
+}
+
+
+std::wstring GameInfo::getDownloadDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << L"\\downloads";
+ return temp.str();
+}
+
+
+std::wstring GameInfo::getCacheDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << L"\\webcache";
+ return temp.str();
+}
+
+
+std::wstring GameInfo::getOverwriteDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << "\\overwrite";
+ return temp.str();
+}
+
+
+std::wstring GameInfo::getLogDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << "\\logs";
+ return temp.str();
+}
+
+
+std::wstring GameInfo::getTutorialDir() const
+{
+ std::wostringstream temp;
+ temp << m_OrganizerDirectory << "\\tutorials";
+ return temp.str();
+}
+
+
+bool GameInfo::requiresSteam() const
+{
+ return FileExists(getGameDirectory().append(L"\\steam_api.dll"));
+}
+
+
+std::wstring GameInfo::getLocalAppFolder() const
+{
+ return getSpecialPath(L"Local AppData");
+}
+
+std::wstring GameInfo::getSpecialPath(LPCWSTR name) const
+{
+ HKEY key;
+ LONG errorcode = ::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
+ 0, KEY_QUERY_VALUE, &key);
+
+ if (errorcode != ERROR_SUCCESS) {
+ throw windows_error("failed to look up special folder", errorcode);
+ }
+
+ WCHAR temp[MAX_PATH];
+ DWORD bufferSize = MAX_PATH;
+
+ errorcode = ::RegQueryValueExW(key, name, NULL, NULL, (LPBYTE)temp, &bufferSize);
+ if (errorcode != ERROR_SUCCESS) {
+ throw windows_error("failed to look up special folder", errorcode);
+ }
+
+ return temp;
+}
+
diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h new file mode 100644 index 00000000..8828a2fc --- /dev/null +++ b/src/shared/gameinfo.h @@ -0,0 +1,187 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef GAMEINFO_H
+#define GAMEINFO_H
+
+#include <string>
+#include <vector>
+#include <wchar.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+enum CloseMOStyle {
+ DEFAULT_CLOSE,
+ DEFAULT_STAY,
+ NEVER_CLOSE
+};
+
+struct ExecutableInfo {
+
+ ExecutableInfo(const std::wstring &aTitle, const std::wstring &aBinary,
+ const std::wstring &aArguments, const std::wstring &aWorkingDirectory, CloseMOStyle aCloseMO)
+ : title(aTitle), binary(aBinary), arguments(aArguments), workingDirectory(aWorkingDirectory),
+ closeMO(aCloseMO), steamAppID(L"") {}
+ ExecutableInfo(const std::wstring &aTitle, const std::wstring &aBinary,
+ const std::wstring &aArguments, const std::wstring &aWorkingDirectory,
+ CloseMOStyle aCloseMO, const std::wstring &aSteamAppID)
+ : title(aTitle), binary(aBinary), arguments(aArguments), workingDirectory(aWorkingDirectory),
+ closeMO(aCloseMO), steamAppID(aSteamAppID) {}
+ std::wstring title;
+ std::wstring binary;
+ std::wstring arguments;
+ std::wstring workingDirectory;
+ CloseMOStyle closeMO;
+ std::wstring steamAppID;
+};
+
+
+/**
+ Class to manage information that depends on the used game type. The intention is to keep
+ as much of the rest of omo is game-agnostic. It is mostly concerned with figuring out the
+ correct paths, filenames and data types.
+*/
+class GameInfo
+{
+
+public:
+
+ enum Type {
+ TYPE_OBLIVION,
+ TYPE_FALLOUT3,
+ TYPE_FALLOUTNV,
+ TYPE_SKYRIM
+ };
+
+ enum LoadOrderMechanism {
+ TYPE_FILETIME,
+ TYPE_PLUGINSTXT
+ };
+
+public:
+
+ virtual ~GameInfo() {}
+
+ std::wstring getOrganizerDirectory() { return m_OrganizerDirectory; }
+
+ virtual std::wstring getRegPath() = 0;
+ virtual std::wstring getBinaryName() = 0;
+
+ virtual unsigned long getBSAVersion() = 0;
+
+ virtual GameInfo::Type getType() = 0;
+
+ virtual std::wstring getGameName() const = 0;
+ virtual std::wstring getGameShortName() const = 0;
+
+ // full path to this games "My Games"-directory
+ virtual std::wstring getDocumentsDir() = 0;
+
+ virtual std::wstring getSaveGameDir() = 0;
+
+ /// determine the load order mechanism used by this game. this may throw an
+ /// exception if the mechanism can't be determined
+ virtual LoadOrderMechanism getLoadOrderMechanism() const { return TYPE_FILETIME; }
+
+ virtual std::wstring getGameDirectory() const;
+ // get absolute path to the directory where omo stores its mods
+ virtual std::wstring getModsDir() const;
+ // get absolute path to the directory where omo stores its profiles
+ virtual std::wstring getProfilesDir() const;
+
+ virtual std::wstring getIniFilename() const;
+ virtual std::wstring getDownloadDir() const;
+ virtual std::wstring getCacheDir() const;
+ virtual std::wstring getOverwriteDir() const;
+ virtual std::wstring getLogDir() const;
+ virtual std::wstring getTutorialDir() const;
+
+ virtual bool requiresBSAInvalidation() const { return true; }
+ virtual bool requiresSteam() const;
+
+ virtual std::wstring getInvalidationBSA() = 0;
+
+ virtual bool isInvalidationBSA(const std::wstring &bsaName) = 0;
+
+ // the key in the game's ini-file that defines the list of bsas to load
+ virtual std::wstring archiveListKey() = 0;
+
+ virtual std::vector<std::wstring> getPrimaryPlugins() = 0;
+
+ // file name of this games ini file(s)
+ virtual std::vector<std::wstring> getIniFileNames() = 0;
+
+ virtual std::wstring getSaveGameExtension() = 0;
+ virtual std::wstring getReferenceDataFile() = 0;
+
+ virtual std::wstring getOMODExt() = 0;
+
+ virtual std::wstring getSteamAPPId() = 0;
+
+ virtual std::wstring getSEName() = 0;
+
+ virtual std::wstring getNexusPage() = 0;
+ virtual std::wstring getNexusInfoUrl() = 0;
+ virtual int getNexusModID() = 0;
+
+ // clone relevant files to the specified directory
+ virtual void createProfile(const std::wstring &directory, bool useDefaults) = 0;
+ virtual void repairProfile(const std::wstring &directory) = 0;
+
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) = 0;
+
+ // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
+ // the game directory. the boolean says whether omo should be closed when the executable is started
+ virtual std::vector<ExecutableInfo> getExecutables() = 0;
+
+public:
+
+ // initialise with the path to the omo directory (needs to be where hook.dll is stored). This
+ // needs to be called before the instance can be retrieved
+ static bool init(const std::wstring &omoDirectory, const std::wstring &gamePath = L"");
+
+ static GameInfo& instance();
+
+protected:
+
+ GameInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory);
+
+ std::wstring getLocalAppFolder() const;
+ const std::wstring &getMyGamesDirectory() const { return m_MyGamesDirectory; }
+ void identifyMyGamesDirectory(const std::wstring &file);
+
+private:
+
+ static bool identifyGame(const std::wstring &omoDirectory, const std::wstring &searchPath);
+ std::wstring getSpecialPath(LPCWSTR name) const;
+
+private:
+
+ static GameInfo* s_Instance;
+
+ std::wstring m_MyGamesDirectory;
+
+ std::wstring m_GameDirectory;
+ std::wstring m_OrganizerDirectory;
+
+};
+
+
+#endif // GAMEINFO_H
diff --git a/src/shared/inject.cpp b/src/shared/inject.cpp new file mode 100644 index 00000000..8cedd247 --- /dev/null +++ b/src/shared/inject.cpp @@ -0,0 +1,142 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "inject.h"
+/*#if defined UNICODE && !defined _UNICODE
+#define _UNICODE 1
+#endif*/
+#include <wchar.h>
+#include <cstdio>
+#include <tchar.h>
+#include <cstdlib>
+#include <exception>
+#include <stdexcept>
+#include <string>
+#include "windows_error.h"
+#include "error_report.h"
+
+
+struct TParameters {
+ char dllname[MAX_PATH];
+ wchar_t profileName[101];
+ char initstr[5];
+ int logLevel;
+};
+
+
+typedef HMODULE (WINAPI *TLoadLibraryType)(LPCTSTR);
+typedef FARPROC (WINAPI *TGetProcAddressType)(HMODULE, LPCSTR);
+
+
+
+void injectDLL(HANDLE processHandle, HANDLE threadHandle, const std::string &dllname, const std::wstring &profileName, int logLevel)
+{
+ // prepare parameters that are to be passed to the injected dll
+ TParameters parameters;
+ memset(¶meters, '\0', sizeof(TParameters));
+ strncpy(parameters.dllname, dllname.c_str(), MAX_PATH - 1);
+ wcsncpy(parameters.profileName, profileName.c_str(), 100);
+ _snprintf(parameters.initstr, 5, "Init"); //this is the name of thie initialisation function we want to call in the target process
+
+ HMODULE k32mod = ::LoadLibrary(__TEXT("kernel32.dll"));
+ TLoadLibraryType loadLibraryFunc = NULL;
+ TGetProcAddressType getProcAddressFunc = NULL;
+ // ansi binaries
+ if (k32mod != NULL) {
+ loadLibraryFunc = reinterpret_cast<TLoadLibraryType>(::GetProcAddress(k32mod, "LoadLibraryA"));
+ getProcAddressFunc = reinterpret_cast<TGetProcAddressType>(::GetProcAddress(k32mod, "GetProcAddress"));
+ if ((loadLibraryFunc == NULL) || (getProcAddressFunc == NULL)) {
+ throw windows_error("failed to determine address for required functions");
+ }
+ } else {
+ throw windows_error("kernel32.dll not loaded??");
+ }
+
+ // allocate memory in the target process and write the parameter-block there
+ LPVOID remoteMem = ::VirtualAllocEx(processHandle, NULL, sizeof(TParameters), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if (remoteMem == NULL) {
+ throw windows_error("failed to allocate memory in target process");
+ }
+ SIZE_T written;
+ if (!::WriteProcessMemory(processHandle, remoteMem, ¶meters, sizeof(TParameters), &written) ||
+ (written != sizeof(TParameters))) {
+ throw windows_error("failed to write parameters to target process");
+ }
+
+ // now for the interesting part: write a stub into the target process that is run before any code of the original binary. This code will load
+ // our injected dll into the process and run its Init-function which takes the profile name as its parameter
+ // obviously this code is ultra-hacky
+
+ // construct the stub in beautiful assembler with placeholders
+ BYTE stubLocal[] = { 0x60, // PUSHAD
+ 0xB8, 0xBA, 0xAD, 0xF0, 0x0D, // MOV EAX, imm32 (LoadLibrary)
+ 0x68, 0xBA, 0xAD, 0xF0, 0x0D, // PUSH imm32 (dllname)
+ 0xFF, 0xD0, // CALL EAX (=LoadLibrary, leaves module handle of our dll in eax)
+ 0x68, 0xBA, 0xAD, 0xF0, 0x0D, // PUSH imm32 ("Init")
+ 0x50, // PUSH EAX
+ 0xB8, 0xBA, 0xAD, 0xF0, 0x0D, // MOVE EAX, imm32 (GetProcAddress)
+ 0xFF, 0xD0, // CALL EAX (GetProcAddress)
+ 0x68, 0xBA, 0xAD, 0xF0, 0x0D, // PUSH imm32 (profile name)
+ 0x68, 0xBA, 0xAD, 0xF0, 0x0D, // PUSH imm32 (log level)
+ 0xFF, 0xD0, // CALL EAX (=InitFunction)
+ 0x58, // POP EAX (init function is defined cdecl)
+ 0x58, // POP EAX (init function is defined cdecl)
+ 0x61, // POPAD
+ 0xE9, 0xBA, 0xAD, 0xF0, 0x0D // JMP near, relative (=original entry point)
+ };
+
+ // reserve memory for the stub
+ PBYTE stubRemote = reinterpret_cast<PBYTE>(::VirtualAllocEx(processHandle, NULL, sizeof(stubLocal), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
+ if (stubRemote == NULL) {
+ throw windows_error("failed to allocate memory for stub");
+ }
+ TParameters *remoteParams = reinterpret_cast<TParameters*>(remoteMem);
+ // determine the remote addresses of each of the parameters
+// ULONG remoteDLLName = reinterpret_cast<ULONG>(remoteMem);
+// ULONG remoteInitString = remoteDLLName + MAX_PATH * sizeof(char);
+
+ // dizzy yet? we still have to calculate the entry point as an address relative to our stub
+ ULONG entryPoint = 0;
+
+ CONTEXT threadContext;
+ threadContext.ContextFlags = CONTEXT_CONTROL;
+ if (::GetThreadContext(threadHandle, &threadContext) == 0) {
+ throw windows_error("failed to access thread context. Please note that Mod Organizer does not support 64bit binaries!");
+ } else {
+ entryPoint = threadContext.Eip - (reinterpret_cast<ULONG>(stubRemote) + sizeof(stubLocal));
+ }
+ // now replace each baadf00d by the correct value. The pointers need to be the pointers in the REMOTE memory of course, that's why we copied them there
+ *(PULONG)&stubLocal[2] = reinterpret_cast<ULONG>(*loadLibraryFunc);
+ *(PULONG)&stubLocal[7] = reinterpret_cast<ULONG>(remoteParams->dllname);
+ *(PULONG)&stubLocal[14] = reinterpret_cast<ULONG>(remoteParams->initstr);
+ *(PULONG)&stubLocal[20] = reinterpret_cast<ULONG>(*getProcAddressFunc);
+ *(PULONG)&stubLocal[27] = reinterpret_cast<ULONG>(remoteParams->profileName);
+ *(PULONG)&stubLocal[32] = logLevel;
+ *(PULONG)&stubLocal[42] = entryPoint;
+ // almost there. copy stub to target process
+ if (!::WriteProcessMemory(processHandle, stubRemote, reinterpret_cast<LPCVOID>(stubLocal), sizeof(stubLocal), &written) ||
+ (written != sizeof(stubLocal))) {
+ throw windows_error("failed to write stub to target process");
+ }
+ // finally, make the stub the new next thing for the thread to execute
+ threadContext.Eip = (ULONG)stubRemote;
+ if (::SetThreadContext(threadHandle, &threadContext) == 0) {
+ throw windows_error("failed to overwrite thread context");
+ }
+}
diff --git a/src/shared/inject.h b/src/shared/inject.h new file mode 100644 index 00000000..69c56cc6 --- /dev/null +++ b/src/shared/inject.h @@ -0,0 +1,27 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <string>
+
+void injectDLL(HANDLE processHandle, HANDLE threadHandle, const std::string &dllname, const std::wstring &profileName, int logLevel);
diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp new file mode 100644 index 00000000..c34b2202 --- /dev/null +++ b/src/shared/oblivioninfo.cpp @@ -0,0 +1,252 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "oblivioninfo.h"
+#include <tchar.h>
+#include <ShlObj.h>
+#include "util.h"
+#include <sstream>
+#include "windows_error.h"
+#include "error_report.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <boost/assign.hpp>
+
+
+OblivionInfo::OblivionInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
+ : GameInfo(omoDirectory, gameDirectory)
+{
+ identifyMyGamesDirectory(L"oblivion");
+}
+
+bool OblivionInfo::identifyGame(const std::wstring &searchPath)
+{
+ return FileExists(searchPath, L"Oblivion.exe") &&
+ FileExists(searchPath, L"OblivionLauncher.exe");
+}
+
+unsigned long OblivionInfo::getBSAVersion()
+{
+ return 0x67;
+}
+
+std::wstring OblivionInfo::getRegPathStatic()
+{
+ HKEY key;
+ LONG errorcode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Bethesda Softworks\\Oblivion",
+ 0, KEY_QUERY_VALUE, &key);
+
+ if (errorcode != ERROR_SUCCESS) {
+ return L"";
+ }
+
+ WCHAR temp[MAX_PATH];
+ DWORD bufferSize = MAX_PATH;
+
+ errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize);
+
+ return std::wstring(temp);
+}
+
+std::wstring OblivionInfo::getInvalidationBSA()
+{
+ return L"Oblivion - Invalidation.bsa";
+}
+
+bool OblivionInfo::isInvalidationBSA(const std::wstring &bsaName)
+{
+ static LPCWSTR invalidation[] = { L"Oblivion - Invalidation.bsa", L"ArchiveInvalidationInvalidated!.bsa",
+ L"BSARedirection.bsa", NULL };
+
+ for (int i = 0; invalidation[i] != NULL; ++i) {
+ if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::wstring OblivionInfo::getDocumentsDir()
+{
+ std::wostringstream temp;
+ temp << getMyGamesDirectory() << L"\\Oblivion";
+
+ return temp.str();
+}
+
+std::wstring OblivionInfo::getSaveGameDir()
+{
+ std::wostringstream temp;
+ temp << getDocumentsDir() << L"\\Saves";
+ return temp.str();
+}
+
+
+std::vector<std::wstring> OblivionInfo::getPrimaryPlugins()
+{
+ return boost::assign::list_of(L"oblivion.esm");
+}
+
+
+std::vector<std::wstring> OblivionInfo::getIniFileNames()
+{
+ return boost::assign::list_of(L"oblivion.ini")(L"oblivionprefs.ini");
+}
+
+
+void OblivionInfo::createProfile(const std::wstring &directory, bool useDefaults)
+{
+ std::wostringstream target;
+
+ // copy plugins.txt
+ target << directory << "\\plugins.txt";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ source << getLocalAppFolder() << "\\Oblivion\\plugins.txt";
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CloseHandle(file);
+ }
+ }
+
+ // copy ini-file
+ target.str(L""); target.clear();
+ target << directory << L"\\oblivion.ini";
+
+ if (!FileExists(target.str())) {
+ std::wostringstream source;
+ source << getMyGamesDirectory() << L"\\Oblivion\\oblivion.ini";
+ if (useDefaults) {
+ source << getGameDirectory() << L"\\oblivion_default.ini";
+ } else {
+ source << getMyGamesDirectory() << L"Oblivion";
+ if (::FileExists(source.str(), L"oblivion.ini")) {
+ source << L"\\oblivion.ini";
+ } else {
+ source.str(L"");
+ source << getGameDirectory() << L"\\oblivion_default.ini";
+ }
+ }
+ if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+
+ { // copy oblivionprefs.ini-file
+ std::wstring target = directory.substr().append(L"\\oblivionprefs.ini");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getMyGamesDirectory() << L"\\Oblivion\\oblivionprefs.ini";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ if ((::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL) == INVALID_HANDLE_VALUE) &&
+ (::GetLastError() != ERROR_FILE_EXISTS)) {
+ std::ostringstream stream;
+ stream << "failed to create ini file: " << ToString(target.c_str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ }
+}
+
+
+std::wstring OblivionInfo::getSEName()
+{
+ return L"obse";
+}
+
+
+std::wstring OblivionInfo::getNexusPage()
+{
+ return L"http://oblivion.nexusmods.com";
+}
+
+
+std::wstring OblivionInfo::getNexusInfoUrlStatic()
+{
+ return L"http://oblivion.nexusmods.com";
+}
+
+
+int OblivionInfo::getNexusModIDStatic()
+{
+ return 38277;
+}
+
+
+void OblivionInfo::repairProfile(const std::wstring &directory)
+{
+ createProfile(directory, false);
+}
+
+
+bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+{
+ static LPCWSTR profileFiles[] = { L"oblivion.ini", L"oblivionprefs.ini", L"plugins.txt", NULL };
+
+ for (int i = 0; profileFiles[i] != NULL; ++i) {
+ if (_wcsicmp(fileName, profileFiles[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+std::wstring OblivionInfo::getSaveGameExtension()
+{
+ return L"*.ess";
+}
+
+std::wstring OblivionInfo::getReferenceDataFile()
+{
+ return L"Oblivion - Meshes.bsa";
+}
+
+
+std::wstring OblivionInfo::getOMODExt()
+{
+ return L"omod";
+}
+
+
+std::wstring OblivionInfo::getSteamAPPId()
+{
+ return L"22330";
+}
+
+
+std::vector<ExecutableInfo> OblivionInfo::getExecutables()
+{
+ std::vector<ExecutableInfo> result;
+ result.push_back(ExecutableInfo(L"OBSE", L"obse_loader.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Oblivion", L"oblivion.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Oblivion Mod Manager", L"OblivionModManager.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Construction Set", L"TESConstructionSet.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Oblivion Launcher", L"OblivionLauncher.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", NEVER_CLOSE));
+ result.push_back(ExecutableInfo(L"BOSS (old)", L"Data/BOSS.exe", L"", L"", NEVER_CLOSE));
+
+ return result;
+}
diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h new file mode 100644 index 00000000..0d6bba65 --- /dev/null +++ b/src/shared/oblivioninfo.h @@ -0,0 +1,92 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef OBLIVIONINFO_H
+#define OBLIVIONINFO_H
+
+#include "gameinfo.h"
+
+class OblivionInfo : public GameInfo
+{
+
+ friend class GameInfo;
+
+public:
+
+ virtual ~OblivionInfo() {}
+
+ virtual unsigned long getBSAVersion();
+
+ static std::wstring getRegPathStatic();
+ virtual std::wstring getRegPath() { return OblivionInfo::getRegPathStatic(); }
+ virtual std::wstring getBinaryName() { return L"Oblivion.exe"; }
+
+ virtual GameInfo::Type getType() { return TYPE_OBLIVION; }
+
+ virtual std::wstring getGameName() const { return L"Oblivion"; }
+ virtual std::wstring getGameShortName() const { return L"Oblivion"; }
+
+ virtual std::wstring getInvalidationBSA();
+
+ virtual bool isInvalidationBSA(const std::wstring &bsaName);
+
+ // full path to this games "My Games"-directory
+ virtual std::wstring getDocumentsDir();
+
+ virtual std::wstring getSaveGameDir();
+
+ virtual std::vector<std::wstring> getPrimaryPlugins();
+
+ // file name of this games ini (no path)
+ virtual std::vector<std::wstring> getIniFileNames();
+
+ virtual std::wstring getSaveGameExtension();
+ virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getOMODExt();
+
+ virtual std::wstring getSteamAPPId();
+
+ virtual std::wstring getSEName();
+
+ virtual std::wstring getNexusPage();
+ static std::wstring getNexusInfoUrlStatic();
+ virtual std::wstring getNexusInfoUrl() { return OblivionInfo::getNexusInfoUrlStatic(); }
+ static int getNexusModIDStatic();
+ virtual int getNexusModID() { return OblivionInfo::getNexusModIDStatic(); }
+
+ virtual void createProfile(const std::wstring &directory, bool useDefaults);
+ virtual void repairProfile(const std::wstring &directory);
+
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+
+ // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
+ // the game directory
+ virtual std::vector<ExecutableInfo> getExecutables();
+
+ virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+
+private:
+
+ OblivionInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory);
+
+ static bool identifyGame(const std::wstring &searchPath);
+
+};
+
+#endif // OBLIVIONINFO_H
diff --git a/src/shared/shared.pro b/src/shared/shared.pro new file mode 100644 index 00000000..3e1283e6 --- /dev/null +++ b/src/shared/shared.pro @@ -0,0 +1,56 @@ +#-------------------------------------------------
+#
+# Project created by QtCreator 2011-05-03T18:35:56
+#
+#-------------------------------------------------
+
+QT -= gui core
+#QT += core
+
+TARGET = mo_shared
+TEMPLATE = lib
+CONFIG += staticlib
+
+INCLUDEPATH += ../../../bsatk "$(BOOSTPATH)"
+
+CONFIG(debug, debug|release) {
+ LIBS += -L../../../bsatk-build/debug
+
+} else {
+ LIBS += -L../../../bsatk-build/release
+}
+
+LIBS += -lbsatk
+
+DEFINES += UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS
+
+DEFINES += BOOST_DISABLE_ASSERTS NDEBUG
+
+# QMAKE_CXXFLAGS += /analyze
+
+SOURCES += \
+ inject.cpp \
+ windows_error.cpp \
+ error_report.cpp \
+ directoryentry.cpp \
+ gameinfo.cpp \
+ oblivioninfo.cpp \
+ fallout3info.cpp \
+ falloutnvinfo.cpp \
+ util.cpp \
+ skyriminfo.cpp \
+ appconfig.cpp
+
+HEADERS += \
+ inject.h \
+ windows_error.h \
+ error_report.h \
+ directoryentry.h \
+ gameinfo.h \
+ oblivioninfo.h \
+ fallout3info.h \
+ falloutnvinfo.h \
+ util.h \
+ skyriminfo.h \
+ appconfig.h \
+ appconfig.inc
diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp new file mode 100644 index 00000000..f3043c28 --- /dev/null +++ b/src/shared/skyriminfo.cpp @@ -0,0 +1,278 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "skyriminfo.h"
+
+#include "util.h"
+#include <tchar.h>
+#include <ShlObj.h>
+#include <sstream>
+#include "windows_error.h"
+#include "error_report.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <boost/assign.hpp>
+
+
+SkyrimInfo::SkyrimInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory)
+ : GameInfo(omoDirectory, gameDirectory)
+{
+ identifyMyGamesDirectory(L"skyrim");
+}
+
+bool SkyrimInfo::identifyGame(const std::wstring &searchPath)
+{
+ return FileExists(searchPath, L"TESV.exe") &&
+ FileExists(searchPath, L"SkyrimLauncher.exe");
+}
+
+unsigned long SkyrimInfo::getBSAVersion()
+{
+ return 0x68;
+}
+
+
+std::wstring SkyrimInfo::getRegPathStatic()
+{
+ HKEY key;
+ LONG errorcode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Bethesda Softworks\\Skyrim",
+ 0, KEY_QUERY_VALUE, &key);
+
+ if (errorcode != ERROR_SUCCESS) {
+ return L"";
+ }
+
+ WCHAR temp[MAX_PATH];
+ DWORD bufferSize = MAX_PATH;
+
+ errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize);
+
+ return std::wstring(temp);
+}
+
+
+std::wstring SkyrimInfo::getInvalidationBSA()
+{
+ return L"Skyrim - Invalidation.bsa";
+}
+
+bool SkyrimInfo::isInvalidationBSA(const std::wstring &bsaName)
+{
+ static LPCWSTR invalidation[] = { L"Skyrim - Invalidation.bsa", NULL };
+
+ for (int i = 0; invalidation[i] != NULL; ++i) {
+ if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const
+{
+ std::wstring fileName = getGameDirectory().append(L"\\TESV.exe");
+
+ try {
+ VS_FIXEDFILEINFO versionInfo = GetFileVersion(fileName);
+ if ((versionInfo.dwFileVersionMS > 0x10004) || // version >= 1.5.x?
+ ((versionInfo.dwFileVersionMS == 0x10004) && (versionInfo.dwFileVersionLS >= 0x1A0000))) { // version >= ?.4.26
+ return TYPE_PLUGINSTXT;
+ } else {
+ return TYPE_FILETIME;
+ }
+ } catch (const std::exception &e) {
+ reportError("TESV.exe is invalid: %s", e.what());
+ return TYPE_FILETIME;
+ }
+}
+
+std::wstring SkyrimInfo::getDocumentsDir()
+{
+ std::wostringstream temp;
+ temp << getMyGamesDirectory() << L"\\Skyrim";
+
+ return temp.str();
+}
+
+std::wstring SkyrimInfo::getSaveGameDir()
+{
+ std::wostringstream temp;
+ temp << getDocumentsDir() << L"\\Saves";
+ return temp.str();
+}
+
+std::vector<std::wstring> SkyrimInfo::getPrimaryPlugins()
+{
+ return boost::assign::list_of(L"skyrim.esm")(L"update.esm");
+}
+
+std::vector<std::wstring> SkyrimInfo::getIniFileNames()
+{
+ return boost::assign::list_of(L"skyrim.ini")(L"skyrimprefs.ini");
+}
+
+std::wstring SkyrimInfo::getSaveGameExtension()
+{
+ return L"*.ess";
+}
+
+std::wstring SkyrimInfo::getReferenceDataFile()
+{
+ return L"Skyrim - Meshes.bsa";
+}
+
+
+std::wstring SkyrimInfo::getOMODExt()
+{
+ return L"fomod";
+}
+
+
+std::wstring SkyrimInfo::getSteamAPPId()
+{
+ return L"72850";
+}
+
+
+std::wstring SkyrimInfo::getSEName()
+{
+ return L"skse";
+}
+
+
+std::wstring SkyrimInfo::getNexusPage()
+{
+ return L"http://skyrim.nexusmods.com";
+}
+
+
+std::wstring SkyrimInfo::getNexusInfoUrlStatic()
+{
+ return L"http://skyrim.nexusmods.com";
+}
+
+
+int SkyrimInfo::getNexusModIDStatic()
+{
+ return 1334;
+}
+
+
+void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults)
+{
+ { // copy plugins.txt
+ std::wstring target = directory.substr().append(L"\\plugins.txt");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getLocalAppFolder() << "\\Skyrim\\plugins.txt";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CloseHandle(file);
+ }
+ }
+ target = directory.substr().append(L"\\loadorder.txt");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getLocalAppFolder() << "\\Skyrim\\loadorder.txt";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CloseHandle(file);
+ }
+ }
+ }
+
+ { // copy skyrim.ini-file
+ std::wstring target = directory.substr().append(L"\\skyrim.ini");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ if (useDefaults) {
+ source << getGameDirectory() << L"\\skyrim_default.ini";
+ } else {
+ source << getMyGamesDirectory() << L"\\Skyrim";
+ if (::FileExists(source.str(), L"skyrim.ini")) {
+ source << L"\\skyrim.ini";
+ } else {
+ source.str(L"");
+ source << getGameDirectory() << L"\\skyrim_default.ini";
+ }
+ }
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ }
+
+ { // copy skyrimprefs.ini-file
+ std::wstring target = directory.substr().append(L"\\skyrimprefs.ini");
+ if (!FileExists(target)) {
+ std::wostringstream source;
+ source << getMyGamesDirectory() << L"\\Skyrim\\skyrimprefs.ini";
+ if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) {
+ if (::GetLastError() != ERROR_FILE_EXISTS) {
+ std::ostringstream stream;
+ stream << "failed to copy ini file: " << ToString(source.str(), false);
+ throw windows_error(stream.str());
+ }
+ }
+ }
+ }
+}
+
+
+void SkyrimInfo::repairProfile(const std::wstring &directory)
+{
+ createProfile(directory, false);
+}
+
+
+bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath)
+{
+ static LPCWSTR profileFiles[] = { L"skyrim.ini", L"skyrimprefs.ini", L"loadorder.txt", NULL };
+
+ for (int i = 0; profileFiles[i] != NULL; ++i) {
+ if (_wcsicmp(fileName, profileFiles[i]) == 0) {
+ return true;
+ }
+ }
+
+ if ((_wcsicmp(fileName, L"plugins.txt") == 0) &&
+ (wcsstr(fullPath, L"AppData") != NULL)){
+ return true;
+ }
+
+ return false;
+}
+
+
+std::vector<ExecutableInfo> SkyrimInfo::getExecutables()
+{
+ std::vector<ExecutableInfo> result;
+ result.push_back(ExecutableInfo(L"SKSE", L"skse_loader.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"SBW", L"SBW.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"Skyrim", L"TESV.exe", L"", L"", DEFAULT_CLOSE));
+ result.push_back(ExecutableInfo(L"BOSS", L"BOSS/BOSS.exe", L"", L"", DEFAULT_STAY));
+ result.push_back(ExecutableInfo(L"Creation Kit", L"CreationKit.exe", L"", L"", DEFAULT_STAY, L"202480"));
+
+ return result;
+}
diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h new file mode 100644 index 00000000..25de4029 --- /dev/null +++ b/src/shared/skyriminfo.h @@ -0,0 +1,100 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SKYRIMINFO_H
+#define SKYRIMINFO_H
+
+
+#include "gameinfo.h"
+
+
+class SkyrimInfo : public GameInfo
+{
+
+ friend class GameInfo;
+
+public:
+
+ virtual ~SkyrimInfo() {}
+
+ virtual unsigned long getBSAVersion();
+
+ static std::wstring getRegPathStatic();
+ virtual std::wstring getRegPath() { return SkyrimInfo::getRegPathStatic(); }
+ virtual std::wstring getBinaryName() { return L"TESV.exe"; }
+
+ virtual GameInfo::Type getType() { return TYPE_SKYRIM; }
+
+ virtual std::wstring getGameName() const { return L"Skyrim"; }
+ virtual std::wstring getGameShortName() const { return L"Skyrim"; }
+
+ virtual LoadOrderMechanism getLoadOrderMechanism() const;
+
+ virtual bool requiresBSAInvalidation() const { return true; }
+// virtual bool requiresSteam() const { return true; }
+
+ virtual std::wstring getInvalidationBSA();
+
+ virtual bool isInvalidationBSA(const std::wstring &bsaName);
+
+ // full path to this games "My Games"-directory
+ virtual std::wstring getDocumentsDir();
+
+ virtual std::wstring getSaveGameDir();
+
+ virtual std::vector<std::wstring> getPrimaryPlugins();
+
+ // file name of this games ini (no path)
+ virtual std::vector<std::wstring> getIniFileNames();
+
+ virtual std::wstring getSaveGameExtension();
+ virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getOMODExt();
+
+ virtual std::wstring getSteamAPPId();
+
+ virtual std::wstring getSEName();
+
+ virtual std::wstring getNexusPage();
+
+ static std::wstring getNexusInfoUrlStatic();
+ virtual std::wstring getNexusInfoUrl() { return SkyrimInfo::getNexusInfoUrlStatic(); }
+ static int getNexusModIDStatic();
+ virtual int getNexusModID() { return SkyrimInfo::getNexusModIDStatic(); }
+
+ virtual void createProfile(const std::wstring &directory, bool useDefaults);
+ virtual void repairProfile(const std::wstring &directory);
+
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+
+ // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
+ // the game directory
+ virtual std::vector<ExecutableInfo> getExecutables();
+
+ virtual std::wstring archiveListKey() { return L"SResourceArchiveList"; }
+
+private:
+
+ SkyrimInfo(const std::wstring &omoDirectory, const std::wstring &gameDirectory);
+
+ static bool identifyGame(const std::wstring &searchPath);
+
+};
+
+#endif // SKYRIMINFO_H
diff --git a/src/shared/util.cpp b/src/shared/util.cpp new file mode 100644 index 00000000..ec52dd38 --- /dev/null +++ b/src/shared/util.cpp @@ -0,0 +1,119 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "util.h"
+#include "windows_error.h"
+#include <sstream>
+#include <algorithm>
+
+
+bool FileExists(const std::wstring &filename)
+{
+ WIN32_FIND_DATAW findData;
+ ZeroMemory(&findData, sizeof(WIN32_FIND_DATAW));
+ HANDLE search = ::FindFirstFileExW(filename.c_str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0);
+ if (search == INVALID_HANDLE_VALUE) {
+ return false;
+ } else {
+ FindClose(search);
+ return true;
+ }
+}
+
+bool FileExists(const std::wstring &searchPath, const std::wstring &filename)
+{
+ std::wstringstream stream;
+ stream << searchPath << "\\" << filename;
+ return FileExists(stream.str());
+}
+
+std::string ToString(const std::wstring &source, bool utf8)
+{
+ char buffer[MAX_PATH];
+ if (utf8) {
+ ::WideCharToMultiByte(CP_UTF8, 0, source.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
+ } else {
+ ::WideCharToMultiByte(GetACP(), 0, source.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
+// wcstombs(buffer, source.c_str(), MAX_PATH);
+ }
+ return std::string(buffer);
+}
+
+std::wstring ToWString(const std::string &source, bool utf8)
+{
+ wchar_t buffer[MAX_PATH];
+ if (utf8) {
+ ::MultiByteToWideChar(CP_UTF8, 0, source.c_str(), -1, buffer, MAX_PATH);
+ } else {
+ // codepage encoding
+ ::MultiByteToWideChar(GetACP(), 0, source.c_str(), -1, buffer, MAX_PATH);
+// mbstowcs(buffer, source.c_str(), MAX_PATH);
+ }
+ return std::wstring(buffer);
+}
+
+std::string &ToLower(std::string &text)
+{
+ std::transform(text.begin(), text.end(), text.begin(), tolower);
+ return text;
+}
+
+
+std::wstring &ToLower(std::wstring &text)
+{
+ std::transform(text.begin(), text.end(), text.begin(), towlower);
+ return text;
+}
+
+std::wstring ToLower(const std::wstring &text)
+{
+ std::wstring temp = text;
+
+ std::transform(temp.begin(), temp.end(), temp.begin(), towlower);
+ return temp;
+}
+
+VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName)
+{
+ DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), NULL);
+ if (size == 0) {
+ throw windows_error("failed to determine file version info size");
+ }
+
+ void *buffer = new char[size];
+ try {
+ if (!::GetFileVersionInfoW(fileName.c_str(), 0UL, size, buffer)) {
+ throw windows_error("failed to determine file version info");
+ }
+
+ void *versionInfoPtr = NULL;
+ UINT versionInfoLength = 0;
+ if (!::VerQueryValue(buffer, L"\\", &versionInfoPtr, &versionInfoLength)) {
+ throw windows_error("failed to determine file version");
+ }
+
+ VS_FIXEDFILEINFO result = *(VS_FIXEDFILEINFO*)versionInfoPtr;
+ delete [] buffer;
+ return result;
+ } catch (...) {
+ delete [] buffer;
+ throw;
+ }
+}
+
diff --git a/src/shared/util.h b/src/shared/util.h new file mode 100644 index 00000000..7f44b55d --- /dev/null +++ b/src/shared/util.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef UTIL_H
+#define UTIL_H
+
+
+#include <string>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+
+static const int MAXPATH_UNICODE = 32767;
+
+
+bool FileExists(const std::wstring &filename);
+
+bool FileExists(const std::wstring &searchPath, const std::wstring &filename);
+
+std::string ToString(const std::wstring &source, bool utf8);
+std::wstring ToWString(const std::string &source, bool utf8);
+
+std::string &ToLower(std::string &text);
+std::wstring &ToLower(std::wstring &text);
+
+std::wstring ToLower(const std::wstring &text);
+
+VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName);
+
+#endif // UTIL_H
diff --git a/src/shared/windows_error.cpp b/src/shared/windows_error.cpp new file mode 100644 index 00000000..ad91db44 --- /dev/null +++ b/src/shared/windows_error.cpp @@ -0,0 +1,45 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "windows_error.h"
+#include <sstream>
+
+std::string windows_error::constructMessage(const std::string& input, int inErrorCode)
+{
+ std::ostringstream finalMessage;
+ finalMessage << input;
+
+ LPSTR buffer = NULL;
+
+ DWORD errorCode = inErrorCode != -1 ? inErrorCode : ::GetLastError();
+
+ // TODO: the message is not english?
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, NULL) == 0) {
+ finalMessage << " (errorcode " << errorCode << ")";
+ } else {
+ LPSTR lastChar = buffer + strlen(buffer) - 2;
+ *lastChar = '\0';
+ finalMessage << " (" << buffer << " [" << errorCode << "])";
+ LocalFree(buffer); // allocated by FormatMessage
+ }
+
+ ::SetLastError(errorCode); // restore error code because FormatMessage might have modified it
+ return finalMessage.str();
+}
diff --git a/src/shared/windows_error.h b/src/shared/windows_error.h new file mode 100644 index 00000000..879ee1d2 --- /dev/null +++ b/src/shared/windows_error.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef WINDOWS_ERROR_H
+#define WINDOWS_ERROR_H
+
+
+#include <stdexcept>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+class windows_error : public std::runtime_error {
+public:
+ windows_error(const std::string& message, int errorcode = -1)
+ : runtime_error(constructMessage(message, errorcode)), m_ErrorCode(errorcode)
+ {}
+ int getErrorCode() const { return m_ErrorCode; }
+private:
+ std::string constructMessage(const std::string& input, int errorcode);
+private:
+ int m_ErrorCode;
+};
+
+#endif // WINDOWS_ERROR_H
diff --git a/src/simpleinstalldialog.cpp b/src/simpleinstalldialog.cpp new file mode 100644 index 00000000..ef694780 --- /dev/null +++ b/src/simpleinstalldialog.cpp @@ -0,0 +1,55 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "simpleinstalldialog.h"
+#include "ui_simpleinstalldialog.h"
+
+SimpleInstallDialog::SimpleInstallDialog(const QString &preset, QWidget *parent) :
+ QDialog(parent), ui(new Ui::SimpleInstallDialog), m_Manual(false)
+{
+ ui->setupUi(this);
+ ui->nameEdit->setText(preset);
+ setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
+}
+
+SimpleInstallDialog::~SimpleInstallDialog()
+{
+ delete ui;
+}
+
+QString SimpleInstallDialog::getName() const
+{
+ return ui->nameEdit->text();
+}
+
+void SimpleInstallDialog::on_okBtn_clicked()
+{
+ this->accept();
+}
+
+void SimpleInstallDialog::on_cancelBtn_clicked()
+{
+ this->reject();
+}
+
+void SimpleInstallDialog::on_manualBtn_clicked()
+{
+ m_Manual = true;
+ this->reject();
+}
diff --git a/src/simpleinstalldialog.h b/src/simpleinstalldialog.h new file mode 100644 index 00000000..5e8765de --- /dev/null +++ b/src/simpleinstalldialog.h @@ -0,0 +1,69 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SIMPLEINSTALLDIALOG_H
+#define SIMPLEINSTALLDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class SimpleInstallDialog;
+}
+
+/**
+ * @brief Dialog for the installation of a simple archive
+ * a simple archive is one that doesn't require any manual changes to work correctly
+ **/
+class SimpleInstallDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ /**
+ * @brief constructor
+ *
+ * @param preset suggested name for the mod
+ * @param parent parent widget
+ **/
+ explicit SimpleInstallDialog(const QString &preset, QWidget *parent = 0);
+ ~SimpleInstallDialog();
+
+ /**
+ * @return true if the user requested the manual installation dialog
+ **/
+ bool manualRequested() const { return m_Manual; }
+ /**
+ * @return the (user-modified) mod name
+ **/
+ QString getName() const;
+
+private slots:
+
+ void on_okBtn_clicked();
+
+ void on_cancelBtn_clicked();
+
+ void on_manualBtn_clicked();
+
+private:
+ Ui::SimpleInstallDialog *ui;
+ bool m_Manual;
+};
+
+#endif // SIMPLEINSTALLDIALOG_H
diff --git a/src/simpleinstalldialog.ui b/src/simpleinstalldialog.ui new file mode 100644 index 00000000..a9fdc1d5 --- /dev/null +++ b/src/simpleinstalldialog.ui @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SimpleInstallDialog</class>
+ <widget class="QDialog" name="SimpleInstallDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>71</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Quick Install</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="nameEdit"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="manualBtn">
+ <property name="toolTip">
+ <string>Opens a Dialog that allows custom modifications.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Opens a Dialog that allows custom modifications.</string>
+ </property>
+ <property name="text">
+ <string>Manual</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/singleinstance.cpp b/src/singleinstance.cpp new file mode 100644 index 00000000..69de45e2 --- /dev/null +++ b/src/singleinstance.cpp @@ -0,0 +1,107 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "singleinstance.h"
+#include "report.h"
+#include "utility.h"
+#include <QLocalSocket>
+
+static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5";
+static const int s_Timeout = 5000;
+
+
+SingleInstance::SingleInstance(bool forcePrimary, QObject *parent) :
+ QObject(parent), m_PrimaryInstance(false)
+{
+ m_SharedMem.setKey(s_Key);
+ if (!m_SharedMem.create(1)) {
+ if (forcePrimary) {
+ while (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
+ Sleep(500);
+ if (m_SharedMem.create(1)) {
+ m_PrimaryInstance = true;
+ break;
+ }
+ }
+ }
+
+ if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
+ m_SharedMem.attach();
+ m_PrimaryInstance = false;
+ }
+ if ((m_SharedMem.error() != QSharedMemory::NoError) &&
+ (m_SharedMem.error() != QSharedMemory::AlreadyExists)) {
+ throw MyException(tr("SHM error: %1").arg(m_SharedMem.errorString()));
+ }
+ } else {
+ m_PrimaryInstance = true;
+ }
+ if (m_PrimaryInstance) {
+ connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
+ m_Server.listen(s_Key);
+ }
+}
+
+
+void SingleInstance::sendMessage(const QString &message)
+{
+ if (m_PrimaryInstance) {
+ // nobody there to receive the message
+ return;
+ }
+ QLocalSocket socket(this);
+
+ bool connected = false;
+ for(int i = 0; i < 2 && !connected; ++i) {
+ if (i > 0) {
+ Sleep(250);
+ }
+
+ // other instance may be just starting up
+ socket.connectToServer(s_Key, QIODevice::WriteOnly);
+ connected = socket.waitForConnected(s_Timeout);
+ }
+
+ if (!connected) {
+ reportError(tr("failed to connect to running instance: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.write(message.toUtf8());
+ if (!socket.waitForBytesWritten(s_Timeout)) {
+ reportError(tr("failed to connect to running instance: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.disconnectFromServer();
+}
+
+
+void SingleInstance::receiveMessage()
+{
+ QLocalSocket *socket = m_Server.nextPendingConnection();
+ if (!socket->waitForReadyRead(s_Timeout)) {
+ reportError(tr("failed to receive data from secondary instance: %1").arg(socket->errorString()));
+ return;
+ }
+
+ QString message = QString::fromUtf8(socket->readAll().constData());
+ emit messageSent(message);
+ socket->disconnectFromServer();
+}
diff --git a/src/singleinstance.h b/src/singleinstance.h new file mode 100644 index 00000000..cc95bf48 --- /dev/null +++ b/src/singleinstance.h @@ -0,0 +1,88 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SINGLEINSTANCE_H
+#define SINGLEINSTANCE_H
+
+#include <QObject>
+#include <QSharedMemory>
+#include <QLocalServer>
+
+
+/**
+ * used to ensure only a single instance of Mod Organizer is started and to
+ * allow secondary instances to send messages to the primary (visible) one. This way,
+ * secondary instances can start a download in the primary one
+ **/
+class SingleInstance : public QObject
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param forcePrimary if true, this will be treated as the primary instance even
+ * if another instance is running. This is used after an update since
+ * the other instance is assumed to be in the process of quitting
+ * @param parent parent object
+ * @todo the forcePrimary parameter makes no sense. The second instance after an update
+ * needs to delete the files from before the update so the first instance needs to quit
+ * first anyway
+ **/
+ explicit SingleInstance(bool forcePrimary, QObject *parent = 0);
+
+ /**
+ * @return true if this is the primary instance (the one that gets to display a UI)
+ **/
+ bool primaryInstance() const { return m_PrimaryInstance; }
+
+ /**
+ * send a message to the primary instance. This can be used to transmit download urls
+ *
+ * @param message message to send
+ **/
+ void sendMessage(const QString &message);
+
+signals:
+
+ /**
+ * @brief emitted when a secondary instance has sent a message (to us)
+ *
+ * @param message the message we received
+ **/
+ void messageSent(const QString &message);
+
+public slots:
+
+private slots:
+
+ void receiveMessage();
+
+private:
+
+ bool m_PrimaryInstance;
+ QSharedMemory m_SharedMem;
+ QLocalServer m_Server;
+
+};
+
+#endif // SINGLEINSTANCE_H
diff --git a/src/spawn.cpp b/src/spawn.cpp new file mode 100644 index 00000000..13e74f93 --- /dev/null +++ b/src/spawn.cpp @@ -0,0 +1,109 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "spawn.h"
+#include "report.h"
+#include "utility.h"
+#include <gameinfo.h>
+#include <inject.h>
+#include <appconfig.h>
+#include <windows_error.h>
+#include <QApplication>
+
+
+bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended, HANDLE& processHandle, HANDLE& threadHandle)
+{
+ STARTUPINFO si;
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ int length = wcslen(binary) + wcslen(arguments) + 4;
+ wchar_t *commandLine = NULL;
+ if (arguments[0] != L'\0') {
+ commandLine = new wchar_t[length];
+ _snwprintf(commandLine, length, L"\"%ls\" %ls", binary, arguments);
+ } else {
+ commandLine = new wchar_t[length];
+ _snwprintf(commandLine, length, L"\"%ls\"", binary);
+
+ }
+
+ PROCESS_INFORMATION pi;
+ BOOL success = ::CreateProcess(NULL,
+ commandLine,
+ NULL, NULL, // no special process or thread attributes
+ FALSE, // don't inherit handle
+ suspended ? CREATE_SUSPENDED : 0, // create suspended so I have time to inject the DLL
+ NULL, // same environment as parent
+ currentDirectory, // current directory
+ &si, &pi // startup and process information
+ );
+
+ delete [] commandLine;
+
+ if (!success) {
+ throw windows_error("failed to start process");
+ }
+
+ processHandle = pi.hProcess;
+ threadHandle = pi.hThread;
+ return true;
+}
+
+
+HANDLE startBinary(const QFileInfo &binary, const QString &arguments, const QString& profileName, int logLevel, const QDir ¤tDirectory, bool hooked)
+{
+ HANDLE processHandle, threadHandle;
+ std::wstring binaryName = ToWString(QDir::toNativeSeparators(binary.absoluteFilePath()));
+ std::wstring currentDirectoryName = ToWString(QDir::toNativeSeparators(currentDirectory.absolutePath()));
+
+ try {
+ if (!spawn(binaryName.c_str(), ToWString(arguments).c_str(), currentDirectoryName.c_str(), hooked, processHandle, threadHandle)) {
+ reportError(QObject::tr("failed to spawn \"%1\"").arg(binary.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ } catch (const windows_error &e) {
+ reportError(QObject::tr("failed to spawn \"%1\": %2").arg(binary.fileName()).arg(e.what()));
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (hooked) {
+ try {
+ QFileInfo dllInfo(QApplication::applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName()));
+ if (!dllInfo.exists()) {
+ reportError(QObject::tr("\"%1\" doesn't exist").arg(dllInfo.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ injectDLL(processHandle, threadHandle,
+ QDir::toNativeSeparators(dllInfo.canonicalFilePath()).toLocal8Bit().constData(),
+ ToWString(profileName).c_str(), logLevel);
+ } catch (const windows_error& e) {
+ reportError(QObject::tr("failed to inject dll into \"%1\": %2").arg(binary.fileName()).arg(e.what()));
+ ::TerminateProcess(processHandle, 1);
+ return INVALID_HANDLE_VALUE;
+ }
+#ifdef _DEBUG
+ reportError("ready?");
+#endif // DEBUG
+ if (::ResumeThread(threadHandle) == (DWORD)-1) {
+ reportError(QObject::tr("failed to run \"%1\"").arg(binary.fileName()));
+ return INVALID_HANDLE_VALUE;
+ }
+ }
+ return processHandle;
+}
diff --git a/src/spawn.h b/src/spawn.h new file mode 100644 index 00000000..1ccfb307 --- /dev/null +++ b/src/spawn.h @@ -0,0 +1,43 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SPAWN_H
+#define SPAWN_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <tchar.h>
+#include <QFileInfo>
+#include <QDir>
+
+/**
+ * @brief spawn a binary with Mod Organizer injected
+ *
+ * @param binary the binary to spawn
+ * @param arguments arguments to pass to the binary
+ * @param profileName name of the active profile
+ * @param currentDirectory the directory to use as the working directory to run in
+ * @param hooked if set, the binary is started with mo injected
+ * @return the process handle
+ * @todo is the profile name even used any more?
+ * @todo is the hooked parameter used?
+ **/
+HANDLE startBinary(const QFileInfo &binary, const QString &arguments, const QString &profileName, int logLevel, const QDir ¤tDirectory, bool hooked);
+
+#endif // SPAWN_H
diff --git a/src/splash.png b/src/splash.png Binary files differnew file mode 100644 index 00000000..45ace8f8 --- /dev/null +++ b/src/splash.png diff --git a/src/stylesheet_resource.qrc b/src/stylesheet_resource.qrc new file mode 100644 index 00000000..75de976b --- /dev/null +++ b/src/stylesheet_resource.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/stylesheet"> + <file alias="combobox-down.png">resources/combobox-down.png</file> + <file alias="branch-closed.png">resources/branch-closed.png</file> + <file alias="branch-open.png">resources/branch-open.png</file> + </qresource> +</RCC> diff --git a/src/stylesheets/dark.qss b/src/stylesheets/dark.qss new file mode 100644 index 00000000..80e58379 --- /dev/null +++ b/src/stylesheets/dark.qss @@ -0,0 +1,356 @@ +QToolTip
+{
+ border: 1px solid black;
+ color: #D9E6EA;
+ background-color: #484F53;
+ padding: 1px;
+ border-radius: 3px;
+ opacity: 100;
+}
+
+QWidget
+{
+ color: #E9E6E4;
+ background-color: #2F3031;
+}
+
+
+QWidget:disabled
+{
+ color: #757676;
+ background-color: #292A2B;
+}
+
+QAbstractItemView
+{
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484F53, stop: 0.7 #656666, stop: 1 #484F53);
+}
+
+QLineEdit
+{
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484F53, stop: 0.9 #757676, stop: 1 #484F53);
+ padding: 1px;
+ border-style: solid;
+ border: 1px solid #1e1e1e;
+ border-radius: 5;
+}
+
+QPushButton
+{
+ color: #D9E6EA;
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #697670, stop: 1 #484F53);
+ border-width: 2px;
+ border-color: #1F2021;
+ border-style: solid;
+ border-radius: 6;
+ padding: 3px;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+
+QPushButton:pressed
+{
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #484F53, stop: 1 #697670);
+}
+
+QPushButton:checked
+{
+ border-width: 1px;
+ border-color: #3EA0CA;
+}
+
+QComboBox
+{
+ selection-background-color: #D9E6EA;
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #9AA6A4, stop: 1 #484F53);
+ border: 2px solid #1D2320;
+ height: 20px;
+ border-radius: 5px;
+}
+
+QComboBox:hover,QPushButton:hover
+{
+ border: 2px solid #3EA0CA;
+}
+
+
+QComboBox:on
+{
+ padding-top: 3px;
+ padding-left: 4px;
+ background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #697670, stop: 1 #484F53);
+ selection-background-color: #80B5C3;
+}
+
+QComboBox::drop-down
+{
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 15px;
+
+ border-left-width: 0px;
+ border-left-color: darkgray;
+ border-left-style: solid;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+QComboBox::down-arrow {
+ image: url(:/stylesheet/combobox-down.png);
+}
+
+
+/* Scrollbars */
+QScrollBar:horizontal {
+ border: 1px solid #1F2021;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 #1D2320, stop: 0.2 #1F2021, stop: 1 #484F53);
+ height: 14px;
+ margin: 1px 16px 1px 16px;
+}
+
+QScrollBar::handle:horizontal
+{
+ background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #3EA0CA, stop: 0.5 #427683, stop: 1 #3EA0CA);
+ min-height: 20px;
+ border-radius: 4px;
+}
+
+QScrollBar::add-line:horizontal {
+ border: 1px solid #1b1b19;
+ border-radius: 2px;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #3EA0CA, stop: 1 #427683);
+ width: 14px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal {
+ border: 1px solid #1b1b19;
+ border-radius: 2px;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #3EA0CA, stop: 1 #427683);
+ width: 14px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::right-arrow:horizontal, QScrollBar::left-arrow:horizontal
+{
+ border: 1px solid black;
+ width: 1px;
+ height: 1px;
+ background: white;
+}
+
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+
+QScrollBar:vertical
+{
+ border: 1px solid #1F2021;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0.0 #1D2320, stop: 0.2 #1F2021, stop: 1 #484F53);
+ width: 14px;
+ margin: 16px 1px 16px 1px;
+}
+
+QScrollBar::handle:vertical
+{
+ background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #3EA0CA, stop: 0.5 #427683, stop: 1 #3EA0CA);
+ min-height: 20px;
+ border-radius: 4px;
+}
+
+QScrollBar::add-line:vertical
+{
+ border: 1px solid #1b1b19;
+ border-radius: 2px;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #3EA0CA, stop: 1 #427683);
+ height: 14px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:vertical
+{
+ border: 1px solid #1b1b19;
+ border-radius: 2px;
+ background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #3EA0CA, stop: 1 #427683);
+ height: 14px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical
+{
+ border: 1px solid black;
+ width: 1px;
+ height: 1px;
+ background: white;
+}
+
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+ background: none;
+}
+
+QTextEdit
+{
+ background-color: #484F53;
+}
+
+QPlainTextEdit
+{
+ background-color: #484F53;
+}
+
+QHeaderView::section
+{
+ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0 #484F53, stop:0.5 #757676, stop:1 #484F53);
+ color: white;
+ padding-left: 4px;
+ border: 1px solid #2D3330;
+ border-radius: 2px;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+
+QCheckBox:disabled
+{
+ color: #414141;
+}
+
+QMenu::separator
+{
+ height: 2px;
+ background-color: #484F53;
+ color: white;
+ padding-left: 4px;
+ margin-left: 10px;
+ margin-right: 5px;
+}
+
+QProgressBar
+{
+ border: 2px solid grey;
+ border-radius: 5px;
+ text-align: center;
+}
+
+QProgressBar::chunk
+{
+ background-color: #427683;
+ width: 20px;
+}
+
+QTabBar::tab {
+ color: #E9E6E4;
+ border: 1px solid #444;
+ border-bottom-style: none;
+ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0.8 #1D2320, stop:0.2 #757676);
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ padding-bottom: 2px;
+ margin-right: -1px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+
+QTabWidget::pane {
+ border: 1px solid #444;
+ top: 1px;
+}
+
+QTabBar::tab:last
+{
+ margin-right: 0; /* the last selected tab has nothing to overlap with on the right */
+}
+
+QTabBar::tab:first
+{
+ margin-left: 0px; /* the last selected tab has nothing to overlap with on the right */
+}
+
+QTabBar::tab:!selected
+{
+ color: #E9E6E4;
+ border-bottom-style: solid;
+ margin-top: 3px;
+ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:0.8 #1D2320, stop:0.4 #484F53);
+}
+
+QTabBar::tab:disabled
+{
+ color: #757676;
+ border-bottom-style: solid;
+ margin-top: 3px;
+ background-color: #484F53;
+}
+QTabBar::tab:selected
+{
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ margin-bottom: 0px;
+}
+
+QTabBar::tab:!selected:hover
+{
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
+ background-color: QLinearGradient(x1:0, y1:0, x2:0, y2:1, stop:1 #212121, stop:0.4 #343434, stop:0.2 #343434, stop:0.1 #3EA0CA);
+}
+
+
+QToolButton {
+ border:2px ridge #757676;
+ border-radius: 6px;
+ margin: 3px;
+ padding-left: 8px;
+ padding-right: 8px;
+ padding-top: 0px;
+ padding-bottom: 2px;
+
+
+}
+QToolButton:hover {
+ border: 2px ridge #757676;
+ background-color: #484F53;
+ border-radius: 6px;
+ margin: 3px;
+ padding-left: 8px;
+ padding-right: 8px;
+ padding-top: 0px;
+ padding-bottom: 2px;
+}
+
+
+QTreeView {
+ color: #E9E6E4;
+ background-color: #3F4041;
+ alternate-background-color: #2F3031;
+}
+
+/*
+QTreeView::item:selected {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #3EA0CA, stop: 1 #0B2A39);
+ }
+
+QTreeView::item:hover {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #1E80AA, stop: 1 #225663);
+ }*/
+
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings {
+ border-image: none;
+ image: url(:/stylesheet/branch-closed.png);
+}
+
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings {
+ border-image: none;
+ image: url(:/stylesheet/branch-open.png);
+}
diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp new file mode 100644 index 00000000..0fac8a7d --- /dev/null +++ b/src/syncoverwritedialog.cpp @@ -0,0 +1,146 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "syncoverwritedialog.h"
+#include "ui_syncoverwritedialog.h"
+#include <utility.h>
+#include <report.h>
+#include <gameinfo.h>
+#include <QDir>
+#include <QDirIterator>
+#include <QComboBox>
+#include <QStringList>
+
+
+SyncOverwriteDialog::SyncOverwriteDialog(const QString &path, DirectoryEntry *directoryStructure, QWidget *parent)
+ : TutorableDialog("SyncOverwrite", parent),
+ ui(new Ui::SyncOverwriteDialog), m_SourcePath(path), m_DirectoryStructure(directoryStructure)
+{
+ ui->setupUi(this);
+ refresh(path, directoryStructure);
+
+ QHeaderView *headerView = ui->syncTree->header();
+#if QT_VERSION >= 0x050000
+ headerView->setSectionResizeMode(0, QHeaderView::Stretch);
+ headerView->setSectionResizeMode(1, QHeaderView::Interactive);
+#else
+ headerView->setResizeMode(0, QHeaderView::Stretch);
+ headerView->setResizeMode(1, QHeaderView::Interactive);
+#endif
+}
+
+
+SyncOverwriteDialog::~SyncOverwriteDialog()
+{
+ delete ui;
+}
+
+
+void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *directoryStructure, QTreeWidgetItem *subTree)
+{
+ QDir overwrite(path);
+ overwrite.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
+ QDirIterator dirIter(overwrite);
+ while (dirIter.hasNext()) {
+ dirIter.next();
+ QFileInfo fileInfo = dirIter.fileInfo();
+
+ QString file = fileInfo.fileName();
+ if (file == "meta.ini") {
+ continue;
+ }
+
+ QTreeWidgetItem *newItem = new QTreeWidgetItem(subTree, QStringList(file));
+
+ if (fileInfo.isDir()) {
+ DirectoryEntry *subDir = directoryStructure->findSubDirectory(ToWString(file));
+ if (subDir != NULL) {
+ readTree(fileInfo.absoluteFilePath(), subDir, newItem);
+ } else {
+ qCritical("no directory structure for %s?", file.toUtf8().constData());
+ delete newItem;
+ newItem = NULL;
+ }
+ } else {
+ const FileEntry *entry = directoryStructure->findFile(ToWString(file));
+ QComboBox* combo = new QComboBox(ui->syncTree);
+ combo->addItem(tr("<don't sync>"), -1);
+ if (entry != NULL) {
+ const std::vector<int> &alternatives = entry->getAlternatives();
+ for (std::vector<int>::const_iterator iter = alternatives.begin(); iter != alternatives.end(); ++iter) {
+ combo->addItem(ToQString(m_DirectoryStructure->getOriginByID(*iter).getName()), *iter);
+ }
+ combo->setCurrentIndex(combo->count() - 1);
+ } else {
+ combo->setCurrentIndex(0);
+ }
+ ui->syncTree->setItemWidget(newItem, 1, combo);
+ }
+ if (newItem != NULL) {
+ subTree->addChild(newItem);
+ }
+ }
+}
+
+
+void SyncOverwriteDialog::refresh(const QString &path, DirectoryEntry *directoryStructure)
+{
+ QTreeWidgetItem *rootItem = new QTreeWidgetItem(ui->syncTree, QStringList("<data>"));
+ readTree(path, directoryStructure, rootItem);
+ ui->syncTree->addTopLevelItem(rootItem);
+ ui->syncTree->expandAll();
+}
+
+
+void SyncOverwriteDialog::applyTo(QTreeWidgetItem *item, const QString &path, const QString &modDirectory)
+{
+ for (int i = 0; i < item->childCount(); ++i) {
+ QTreeWidgetItem *child = item->child(i);
+ QString filePath;
+ if (path.length() != 0) {
+ filePath = path.mid(0).append("/").append(child->text(0));
+ } else {
+ filePath = child->text(0);
+ }
+ if (child->childCount() != 0) {
+ applyTo(child, filePath, modDirectory);
+ } else {
+ QComboBox *comboBox = qobject_cast<QComboBox*>(ui->syncTree->itemWidget(child, 1));
+ if (comboBox != NULL) {
+ int originID = comboBox->itemData(comboBox->currentIndex(), Qt::UserRole).toInt();
+ if (originID != -1) {
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByID(originID);
+ QString source = m_SourcePath.mid(0).append("/").append(filePath);
+ QString destination = modDirectory.mid(0).append("/").append(ToQString(origin.getName())).append("/").append(filePath);
+ if (!QFile::remove(destination)) {
+ reportError(tr("failed to remove %1").arg(destination));
+ } else if (!QFile::rename(source, destination)) {
+ reportError(tr("failed to move %1 to %2").arg(source).arg(destination));
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void SyncOverwriteDialog::apply(const QString &modDirectory)
+{
+ applyTo(ui->syncTree->topLevelItem(0), "", modDirectory);
+}
diff --git a/src/syncoverwritedialog.h b/src/syncoverwritedialog.h new file mode 100644 index 00000000..ca4abb8e --- /dev/null +++ b/src/syncoverwritedialog.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SYNCOVERWRITEDIALOG_H
+#define SYNCOVERWRITEDIALOG_H
+
+
+#include <directoryentry.h>
+#include "tutorabledialog.h"
+#include <QTreeWidgetItem>
+
+
+namespace Ui {
+class SyncOverwriteDialog;
+}
+
+class SyncOverwriteDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SyncOverwriteDialog(const QString &path, DirectoryEntry *directoryStructure, QWidget *parent = 0);
+ ~SyncOverwriteDialog();
+
+ void apply(const QString &modDirectory);
+private:
+ void refresh(const QString &path, DirectoryEntry *directoryStructure);
+ void readTree(const QString &path, DirectoryEntry *directoryStructure, QTreeWidgetItem *subTree);
+ void applyTo(QTreeWidgetItem *item, const QString &path, const QString &modDirectory);
+
+private:
+
+ Ui::SyncOverwriteDialog *ui;
+ QString m_SourcePath;
+ DirectoryEntry *m_DirectoryStructure;
+
+};
+
+#endif // SYNCOVERWRITEDIALOG_H
diff --git a/src/syncoverwritedialog.ui b/src/syncoverwritedialog.ui new file mode 100644 index 00000000..18e5c1b6 --- /dev/null +++ b/src/syncoverwritedialog.ui @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SyncOverwriteDialog</class>
+ <widget class="QDialog" name="SyncOverwriteDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>537</width>
+ <height>430</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Sync Overwrite</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTreeWidget" name="syncTree">
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerDefaultSectionSize">
+ <number>300</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Sync To</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SyncOverwriteDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SyncOverwriteDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/textviewer.h b/src/textviewer.h new file mode 100644 index 00000000..c0d29607 --- /dev/null +++ b/src/textviewer.h @@ -0,0 +1,93 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef TEXTVIEWER_H
+#define TEXTVIEWER_H
+
+#include <QDialog>
+#include <QTabWidget>
+#include <finddialog.h>
+#include <set>
+#include "loghighlighter.h"
+
+namespace Ui {
+ class TextViewer;
+}
+
+
+/**
+ * @brief tabbed text editor
+ **/
+class TextViewer : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ * @param parent parent widget
+ **/
+ explicit TextViewer(QWidget *parent = 0);
+
+ ~TextViewer();
+
+ /**
+ * @brief set the description text to inform the user what he's editing
+ *
+ * @param description the description to set
+ **/
+ void setDescription(const QString &description);
+
+ /**
+ * @brief add a new tab with the specified file open
+ *
+ * @param fileName name of the file to open
+ * @param writable if true, the file can be modified
+ **/
+ void addFile(const QString &fileName, bool writable);
+
+protected:
+
+ void closeEvent(QCloseEvent *event);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+
+ void saveFile();
+ void modified();
+ void patternChanged(QString newPattern);
+ void findNext();
+
+private:
+
+ void saveFile(const QTextEdit *editor);
+ void find();
+
+private:
+
+ Ui::TextViewer *ui;
+ QTabWidget *m_EditorTabs;
+ std::set<QTextEdit*> m_Modified;
+ FindDialog *m_FindDialog;
+ QString m_FindPattern;
+
+};
+
+#endif // TEXTVIEWER_H
diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp new file mode 100644 index 00000000..c6ddfd78 --- /dev/null +++ b/src/transfersavesdialog.cpp @@ -0,0 +1,331 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "transfersavesdialog.h"
+#include "ui_transfersavesdialog.h"
+#include "utility.h"
+#include <gameinfo.h>
+#include <QDir>
+#include <QMessageBox>
+#include <Shlwapi.h>
+#include <shlobj.h>
+
+
+TransferSavesDialog::TransferSavesDialog(const Profile &profile, QWidget *parent)
+ : TutorableDialog("TransferSaves", parent), ui(new Ui::TransferSavesDialog), m_Profile(profile)
+{
+ ui->setupUi(this);
+ refreshGlobalSaves();
+ refreshLocalSaves();
+ refreshGlobalCharacters();
+ refreshLocalCharacters();
+}
+
+TransferSavesDialog::~TransferSavesDialog()
+{
+ delete ui;
+}
+
+
+void TransferSavesDialog::refreshGlobalSaves()
+{
+ m_GlobalSaves.clear();
+
+ QDir savesDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir())));
+
+ QStringList filters;
+ filters << ToQString(GameInfo::instance().getSaveGameExtension());
+ savesDir.setNameFilters(filters);
+
+ QStringList files = savesDir.entryList(QDir::Files, QDir::Time);
+
+ foreach (const QString &filename, files) {
+ SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename));
+ save->setParent(this);
+ m_GlobalSaves.push_back(save);
+ }
+}
+
+
+void TransferSavesDialog::refreshLocalSaves()
+{
+ m_LocalSaves.clear();
+
+ QDir savesDir(m_Profile.getPath().append("/saves"));
+
+ QStringList filters;
+ filters << ToQString(GameInfo::instance().getSaveGameExtension());
+ savesDir.setNameFilters(filters);
+
+ QStringList files = savesDir.entryList(QDir::Files, QDir::Time);
+
+ foreach (const QString &filename, files) {
+ SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename));
+ save->setParent(this);
+ m_LocalSaves.push_back(save);
+ }
+}
+
+
+void TransferSavesDialog::refreshGlobalCharacters()
+{
+ std::set<QString> characters;
+ for (std::vector<SaveGame*>::const_iterator iter = m_GlobalSaves.begin();
+ iter != m_GlobalSaves.end(); ++iter) {
+ characters.insert((*iter)->pcName());
+ }
+ ui->globalCharacterList->clear();
+ for (std::set<QString>::const_iterator iter = characters.begin();
+ iter != characters.end(); ++iter) {
+ ui->globalCharacterList->addItem(*iter);
+ }
+ if (ui->globalCharacterList->count() > 0) {
+ ui->globalCharacterList->setCurrentRow(0);
+ ui->copyToLocalBtn->setEnabled(true);
+ ui->moveToLocalBtn->setEnabled(true);
+ } else {
+ ui->copyToLocalBtn->setEnabled(false);
+ ui->moveToLocalBtn->setEnabled(false);
+ }
+}
+
+
+void TransferSavesDialog::refreshLocalCharacters()
+{
+ std::set<QString> characters;
+ for (std::vector<SaveGame*>::const_iterator iter = m_LocalSaves.begin();
+ iter != m_LocalSaves.end(); ++iter) {
+ characters.insert((*iter)->pcName());
+ }
+ ui->localCharacterList->clear();
+ for (std::set<QString>::const_iterator iter = characters.begin();
+ iter != characters.end(); ++iter) {
+ ui->localCharacterList->addItem(*iter);
+ }
+ if (ui->localCharacterList->count() > 0) {
+ ui->localCharacterList->setCurrentRow(0);
+ ui->copyToGlobalBtn->setEnabled(true);
+ ui->moveToGlobalBtn->setEnabled(true);
+ } else {
+ ui->copyToGlobalBtn->setEnabled(false);
+ ui->moveToGlobalBtn->setEnabled(false);
+ }
+}
+
+
+bool TransferSavesDialog::testOverwrite(OverwriteMode &overwriteMode, const QString &destinationFile)
+{
+ QMessageBox::StandardButton res = overwriteMode == OVERWRITE_YES ? QMessageBox::Yes : QMessageBox::No;
+ if (overwriteMode == OVERWRITE_ASK) {
+ res = QMessageBox::question(this, tr("Overwrite"),
+ tr("Overwrite the file \"%1\"").arg(destinationFile),
+ QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll | QMessageBox::NoToAll);
+ if (res == QMessageBox::YesToAll) {
+ overwriteMode = OVERWRITE_YES;
+ res = QMessageBox::Yes;
+ } else if (res == QMessageBox::NoToAll) {
+ overwriteMode = OVERWRITE_NO;
+ res = QMessageBox::No;
+ }
+ }
+ return res == QMessageBox::Yes;
+}
+
+QStringList TransferSavesDialog::getFilesToProcess(const SaveGame *save)
+{
+ QStringList result = save->attachedFiles();
+ result.append(save->fileName());
+ return result;
+}
+
+void TransferSavesDialog::on_moveToLocalBtn_clicked()
+{
+ QString selectedCharacter = ui->globalCharacterList->currentItem()->text();
+ if (QMessageBox::question(this, tr("Confirm"),
+ tr("Copy all save games of character \"%1\" to the profile?").arg(selectedCharacter),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ QString destination = m_Profile.getPath().append("/saves");
+ OverwriteMode overwriteMode = OVERWRITE_ASK;
+
+ for (std::vector<SaveGame*>::const_iterator iter = m_GlobalSaves.begin();
+ iter != m_GlobalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == selectedCharacter) {
+ QStringList files = getFilesToProcess(*iter);
+ foreach (const QString &file, files) {
+ QFileInfo fileInfo(file);
+ QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName());
+ if (QFile::exists(destinationFile)) {
+ if (testOverwrite(overwriteMode, destinationFile)) {
+ QFile::remove(destinationFile);
+ } else {
+ continue;
+ }
+ }
+ if (!QFile::rename(fileInfo.absoluteFilePath(), destinationFile)) {
+ qCritical("failed to move %s to %s",
+ fileInfo.absoluteFilePath().toUtf8().constData(),
+ destinationFile.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+ refreshGlobalSaves();
+ refreshGlobalCharacters();
+ refreshLocalSaves();
+ refreshLocalCharacters();
+}
+
+void TransferSavesDialog::on_copyToLocalBtn_clicked()
+{
+ QString selectedCharacter = ui->globalCharacterList->currentItem()->text();
+ if (QMessageBox::question(this, tr("Confirm"),
+ tr("Copy all save games of character \"%1\" to the profile?").arg(selectedCharacter),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ QString destination = m_Profile.getPath().append("/saves");
+ OverwriteMode overwriteMode = OVERWRITE_ASK;
+ for (std::vector<SaveGame*>::const_iterator iter = m_GlobalSaves.begin();
+ iter != m_GlobalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == selectedCharacter) {
+ QStringList files = getFilesToProcess(*iter);
+ foreach (const QString &file, files) {
+ QFileInfo fileInfo(file);
+ QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName());
+ if (QFile::exists(destinationFile)) {
+ if (testOverwrite(overwriteMode, destinationFile)) {
+ QFile::remove(destinationFile);
+ } else {
+ continue;
+ }
+ }
+ if (!QFile::copy(fileInfo.absoluteFilePath(), destinationFile)) {
+ qCritical("failed to copy %s to %s",
+ fileInfo.absoluteFilePath().toUtf8().constData(),
+ destinationFile.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+ refreshLocalSaves();
+ refreshLocalCharacters();
+}
+
+void TransferSavesDialog::on_moveToGlobalBtn_clicked()
+{
+ QString selectedCharacter = ui->localCharacterList->currentItem()->text();
+ if (QMessageBox::question(this, tr("Confirm"),
+ tr("Move all save games of character \"%1\" to the global location? Please be aware "
+ "that this will mess up the running number of save games.").arg(selectedCharacter),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+
+ QString destination = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir()));
+ OverwriteMode overwriteMode = OVERWRITE_ASK;
+ for (std::vector<SaveGame*>::const_iterator iter = m_LocalSaves.begin();
+ iter != m_LocalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == selectedCharacter) {
+ QStringList files = getFilesToProcess(*iter);
+ foreach (const QString &file, files) {
+ QFileInfo fileInfo(file);
+ QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName());
+ if (QFile::exists(destinationFile)) {
+ if (testOverwrite(overwriteMode, destinationFile)) {
+ QFile::remove(destinationFile);
+ } else {
+ continue;
+ }
+ }
+ if (!QFile::rename(fileInfo.absoluteFilePath(), destinationFile)) {
+ qCritical("failed to move %s to %s",
+ fileInfo.absoluteFilePath().toUtf8().constData(),
+ destinationFile.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+ refreshGlobalSaves();
+ refreshGlobalCharacters();
+ refreshLocalSaves();
+ refreshLocalCharacters();
+}
+
+void TransferSavesDialog::on_copyToGlobalBtn_clicked()
+{
+ QString selectedCharacter = ui->localCharacterList->currentItem()->text();
+ if (QMessageBox::question(this, tr("Confirm"),
+ tr("Copy all save games of character \"%1\" to the global location? Please be aware "
+ "that this will mess up the running number of save games.").arg(selectedCharacter),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+
+ QString destination = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getSaveGameDir()));
+ OverwriteMode overwriteMode = OVERWRITE_ASK;
+ for (std::vector<SaveGame*>::const_iterator iter = m_LocalSaves.begin();
+ iter != m_LocalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == selectedCharacter) {
+ QStringList files = getFilesToProcess(*iter);
+ foreach (const QString &file, files) {
+ QFileInfo fileInfo(file);
+ QString destinationFile = destination.mid(0).append("/").append(fileInfo.fileName());
+ if (QFile::exists(destinationFile)) {
+ if (testOverwrite(overwriteMode, destinationFile)) {
+ QFile::remove(destinationFile);
+ } else {
+ continue;
+ }
+ }
+ if (!QFile::copy(fileInfo.absoluteFilePath(), destinationFile)) {
+ qCritical("failed to copy %s to %s",
+ fileInfo.absoluteFilePath().toUtf8().constData(),
+ destinationFile.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+ refreshGlobalSaves();
+ refreshGlobalCharacters();
+}
+
+void TransferSavesDialog::on_doneButton_clicked()
+{
+ close();
+}
+
+void TransferSavesDialog::on_globalCharacterList_currentTextChanged(const QString ¤tText)
+{
+ ui->globalSavesList->clear();
+ for (std::vector<SaveGame*>::const_iterator iter = m_GlobalSaves.begin();
+ iter != m_GlobalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == currentText) {
+ ui->globalSavesList->addItem(QFileInfo((*iter)->fileName()).fileName());
+ }
+ }
+}
+
+void TransferSavesDialog::on_localCharacterList_currentTextChanged(const QString ¤tText)
+{
+ ui->localSavesList->clear();
+ for (std::vector<SaveGame*>::const_iterator iter = m_LocalSaves.begin();
+ iter != m_LocalSaves.end(); ++iter) {
+ if ((*iter)->pcName() == currentText) {
+ ui->localSavesList->addItem(QFileInfo((*iter)->fileName()).fileName());
+ }
+ }
+}
diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h new file mode 100644 index 00000000..e8d08a13 --- /dev/null +++ b/src/transfersavesdialog.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef TRANSFERSAVESDIALOG_H
+#define TRANSFERSAVESDIALOG_H
+
+#include "tutorabledialog.h"
+#include "savegamegamebyro.h"
+#include "profile.h"
+
+namespace Ui {
+class TransferSavesDialog;
+}
+
+class TransferSavesDialog : public TutorableDialog
+{
+ Q_OBJECT
+
+public:
+ explicit TransferSavesDialog(const Profile &profile, QWidget *parent = 0);
+ ~TransferSavesDialog();
+
+private slots:
+
+ void on_moveToLocalBtn_clicked();
+
+ void on_doneButton_clicked();
+
+ void on_globalCharacterList_currentTextChanged(const QString ¤tText);
+
+ void on_localCharacterList_currentTextChanged(const QString ¤tText);
+
+ void on_copyToLocalBtn_clicked();
+
+ void on_moveToGlobalBtn_clicked();
+
+ void on_copyToGlobalBtn_clicked();
+
+private:
+
+ enum OverwriteMode {
+ OVERWRITE_ASK,
+ OVERWRITE_YES,
+ OVERWRITE_NO
+ };
+
+private:
+
+ void refreshGlobalCharacters();
+ void refreshLocalCharacters();
+ void refreshGlobalSaves();
+ void refreshLocalSaves();
+ bool testOverwrite(OverwriteMode &overwriteMode, const QString &destinationFile);
+ QStringList getFilesToProcess(const SaveGame *save);
+
+private:
+
+ Ui::TransferSavesDialog *ui;
+
+ Profile m_Profile;
+
+ std::vector<SaveGame*> m_GlobalSaves;
+ std::vector<SaveGame*> m_LocalSaves;
+
+};
+
+#endif // TRANSFERSAVESDIALOG_H
diff --git a/src/transfersavesdialog.ui b/src/transfersavesdialog.ui new file mode 100644 index 00000000..7cd1c4b5 --- /dev/null +++ b/src/transfersavesdialog.ui @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TransferSavesDialog</class>
+ <widget class="QDialog" name="TransferSavesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>882</width>
+ <height>528</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Global Characters</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="globalCharacterList">
+ <property name="toolTip">
+ <string>This is a list of characters in the global location.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This is a list of characters in the global location.
+
+On Windows Vista/Windows 7:
+ C:\Users\[UserName]\Documents\My Games\Skyrim\Saves
+
+On Windows XP:
+ C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves
+</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="globalSavesList">
+ <property name="whatsThis">
+ <string>This is a list of save games for the selected character in the global location.
+
+On Windows Vista/Windows 7:
+ C:\Users\[UserName]\Documents\My Games\Skyrim\Saves
+
+On Windows XP:
+ C:\Documents and Settings[UserName]\My Documents\My Games\Skyrim\Saves
+
+</string>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="moveToLocalBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Move -></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="copyToLocalBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Copy -></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Minimum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="moveToGlobalBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string><- Move</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="copyToGlobalBtn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string><- Copy</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>100</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="doneButton">
+ <property name="text">
+ <string>Done</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Profile Characters</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="localCharacterList"/>
+ </item>
+ <item>
+ <widget class="QListWidget" name="localSavesList">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/tutorials/Highlight.qml b/src/tutorials/Highlight.qml new file mode 100644 index 00000000..bb4db78f --- /dev/null +++ b/src/tutorials/Highlight.qml @@ -0,0 +1,19 @@ +// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
+import QtQuick 1.1
+
+Rectangle {
+ radius: 10
+ color: "transparent"
+ height: 100
+ border.color: "black"
+ border.width: 3
+ opacity: 0.9
+ smooth: true
+
+ SequentialAnimation on opacity {
+ loops: Animation.Infinite
+
+ PropertyAnimation { easing.type: Easing.InOutSine; duration: 300; to: 0.1 }
+ PropertyAnimation { easing.type: Easing.OutInSine; duration: 300; to: 0.7 }
+ }
+}
diff --git a/src/tutorials/TutorialDescription.qml b/src/tutorials/TutorialDescription.qml new file mode 100644 index 00000000..b295e477 --- /dev/null +++ b/src/tutorials/TutorialDescription.qml @@ -0,0 +1,54 @@ +import QtQuick 1.1
+
+// rectangle for description texts
+Rectangle {
+ property alias text: textBox.text
+ property alias continueVisible: continueIcon.visible
+ property int innerWidth;
+ signal clicked
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 100
+ width: textBox.width + 30
+ height: textBox.height + 8
+ border.color: "black"
+ border.width: 3
+ smooth: true
+ opacity: 0.9
+ color: "#707070"
+
+ Image {
+ id: continueIcon
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 5
+ anchors.right: parent.right
+ anchors.rightMargin: 5
+ source: "qrc:/MO/gui/next"
+
+ SequentialAnimation on opacity {
+ loops: Animation.Infinite
+
+ PauseAnimation { duration: 500 }
+ PropertyAnimation { easing.type: Easing.InOutSine; duration: 400; to: 0.0 }
+ PropertyAnimation { easing.type: Easing.OutInSine; duration: 400; to: 1.0 }
+ }
+ }
+
+ Text {
+ id: textBox
+ text: ""
+ font.pointSize: 12
+ font.bold: false
+ width: innerWidth
+ font.family: "Courier"
+ wrapMode: Text.WordWrap
+ anchors.centerIn: parent
+ }
+
+ MouseArea {
+ id: clickArea
+ anchors.fill: parent
+ onClicked: parent.clicked(mouse)
+ }
+}
diff --git a/src/tutorials/TutorialOverlay.qml b/src/tutorials/TutorialOverlay.qml new file mode 100644 index 00000000..34959d7d --- /dev/null +++ b/src/tutorials/TutorialOverlay.qml @@ -0,0 +1,53 @@ +// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
+import QtQuick 1.1
+import "tutorials.js" as Logic
+
+Rectangle {
+ color: "transparent"
+
+ property int step : 0
+ property alias description: tutDescription
+ property alias highlight: tutHighlight
+ property alias text: tutDescription.text
+ property alias boxOpacity: tutDescription.opacity
+ property int offsetBottom: 50
+ property int maxWidth: 400
+
+ function init() {
+ Logic.init()
+ Logic.nextStep()
+ }
+
+ function enableBackground(enabled) {
+ disabledBackground.visible = enabled
+ }
+
+ signal nextStep
+
+ onNextStep: {
+ if (step == 0) {
+ Logic.init()
+ }
+
+ Logic.nextStep()
+ }
+
+ TutorialDescription {
+ id: tutDescription
+ innerWidth: maxWidth
+ anchors.bottomMargin: offsetBottom
+ onClicked: {
+ Logic.clickNext()
+ }
+ }
+
+ Rectangle {
+ id: disabledBackground
+ anchors.fill: parent
+ opacity: 0.2
+ color: "#808080"
+ }
+
+ Highlight { id: tutHighlight }
+
+}
diff --git a/src/tutorials/tutorial_basics.js b/src/tutorials/tutorial_basics.js new file mode 100644 index 00000000..c8776b28 --- /dev/null +++ b/src/tutorials/tutorial_basics.js @@ -0,0 +1,2 @@ +function tutorial() {
+}
diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js new file mode 100644 index 00000000..3a7160c6 --- /dev/null +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -0,0 +1,164 @@ +//TL Conflict Resolution#10
+function getTutorialSteps() {
+ return [
+ function() {
+ tutorial.text = qsTr("There are multiple types of conflicts you may encounter when dealing with Mods. "
+ +"This tutorial will try to cover and explain how to deal with all of them.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("First up are file conflicts. These occur when two mods contain the same file. "
+ +"Most commonly this happens when several mods replace the same standard asset from "
+ +"the game, like the texture of an armor.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("As an example, say you install \"ModA\" which contains stylish new iron and leather armor. "
+ +"Then you install \"ModB\" which contains sexy ebony and leather armor. Obviously there is a "
+ +"conflict now: which leather armor to use?")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("If you were to install the mods manually, when installing \"ModB\" you would be asked if you want "
+ +"to overwrite conflicting files. If you choose yes, you get the leather armor from \"ModB\" otherwise "
+ +"you keep the one from \"ModA\". If you later decide you made the wrong choice, "
+ +"you have to reinstall one of the mods.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("With MO, both ModA and ModB get installed completely (no overwrite dialog) and by default "
+ +"\"ModB\" gets to provide the leather armor because it's automatically assigned the higher priority.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("However, you can change the mod priority at any time using drag&drop on this list. "
+ +"If you assign \"ModA\" a higher priority, it provides the leather armor, no re-installation required. "
+ +"Since the priorities of mods in this list are treated as if the mods were installed in that order, "
+ +"I tend to talk about \"installation order\".")
+ highlightItem("modList", false)
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("If the \"Flags\"-column is enabled in the mod list, it will show you which mods are involved in a conflict and how...")
+ waitForClick()
+ },
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("<img src=\":/MO/gui/emblem_conflict_overwrite\" /> indicates that the mod overwrites files that are also available in another mod.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("<img src=\":/MO/gui/emblem_conflict_overwritten\" /> indicates that the mod is <b>partially</b> overwritten by another.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("<img src=\":/MO/gui/emblem_conflict_mixed\" /> indicates that both of the above is true.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("<img src=\":/MO/gui/emblem_conflict_redundant\" /> indicates that the mod is completely overwrtten by another. You could as well disable it.");
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("There are two ways to see the individual files involved in a conflict:")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("Option A: Switch to the \"Data\"-tab if necessary")
+ if (!tutorialControl.waitForTabOpen("tabWidget", 2)) {
+ highlightItem("tabWidget", false)
+ waitForClick()
+ } else {
+ highlightItem("tabWidget", true)
+ }
+ },
+ function() {
+ tutorial.text = qsTr("... here, if you mark the highlighted control, the tree will only display files in conflict. "
+ +"In the right column, it says which mod currently provides the mod (because it has highest priority) "
+ +"and if you hover your mouse over that info, it will list which other mods contains it.")
+ highlightItem("conflictsCheckBox", false)
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("Option B: Open the <i>Information</i>-Dialog of an <b>enabled</b> mod you're interested in by "
+ +"either double-clicking it or selecting <i>Information...</i> from the right-click menu")
+ highlightItem("modList", true)
+ manager.activateTutorial("ModInfoDialog", "tutorial_conflictresolution_modinfo.js")
+ applicationWindow.modInfoDisplayed.connect(nextStep)
+ },
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("This was everything to know about file conflicts. The second type of conflict we have to deal with "
+ +"are \"record conflicts\".")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("I told you in the \"First Steps\" tutorial how the esp/esm plugins contain changes to the game world "
+ +"like modifications to the terrain or existing NPCs. Each change like this is stored in a record, hence the "
+ +"name \"record conflict\". For example when two mods try to change the same location, only one change can become active.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("As with file conflicts you can't really fix these conflicts, you have to choose which change you want. "
+ +"This time around however, if you choose wrong, your game may become unstable because there may be "
+ +"dependencies between the records of a mod.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("Please open the \"ESPs\"-tab...")
+ highlightItem("tabWidget", true)
+ if (!tutorialControl.waitForTabOpen("tabWidget", 0)) {
+ nextStep()
+ }
+ },
+ function() {
+ tutorial.text = qsTr("Again you can use drag&drop to change priorities of plugins, thus deciding which plugin takes "
+ +"precedence in regards to conflicts. This is commonly called the \"load order\". "
+ +"But how do you know how to order the plugins?")
+ waitForClick()
+ },
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("Unlike with file conflicts, MO does not provide help on finding conflicts. The good news is, there "
+ +"already is a perfect tool for that called BOSS. BOSS is available on the Nexus and integrates "
+ +"neatly with MO. Basically, if you don't have BOSS yet, install it once this tutorial is over.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("After you installed BOSS in the default location (follow its instructions), start MO again and BOSS should automatically appear as an Executable...")
+ highlightItem("startGroup", false)
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("When you run BOSS, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). "
+ +"It will also open a report in your browser that warns about incompatibilities. You should read the report, at least "
+ +"for new mods.")
+ waitForClick()
+ },
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("The final type of conflicts are also \"record conflicts\". Like the previous type. It's confusing, so "
+ +"I'll just call them \"lists conflicts\" instead. The difference is the types of "
+ +"records in conflict. The ones in question here can be merged so you may be able to get all modifications in your game.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("One common example of such records are leveled lists that contain all the items that may spawn at a specific "
+ +"character level. Traditionally, if multiple mods add items to such a list, only one is in effect...")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("... but there are tools to merge those mods so you can have the effects of all of them. Again, this "
+ +"functionality is not integrated with MO because there are already great tools. For Oblivion and Skyrim "
+ +"look for wrye bash, for fallout 3/nv it's wrye flash. For Skyrim there is also "
+ +"\"SkyBash\". All of these can create a so-called \"bashed patch\" which is a plugin that contains the combined "
+ +"mergeable records from all your mods.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("This completes the tutorial.")
+ waitForClick()
+ }
+
+ ]
+}
diff --git a/src/tutorials/tutorial_conflictresolution_modinfo.js b/src/tutorials/tutorial_conflictresolution_modinfo.js new file mode 100644 index 00000000..b5ef461e --- /dev/null +++ b/src/tutorials/tutorial_conflictresolution_modinfo.js @@ -0,0 +1,21 @@ +function getTutorialSteps() {
+ return [
+ function() {
+ tutorial.text = qsTr("Please switch to the \"Conflicts\"-Tab.")
+ highlightItem("tabWidget", true)
+ if (!tutorialControl.waitForTabOpen("tabWidget", 4)) {
+ nextStep()
+ }
+ },
+ function() {
+ tutorial.text = qsTr("Here you can see a list of files in this mod that out-prioritize others "
+ +"in a file conflict and one with files where this mod is overridden.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("Please close the information dialog again.")
+ waitForClick()
+ }
+
+ ]
+}
diff --git a/src/tutorials/tutorial_firststeps.js b/src/tutorials/tutorial_firststeps.js new file mode 100644 index 00000000..bf3cad38 --- /dev/null +++ b/src/tutorials/tutorial_firststeps.js @@ -0,0 +1,5 @@ +// First Steps
+subTutorials = [
+ ["MainWindow", "tutorial_firststeps_main.js"],
+ ["SettingsDialog", "tutorial_firststeps_settings.js"]
+ ];
diff --git a/src/tutorials/tutorial_firststeps_browser.js b/src/tutorials/tutorial_firststeps_browser.js new file mode 100644 index 00000000..062cc18c --- /dev/null +++ b/src/tutorials/tutorial_firststeps_browser.js @@ -0,0 +1,12 @@ +function getTutorialSteps()
+{
+ return [
+ function() {
+ tutorial.text = qsTr("This is a fully featured browser that is set up to "
+ +"open the correct nexus page for your game. You can "
+ +"download any mod using the \"DOWNLOAD WITH MANAGER\"-button "
+ +"or the \"manual\"-link and it will be downloaded by MO.")
+ waitForClick()
+ }
+ ]
+}
diff --git a/src/tutorials/tutorial_firststeps_main.js b/src/tutorials/tutorial_firststeps_main.js new file mode 100644 index 00000000..9785dc42 --- /dev/null +++ b/src/tutorials/tutorial_firststeps_main.js @@ -0,0 +1,172 @@ +//TL First Steps#0
+function getTutorialSteps()
+{
+ return [
+ function() {
+ tutorial.text = qsTr("Welcome to the ModOrganizer Tutorial! This will guide you through the most important features of the program.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("Before we continue with the step-by-step tutorial, I'd like to tell you about the other ways you can receive help on ModOrganizer.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("The highlighted button provides hints on solving problems MO recognized automatically.")
+ if (!tutorialControl.waitForAction("actionProblems")) {
+ highlightAction("actionProblems", false)
+ waitForClick()
+ } else {
+ tutorial.text += qsTr("\nThere IS a problem now but you may want to hold off on fixing it until after completing the tutorial.")
+ highlightAction("actionProblems", true)
+ }
+ },
+
+ function() {
+ tutorial.text = qsTr("This button provides multiple sources of information and further tutorials.")
+ highlightItem("actionHelp", true)
+ tutorialControl.waitForButton("actionHelp")
+ },
+
+ function() {
+ tutorial.text = qsTr("Finally there are tooltips on almost every part of Mod Organizer. If there is a control "
+ + "in MO you don't understand, please try hovering over it to get a short description or "
+ + "use \"Help on UI\" from the help menu to get a longer explanation")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("This list displays all mods installed through MO. The first point in our agenda will be adding some stuff to it.")
+ highlightItem("modList", false)
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("There are a few ways to get mods into ModOrganizer. The easiest is to use the embedded nexus browser. Click \"Nexus\"")
+ highlightAction("actionNexus", true)
+ manager.activateTutorial("NexusDialog", "tutorial_firststeps_browser.js")
+ tutorialControl.waitForAction("actionNexus")
+ },
+
+ function() {
+ tutorial.text = qsTr("Downloads will appear here. Double click one to install it.")
+ applicationWindow.modInstalled.connect(nextStep)
+ highlightItem("downloadView", true)
+ },
+
+ function() {
+ unhighlight()
+ applicationWindow.modInstalled.disconnect(nextStep)
+ tutorial.text = qsTr("Great, you just installed your first mod. Please note that the installation procedure may differ based on how a mod was packaged.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("I promised you multiple ways of getting mods into MO. Please open the settings dialog now.")
+ highlightAction("actionSettings", true)
+ manager.activateTutorial("SettingsDialog", "tutorial_firststeps_settings.js")
+ tutorialControl.waitForAction("actionSettings")
+ },
+
+ function() {
+ tutorial.text = qsTr("So far I only showed you how to get mods from Nexus.\n"
+ + "You can also install mods from disk using the \"Install Mod\" button.")
+ highlightAction("actionInstallMod", false)
+ waitForClick()
+ },
+
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("Now you know all about downloading and installing mods but they are not enabled yet...")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("Install a few more mods if you want, then enable mods by checking them in the left pane. "
+ + "Mods that aren't enabled have no effect on the game whatsoever. ")
+ highlightItem("modList", true)
+ modList.modlist_changed.connect(nextStep)
+ },
+
+ function() {
+ modList.modlist_changed.disconnect(nextStep)
+ unhighlight()
+ tutorial.text = qsTr("For some mods, enabling it on the left pane is all you have to do...")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("...but most contain plugins. These are plugins for the game and are required "
+ +"to add stuff to the game (new weapons, armors, quests, areas, ...). "
+ +"Please open the \"ESPs\"-tab to get a list of plugins.")
+ if (tutorialControl.waitForTabOpen("tabWidget", 0)) {
+ highlightItem("tabWidget", true)
+ } else {
+ waitForClick()
+ }
+ },
+
+ function() {
+ tutorial.text = qsTr("You will notice some plugins are grayed out. These are part of the main game and can't be "
+ +"disabled.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("A single mod may contain zero, one or multiple esps. Some or all may be optional. "
+ + "If in doubt, please consult the documentation of the indiviual mod. "
+ + "To do so, right-click the mod and select \"Information\".")
+ highlightItem("modList", true)
+ manager.activateTutorial("ModInfoDialog", "tutorial_firststeps_modinfo.js")
+ applicationWindow.modInfoDisplayed.connect(nextStep)
+ },
+
+ function() {
+ tutorial.text = qsTr("Another special type of files are BSAs. These are bundles of game resources. "
+ + "Please open the \"BSAs\"-tab.")
+ if (tutorialControl.waitForTabOpen("tabWidget", 1)) {
+ highlightItem("tabWidget", true)
+ } else {
+ waitForClick()
+ }
+ },
+
+ function() {
+ tutorial.text = qsTr("These archives can be a real headache because the way bsas interact "
+ + "with non-bundled resources is complicated. The game can even crash if required "
+ + "archives are not loaded or ordered incorrectly.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("MO applies some \"magic\" to make all BSAs that are checked in this list load in "
+ + "the correct order interleaved with the non-bundled resources. Usually it's best "
+ + "to check all bsas that have an exclamation mark at the side.")
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("Now you know how to download, install and enable mods.\n"
+ + "It's important you always start the game from inside MO, otherwise "
+ + "the mods you installed here won't work.")
+ highlightItem("startGroup", false)
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("This combobox lets you choose <i>what</i> to start. This way you can start the game, Launcher, "
+ + "Script Extender, the Creation Kit or other tools. If you miss a tool you can also configure this list "
+ + "but that is an advanced topic.")
+ highlightItem("executablesListBox", false)
+ waitForClick()
+ },
+
+ function() {
+ tutorial.text = qsTr("This completes the basic tutorial. As homework go play a bit! After you "
+ + "have installed more mods you may want to read the tutorial on conflict resolution.")
+ highlightItem("startButton", false)
+ waitForClick()
+ }
+ ]
+}
diff --git a/src/tutorials/tutorial_firststeps_modinfo.js b/src/tutorials/tutorial_firststeps_modinfo.js new file mode 100644 index 00000000..3c56d1f4 --- /dev/null +++ b/src/tutorials/tutorial_firststeps_modinfo.js @@ -0,0 +1,24 @@ +function getTutorialSteps()
+{
+ return [
+ function() {
+ tutorial.text = qsTr("This dialog tries to expose as much information about a mod as possible. "
+ +"Depending on the mod this may include readmes, screenshots, optional plugins and so on. "
+ +"If a certain type of information was not found in a mod, the corresponding tab "
+ +"is grayed out.")
+ highlightItem("tabWidget", false)
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("If you installed the mod from Nexus, the corresponding tab should give you direct "
+ +"access to the mod page. That tab can also be used to download optional packages "
+ +"or updates for the mod.")
+ waitForClick()
+ },
+ function() {
+ unhighlight()
+ tutorial.text = qsTr("We may re-visit this screen in later tutorials.")
+ waitForClick()
+ }
+ ]
+}
diff --git a/src/tutorials/tutorial_firststeps_settings.js b/src/tutorials/tutorial_firststeps_settings.js new file mode 100644 index 00000000..2bff4251 --- /dev/null +++ b/src/tutorials/tutorial_firststeps_settings.js @@ -0,0 +1,25 @@ +function getTutorialSteps()
+{
+ return [
+ function() {
+ highlightItem("tabWidget", true)
+ tutorial.text = qsTr("You can use your regular browser to download from Nexus.\nPlease open the \"Nexus\"-tab")
+ tutorialControl.waitForTabOpen("tabWidget", 2)
+ },
+
+ function() {
+ highlightItem("handleNXMBox", false)
+ tutorial.text = qsTr("If this box is checked the \"DOWNLOAD WITH MANAGER\"-buttons "
+ +"in your regular browser will also download with Mod Organizer.")
+ waitForClick()
+ },
+
+ function() {
+ highlightItem("nexusBox", false)
+ tutorial.text = qsTr("You can also store your Nexus-credentials "
+ +"here for automatic login. The password is "
+ +"stored unencrypted on your disk!")
+ waitForClick()
+ }
+ ]
+}
diff --git a/src/tutorials/tutorial_window_installer.js b/src/tutorials/tutorial_window_installer.js new file mode 100644 index 00000000..a2779234 --- /dev/null +++ b/src/tutorials/tutorial_window_installer.js @@ -0,0 +1,37 @@ +//WIN InstallDialog
+function getTutorialSteps()
+{
+ return [
+ function() {
+ tutorial.text = qsTr("This mod has been packaged in a way that Mod Organizer did not automatically "
+ + "recognize...")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("You can use drag&drop on this list to fix the structure of the mod.")
+ highlightItem("treeContent", false)
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("The correct structure replicates the data-directory of the game. That means "
+ + "esps, the \"meshes\"- or \"textures\"-directory and so on should be directly "
+ + "below \"<data>\".")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("You can also disable files and directories that you don't want to unpack.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("From the context menu (right-click) you can open textfiles, in case "
+ + "you want to access a readme.")
+ waitForClick()
+ },
+ function() {
+ tutorial.text = qsTr("This text will turn green if MO thinks the structure looks good.")
+ highlightItem("problemLabel", false)
+ manager.finishWindowTutorial("InstallDialog")
+ waitForClick()
+ }
+ ]
+}
diff --git a/src/tutorials/tutorials.js b/src/tutorials/tutorials.js new file mode 100644 index 00000000..f2b18856 --- /dev/null +++ b/src/tutorials/tutorials.js @@ -0,0 +1,75 @@ +var tutorialSteps = []
+var waitingForClick = false
+
+
+function highlightItem(widgetName, click) {
+ var rect = tutorialControl.getRect(widgetName)
+ highlight.x = rect.x - 1
+ highlight.y = rect.y - 1
+ highlight.width = rect.width + 2
+ highlight.height = rect.height + 2
+ if (click) {
+ highlight.border.color = "green"
+ } else {
+ highlight.border.color = "blue"
+ }
+ highlight.visible = true
+}
+
+function highlightAction(actionName, click) {
+ var rect = tutorialControl.getActionRect(actionName)
+ highlight.x = rect.x - 1
+ highlight.y = rect.y - 1
+ highlight.width = rect.width + 2
+ highlight.height = rect.height + 2
+ if (click) {
+ highlight.border.color = "green"
+ } else {
+ highlight.border.color = "blue"
+ }
+ highlight.visible = true
+}
+
+function unhighlight()
+{
+ highlight.visible = false
+}
+
+function waitForClick()
+{
+ waitingForClick = true;
+ description.continueVisible = true
+ // ui needs to be locked, otherwise the tutorial-view does not receive mouse-events!
+ tutorialControl.lockUI(true)
+}
+
+function clickNext()
+{
+ if (waitingForClick) {
+ nextStep()
+ }
+}
+
+function nextStep()
+{
+ waitingForClick = false;
+ description.continueVisible = false
+ if (step < tutorialSteps.length) {
+ tutorialControl.lockUI(false)
+ step++
+ tutorialSteps[step - 1]()
+ } else {
+ tutorialControl.finish()
+ }
+}
+
+function init()
+{
+ var res = Qt.include("file:///" + scriptName)
+ if (res.status !== 0) {
+ console.log("failed to load " + scriptName + ": " + res.status)
+ return
+ }
+
+ tutorialSteps = getTutorialSteps()
+}
diff --git a/src/tutorials/tutorials_installdialog.qml b/src/tutorials/tutorials_installdialog.qml new file mode 100644 index 00000000..33f0a660 --- /dev/null +++ b/src/tutorials/tutorials_installdialog.qml @@ -0,0 +1,7 @@ +import QtQuick 1.1
+
+TutorialOverlay {
+ id: tutorial
+ offsetBottom: 65
+ maxWidth: 420
+}
diff --git a/src/tutorials/tutorials_mainwindow.qml b/src/tutorials/tutorials_mainwindow.qml new file mode 100644 index 00000000..6b4e6b30 --- /dev/null +++ b/src/tutorials/tutorials_mainwindow.qml @@ -0,0 +1,8 @@ +import QtQuick 1.1
+
+
+TutorialOverlay {
+ id: tutorial
+ offsetBottom: 50
+ maxWidth: 400
+}
diff --git a/src/tutorials/tutorials_modinfodialog.qml b/src/tutorials/tutorials_modinfodialog.qml new file mode 100644 index 00000000..e9a56cb3 --- /dev/null +++ b/src/tutorials/tutorials_modinfodialog.qml @@ -0,0 +1,7 @@ +import QtQuick 1.1
+
+TutorialOverlay {
+ id: tutorial
+ offsetBottom: 60
+ maxWidth: 420
+}
diff --git a/src/tutorials/tutorials_nexusdialog.qml b/src/tutorials/tutorials_nexusdialog.qml new file mode 100644 index 00000000..6a7af6d6 --- /dev/null +++ b/src/tutorials/tutorials_nexusdialog.qml @@ -0,0 +1,8 @@ +import QtQuick 1.1
+
+TutorialOverlay {
+ id: tutorial
+ offsetBottom: 40
+ maxWidth: 600
+ boxOpacity: 0.95
+}
diff --git a/src/tutorials/tutorials_settingsdialog.qml b/src/tutorials/tutorials_settingsdialog.qml new file mode 100644 index 00000000..e9a56cb3 --- /dev/null +++ b/src/tutorials/tutorials_settingsdialog.qml @@ -0,0 +1,7 @@ +import QtQuick 1.1
+
+TutorialOverlay {
+ id: tutorial
+ offsetBottom: 60
+ maxWidth: 420
+}
diff --git a/src/version.rc b/src/version.rc new file mode 100644 index 00000000..c1f85d9f --- /dev/null +++ b/src/version.rc @@ -0,0 +1,21 @@ +#include "Winver.h"
+
+#define VER_FILEVERSION 0,12,6,0
+#define VER_FILEVERSION_STR 0,12,6,0
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_FILEVERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS (0)
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_APP
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ VALUE "CompanyName", "Tannin"
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ END
+
+END
|
