From 7500c9f9921b2c16566a80e412d31dc59eb0d57c Mon Sep 17 00:00:00 2001 From: Branan Purvine-Riley Date: Fri, 20 Jan 2012 16:47:27 -0800 Subject: [PATCH] Import plLocalizationEditor --- Sources/Tools/CMakeLists.txt | 1 + .../Tools/plLocalizationEditor/CMakeLists.txt | 41 ++ .../Tools/plLocalizationEditor/plAddDlgs.cpp | 413 ++++++++++++++++++ .../Tools/plLocalizationEditor/plAddDlgs.h | 84 ++++ .../Tools/plLocalizationEditor/plEditDlg.cpp | 316 ++++++++++++++ .../Tools/plLocalizationEditor/plEditDlg.h | 72 +++ .../plLocalizationEditor/plLocTreeView.cpp | 213 +++++++++ .../plLocalizationEditor/plLocTreeView.h | 65 +++ .../plLocalizationEditor.cpp | 394 +++++++++++++++++ .../Tools/plLocalizationEditor/res/icon1.ico | Bin 0 -> 2998 bytes .../res/plLocalizationEditor.rc | 268 ++++++++++++ .../Tools/plLocalizationEditor/res/resource.h | 51 +++ 12 files changed, 1918 insertions(+) create mode 100644 Sources/Tools/plLocalizationEditor/CMakeLists.txt create mode 100644 Sources/Tools/plLocalizationEditor/plAddDlgs.cpp create mode 100644 Sources/Tools/plLocalizationEditor/plAddDlgs.h create mode 100644 Sources/Tools/plLocalizationEditor/plEditDlg.cpp create mode 100644 Sources/Tools/plLocalizationEditor/plEditDlg.h create mode 100644 Sources/Tools/plLocalizationEditor/plLocTreeView.cpp create mode 100644 Sources/Tools/plLocalizationEditor/plLocTreeView.h create mode 100644 Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp create mode 100644 Sources/Tools/plLocalizationEditor/res/icon1.ico create mode 100644 Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc create mode 100644 Sources/Tools/plLocalizationEditor/res/resource.h diff --git a/Sources/Tools/CMakeLists.txt b/Sources/Tools/CMakeLists.txt index a9d02543..ffc86803 100644 --- a/Sources/Tools/CMakeLists.txt +++ b/Sources/Tools/CMakeLists.txt @@ -1,5 +1,6 @@ #add_subdirectory(Migration) #add_subdirectory(plDatMerger) +add_subdirectory(plLocalizationEditor) add_subdirectory(plResBrowser) if(FREETYPE_FOUND) diff --git a/Sources/Tools/plLocalizationEditor/CMakeLists.txt b/Sources/Tools/plLocalizationEditor/CMakeLists.txt new file mode 100644 index 00000000..bf8432cf --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories("../../Plasma/CoreLib") +include_directories("../../Plasma/NucleusLib") +include_directories("../../Plasma/NucleusLib/inc") +include_directories("../../Plasma/PubUtilLib") +include_directories("../../Plasma/FeatureLib") + +add_definitions("-DUNICODE") + +set(plLocalizationEditor_HEADERS + plAddDlgs.h + plEditDlg.h + plLocTreeView.h +) + +set(plLocalizationEditor_SOURCES + plAddDlgs.cpp + plEditDlg.cpp + plLocalizationEditor.cpp + plLocTreeView.cpp +) + +set(plLocalizationEditor_RESOURCES + res/plLocalizationEditor.rc + res/resource.h + res/icon1.ico +) + +add_executable(plLocalizationEditor WIN32 ${plLocalizationEditor_HEADERS} ${plLocalizationEditor_SOURCES} ${plLocalizationEditor_RESOURCES}) + +target_link_libraries(plLocalizationEditor CoreLib) +target_link_libraries(plLocalizationEditor CoreLibExe) +target_link_libraries(plLocalizationEditor pnProduct) +target_link_libraries(plLocalizationEditor pnSceneObject) +target_link_libraries(plLocalizationEditor plResMgr) +target_link_libraries(plLocalizationEditor pfLocalizationMgr) +target_link_libraries(plLocalizationEditor ${EXPAT_LIBRARY}) +target_link_libraries(plLocalizationEditor comctl32) + +source_group("Source Files" FILES ${plLocalizationEditor_SOURCES}) +source_group("Header Files" FILES ${plLocalizationEditor_HEADERS}) +source_group("Resource Files" FILES ${plLocalizationEditor_RESOURCES}) diff --git a/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp b/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp new file mode 100644 index 00000000..e4f92450 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp @@ -0,0 +1,413 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +// basic classes for encapsulating the add dialogs + +#include "res/resource.h" +#include "plAddDlgs.h" +#include "plEditDlg.h" + +#include "hsUtils.h" +#include "plResMgr/plLocalization.h" +#include "pfLocalizationMgr/pfLocalizationDataMgr.h" + +#include +#include + +extern HINSTANCE gInstance; + +// very simple subclass for edit controls (and combo boxes) so that they only accept alphanumeric values +class AlphaNumericEditCtrl +{ + int fCtrlID; + HWND fOwner, fEditBox; + LONG_PTR fPrevProc; + +public: + AlphaNumericEditCtrl() : fCtrlID(0), fOwner(NULL), fEditBox(NULL), fPrevProc(NULL) {} + ~AlphaNumericEditCtrl() {} + + void Setup(int ctrlID, HWND owner, bool comboBox); + static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +}; + +std::map editBoxMap; + +// basic setup of the edit control +void AlphaNumericEditCtrl::Setup(int ctrlID, HWND owner, bool comboBox) +{ + fCtrlID = ctrlID; + fOwner = owner; + + // if we're a combo box, we need to subclass the edit control, not the combo box + if (comboBox) + { + COMBOBOXINFO cbinfo; + cbinfo.cbSize = sizeof(COMBOBOXINFO); + GetComboBoxInfo(GetDlgItem(fOwner, fCtrlID), &cbinfo); + fEditBox = cbinfo.hwndItem; + } + else + fEditBox = GetDlgItem(fOwner, fCtrlID); + + // subclass the edit box so we can filter input (don't ask me why we have to double cast the + // function pointer to get rid of the compiler warning) + fPrevProc = SetWindowLongPtr(fEditBox, GWLP_WNDPROC, (LONG)(LONG_PTR)AlphaNumericEditCtrl::WndProc); + + editBoxMap[fCtrlID] = *this; +} + +// Message handler for our edit box +LRESULT CALLBACK AlphaNumericEditCtrl::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int ctrlID = GetDlgCtrlID(hWnd); + if (editBoxMap.find(ctrlID) == editBoxMap.end()) // control ID doesn't exist, so it's probably a combo boxes' edit ctrl + ctrlID = GetDlgCtrlID(GetParent(hWnd)); // so grab the parent's ID number instead + switch (message) + { + case WM_CHAR: + { + AlphaNumericEditCtrl editBox = editBoxMap[ctrlID]; + char theChar = (char)wParam; + + // we only accept 0-9, a-z, A-Z, or backspace + if ((theChar < '0' || theChar > '9') && (theChar < 'a' || theChar > 'z') && (theChar < 'A' || theChar >'Z') && !(theChar == VK_BACK)) + { + MessageBeep(-1); // alert the user + return FALSE; // and make sure the default handler doesn't get it + } + } + } + // Any messages we don't process must be passed onto the original window function + return CallWindowProc((WNDPROC)editBoxMap[ctrlID].fPrevProc, hWnd, message, wParam, lParam); +} + +// plAddElementDlg - dialog for adding a single element +BOOL CALLBACK plAddElementDlg::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static plAddElementDlg* pthis = NULL; + + switch (msg) + { + case WM_INITDIALOG: + pthis = (plAddElementDlg*)lParam; + if (!pthis->IInitDlg(hDlg)) + EndDialog(hDlg, 0); + return FALSE; + + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK) + { + EndDialog(hDlg, 1); + return TRUE; + } + else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, 0); + return TRUE; + } + else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_PARENTAGE) + { + wchar_t buff[256]; + // we do this whole get sel, get item because get text won't return the updated text + int index = (int)SendMessage(GetDlgItem(hDlg, IDC_PARENTAGE), CB_GETCURSEL, (WPARAM)0, (LPARAM)0); + SendMessage(GetDlgItem(hDlg, IDC_PARENTAGE), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff); + + pthis->fAgeName = buff; + pthis->fAgeChanged = true; + pthis->IUpdateDlg(hDlg); + } + else if (HIWORD(wParam) == CBN_EDITCHANGE && LOWORD(wParam) == IDC_PARENTAGE) + { + wchar_t buff[256]; + GetDlgItemTextW(hDlg, IDC_PARENTAGE, buff, 256); + + pthis->fAgeName = buff; + pthis->fAgeChanged = true; + pthis->IUpdateDlg(hDlg, false); + } + else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_PARENTSET) + { + wchar_t buff[256]; + // we do this whole get sel, get item because get text won't return the updated text + int index = (int)SendMessage(GetDlgItem(hDlg, IDC_PARENTSET), CB_GETCURSEL, (WPARAM)0, (LPARAM)0); + SendMessage(GetDlgItem(hDlg, IDC_PARENTSET), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff); + + pthis->fSetName = buff; + pthis->IUpdateDlg(hDlg); + } + else if (HIWORD(wParam) == CBN_EDITCHANGE && LOWORD(wParam) == IDC_PARENTSET) + { + wchar_t buff[256]; + GetDlgItemTextW(hDlg, IDC_PARENTSET, buff, 256); + + pthis->fSetName = buff; + pthis->IUpdateDlg(hDlg, false); + } + else if (HIWORD(wParam) == EN_UPDATE && LOWORD(wParam) == IDC_ELEMENTNAME) + { + wchar_t buff[256]; + GetDlgItemTextW(hDlg, IDC_ELEMENTNAME, buff, 256); + pthis->fElementName = buff; + + pthis->IUpdateDlg(hDlg); + } + break; + + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_CLOSE: + EndDialog(hDlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +bool plAddElementDlg::IInitDlg(HWND hDlg) +{ + HWND listCtrl = GetDlgItem(hDlg, IDC_PARENTAGE); + std::vector ageNames = pfLocalizationDataMgr::Instance().GetAgeList(); + + // add the age names to the list + for (int i = 0; i < ageNames.size(); i++) + SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)ageNames[i].c_str()); + + // select the age we were given + SendMessage(listCtrl, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)fAgeName.c_str()); + + AlphaNumericEditCtrl ageCtrl, setCtrl, subCtrl; + ageCtrl.Setup(IDC_PARENTAGE, hDlg, true); + setCtrl.Setup(IDC_PARENTSET, hDlg, true); + subCtrl.Setup(IDC_ELEMENTNAME, hDlg, false); + + fAgeChanged = true; + + IUpdateDlg(hDlg); + return true; +} + +void plAddElementDlg::IUpdateDlg(HWND hDlg, bool setFocus) +{ + std::wstring pathStr = L"Path: " + fAgeName + L"." + fSetName + L"." + fElementName; + SetDlgItemTextW(hDlg, IDC_PATH, pathStr.c_str()); + + if (fAgeChanged) // we only update this if the age changed (saves time and prevents weird bugs, like typing backwards) + { + // now add the sets + HWND listCtrl = GetDlgItem(hDlg, IDC_PARENTSET); + SendMessage(listCtrl, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0); + std::vector setNames = pfLocalizationDataMgr::Instance().GetSetList(fAgeName); + + // add the set names to the list + for (int i = 0; i < setNames.size(); i++) + SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)setNames[i].c_str()); + + // select the set we currently have + int ret = (int)SendMessage(listCtrl, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)fSetName.c_str()); + if (ret == CB_ERR) // couldn't find the string, so just set it as the current string in the edit box + SetDlgItemTextW(hDlg, IDC_PARENTSET, fSetName.c_str()); + + fAgeChanged = false; + } + + if (fSetName != L"" && setFocus) + SetFocus(GetDlgItem(hDlg, IDC_ELEMENTNAME)); + + if (fSetName != L"" && fElementName != L"") + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + else + EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); +} + +plAddElementDlg::plAddElementDlg(std::wstring parentPath) +{ + // throw away vars + std::wstring element, lang; + + SplitLocalizationPath(parentPath, fAgeName, fSetName, element, lang); +} + +bool plAddElementDlg::DoPick(HWND parent) +{ + INT_PTR ret = DialogBoxParam(gInstance, MAKEINTRESOURCE(IDD_ADDELEMENT), + parent, IDlgProc, (LPARAM)this); + + editBoxMap.clear(); + + return (ret != 0); +} + +// plAddLocalizationDlg - dialog for adding a single localization +BOOL CALLBACK plAddLocalizationDlg::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static plAddLocalizationDlg* pthis = NULL; + + switch (msg) + { + case WM_INITDIALOG: + pthis = (plAddLocalizationDlg*)lParam; + if (!pthis->IInitDlg(hDlg)) + EndDialog(hDlg, 0); + return FALSE; + + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK) + { + EndDialog(hDlg, 1); + return TRUE; + } + else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, 0); + return TRUE; + } + else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_LANGUAGE) + { + wchar_t buff[256]; + // we do this whole get sel, get item because get text won't return the updated text + int index = (int)SendMessage(GetDlgItem(hDlg, IDC_LANGUAGE), CB_GETCURSEL, (WPARAM)0, (LPARAM)0); + SendMessage(GetDlgItem(hDlg, IDC_LANGUAGE), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff); + + pthis->fLanguageName = buff; + pthis->IUpdateDlg(hDlg); + } + break; + + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_CLOSE: + EndDialog(hDlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +std::vector IGetAllLanguageNames() +{ + int numLocales = plLocalization::GetNumLocales(); + std::vector retVal; + + for (int curLocale = 0; curLocale <= numLocales; curLocale++) + { + const char *name = plLocalization::GetLanguageName((plLocalization::Language)curLocale); + wchar_t *wName = hsStringToWString(name); + retVal.push_back(wName); + delete [] wName; + } + + return retVal; +} + +bool plAddLocalizationDlg::IInitDlg(HWND hDlg) +{ + std::wstring pathStr = L"Path: " + fAgeName + L"." + fSetName + L"." + fElementName; + SetDlgItemTextW(hDlg, IDC_PATH, pathStr.c_str()); + + std::vector existingLanguages; + existingLanguages = pfLocalizationDataMgr::Instance().GetLanguages(fAgeName, fSetName, fElementName); + + std::vector missingLanguages = IGetAllLanguageNames(); + for (int i = 0; i < existingLanguages.size(); i++) // remove all languages we already have + { + for (int j = 0; j < missingLanguages.size(); j++) + { + if (missingLanguages[j] == existingLanguages[i]) + { + missingLanguages.erase(missingLanguages.begin() + j); + j--; + } + } + } + + HWND listCtrl = GetDlgItem(hDlg, IDC_LANGUAGE); + // see if any languages are missing + if (missingLanguages.size() == 0) + { + // none are missing, so disable the control + EnableWindow(listCtrl, FALSE); + IUpdateDlg(hDlg); + return true; + } + + // add the missing languages to the list + for (int i = 0; i < missingLanguages.size(); i++) + SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)missingLanguages[i].c_str()); + + // select the first language in the list + SendMessage(listCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0); + // and put it's value into the internal variable + wchar_t buff[256]; + GetDlgItemText(hDlg, IDC_LANGUAGE, buff, 256); + fLanguageName = buff; + + IUpdateDlg(hDlg); + return true; +} + +void plAddLocalizationDlg::IUpdateDlg(HWND hDlg) +{ + if (fLanguageName != L"") + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + else + EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); +} + +plAddLocalizationDlg::plAddLocalizationDlg(std::wstring parentPath) +{ + // throw away vars + std::wstring lang; + + SplitLocalizationPath(parentPath, fAgeName, fSetName, fElementName, lang); +} + +bool plAddLocalizationDlg::DoPick(HWND parent) +{ + INT_PTR ret = DialogBoxParam(gInstance, MAKEINTRESOURCE(IDD_ADDLOCALIZATION), + parent, IDlgProc, (LPARAM)this); + + return (ret != 0); +} diff --git a/Sources/Tools/plLocalizationEditor/plAddDlgs.h b/Sources/Tools/plLocalizationEditor/plAddDlgs.h new file mode 100644 index 00000000..b8c63053 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plAddDlgs.h @@ -0,0 +1,84 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +// basic classes for encapsulating the add dialogs +#ifndef __plAddDlgs_h__ +#define __plAddDlgs_h__ + +#include +#define WIN32_LEAN_AND_MEAN +#include +#include + +class plAddElementDlg +{ +protected: + static BOOL CALLBACK IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + bool IInitDlg(HWND hDlg); + void IUpdateDlg(HWND hDlg, bool setFocus = true); + + std::wstring fAgeName, fSetName, fElementName; + bool fAgeChanged; +public: + plAddElementDlg(std::wstring parentPath); + + bool DoPick(HWND parent); // returns true if [Ok] clicked, false otherwise. + std::wstring GetValue() {return fAgeName + L"." + fSetName + L"." + fElementName;} +}; + +class plAddLocalizationDlg +{ +protected: + static BOOL CALLBACK IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + bool IInitDlg(HWND hDlg); + void IUpdateDlg(HWND hDlg); + + std::wstring fAgeName, fSetName, fElementName, fLanguageName; +public: + plAddLocalizationDlg(std::wstring parentPath); + + bool DoPick(HWND parent); // returns true if [Ok] clicked, false otherwise. + std::wstring GetValue() {return fLanguageName;} +}; + +#endif diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp new file mode 100644 index 00000000..d770c9b8 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp @@ -0,0 +1,316 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +// Basic edit dialog stuff +#include "plEditDlg.h" +#include "res/resource.h" +#include "plLocTreeView.h" +#include "plAddDlgs.h" + +#include "hsUtils.h" +#include "pfLocalizationMgr/pfLocalizationDataMgr.h" + +#include + +HWND gEditDlg = NULL; +extern HINSTANCE gInstance; +extern HWND gTreeView; + +// global data for this dialog +std::wstring gCurrentPath = L""; + +// split a subtitle path up into its component parts +void SplitLocalizationPath(std::wstring path, std::wstring &ageName, std::wstring &setName, std::wstring &locName, std::wstring &locLanguage) +{ + ageName = setName = locName = locLanguage = L""; + + std::wstring::size_type lastPos = 0, curPos = 0; + // separate the age name out + curPos = path.find(L"."); + if (curPos == std::wstring::npos) + { + ageName = path; + return; + } + ageName = path.substr(0, curPos); + path = path.substr(curPos + 1, path.length()); + + // separate the set name out + curPos = path.find(L"."); + if (curPos == std::wstring::npos) + { + setName = path; + return; + } + setName = path.substr(0, curPos); + path = path.substr(curPos + 1, path.length()); + + // separate the element out + curPos = path.find(L"."); + if (curPos == std::wstring::npos) + { + locName = path; + return; + } + locName = path.substr(0, curPos); + path = path.substr(curPos + 1, path.length()); + + // what's left is the language + locLanguage = path; +} + +// saves the current localization text to the data manager +void SaveLocalizationText() +{ + if (gCurrentPath == L"") + return; // no path to save + + UInt32 textLen = (UInt32)SendMessage(GetDlgItem(gEditDlg, IDC_LOCALIZATIONTEXT), WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); + wchar_t *buffer = new wchar_t[textLen + 2]; + GetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, buffer, textLen + 1); + buffer[textLen + 1] = 0; + std::wstring plainTextData = buffer; + delete [] buffer; + std::wstring ageName, setName, elementName, elementLanguage; + SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage); + + std::wstring name = ageName + L"." + setName + L"." + elementName; + pfLocalizationDataMgr::Instance().SetElementPlainTextData(name, elementLanguage, plainTextData); +} + +// Reset all controls to their default values (except for static controls) +void ResetDlgDefaults() +{ + SetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, L""); +} + +// Enable/disable all edit controls (some won't enable/disable unless an audio file is loaded and the subtitle is timed) +void EnableDlg(BOOL enable) +{ + if (!enable) + ResetDlgDefaults(); // reset controls to defaults + + EnableWindow(GetDlgItem(gEditDlg, IDC_LOCALIZATIONTEXT), enable); +} + +// updates the edit dialog based on the path specified +void UpdateEditDlg(std::wstring locPath) +{ + if (locPath == gCurrentPath) + return; + + gCurrentPath = locPath; + + std::wstring itemText = L"Text ("; + itemText += locPath + L"):"; + SetDlgItemTextW(gEditDlg, IDC_LOCPATH, itemText.c_str()); + + std::wstring ageName = L"", setName = L"", elementName = L"", elementLanguage = L""; + SplitLocalizationPath(locPath, ageName, setName, elementName, elementLanguage); + + // now make sure they've drilled down deep enough to enable the dialog + if (elementLanguage == L"") // not deep enough + EnableDlg(FALSE); + else + { + EnableDlg(TRUE); + std::wstring key = ageName + L"." + setName + L"." + elementName; + std::wstring elementText = pfLocalizationDataMgr::Instance().GetElementPlainTextData(key, elementLanguage); + SetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, elementText.c_str()); + } + + // now to setup the add/delete buttons + if (elementLanguage != L"") // they have selected a language + { + SetDlgItemText(gEditDlg, IDC_ADD, L"Add Localization"); + EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE); + SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Localization"); + if (elementLanguage != L"English") // don't allow them to delete the default language + EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE); + else + EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE); + } + else // they have selected something else + { + SetDlgItemText(gEditDlg, IDC_ADD, L"Add Element"); + EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE); + SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Element"); + if (elementName != L"") // the have selected an individual element + { + std::vector elementNames = pfLocalizationDataMgr::Instance().GetElementList(ageName, setName); + if (elementNames.size() > 1) // they can't delete the only subtitle in a set + EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE); + else + EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE); + } + else + EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE); + } +} + +BOOL HandleCommandMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + int wmID, wmEvent; + wmID = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + switch (wmEvent) + { + case BN_CLICKED: + switch (wmID) + { + case IDC_ADD: + { + SaveLocalizationText(); // save any current changes to the database + + std::wstring buttonText; + wchar_t buff[256]; + GetDlgItemText(gEditDlg, IDC_ADD, buff, 256); + buttonText = buff; + + if (buttonText == L"Add Element") + { + plAddElementDlg dlg(gCurrentPath); + if (dlg.DoPick(gEditDlg)) + { + std::wstring path = dlg.GetValue(); // path is age.set.name + if (!pfLocalizationDataMgr::Instance().AddElement(path)) + MessageBox(gEditDlg, L"Couldn't add new element because one already exists with that name!", L"Error", MB_ICONERROR | MB_OK); + else + { + gCurrentPath = L""; + plLocTreeView::ClearTreeView(gTreeView); + plLocTreeView::FillTreeViewFromData(gTreeView, path); + UpdateEditDlg(path); + } + } + } + else if (buttonText == L"Add Localization") + { + plAddLocalizationDlg dlg(gCurrentPath); + if (dlg.DoPick(gEditDlg)) + { + std::wstring newLanguage = dlg.GetValue(); + std::wstring ageName, setName, elementName, elementLanguage; + SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage); + std::wstring key = ageName + L"." + setName + L"." + elementName; + if (!pfLocalizationDataMgr::Instance().AddLocalization(key, newLanguage)) + MessageBox(gEditDlg, L"Couldn't add additional localization!", L"Error", MB_ICONERROR | MB_OK); + else + { + std::wstring path = key + L"." + newLanguage; // select the new language + gCurrentPath = L""; + plLocTreeView::ClearTreeView(gTreeView); + plLocTreeView::FillTreeViewFromData(gTreeView, path); + UpdateEditDlg(path); + } + } + } + return FALSE; + } + case IDC_DELETE: + { + SaveLocalizationText(); // save any current changes to the database + + std::wstring messageText = L"Are you sure that you want to delete " + gCurrentPath + L"?"; + int res = MessageBoxW(gEditDlg, messageText.c_str(), L"Delete", MB_ICONQUESTION | MB_YESNO); + if (res == IDYES) + { + std::wstring buttonText; + wchar_t buff[256]; + GetDlgItemText(gEditDlg, IDC_DELETE, buff, 256); + buttonText = buff; + + if (buttonText == L"Delete Element") + { + if (!pfLocalizationDataMgr::Instance().DeleteElement(gCurrentPath)) + MessageBox(gEditDlg, L"Couldn't delete element!", L"Error", MB_ICONERROR | MB_OK); + else + { + std::wstring path = gCurrentPath; + gCurrentPath = L""; + plLocTreeView::ClearTreeView(gTreeView); + plLocTreeView::FillTreeViewFromData(gTreeView, path); + UpdateEditDlg(path); + } + } + else if (buttonText == L"Delete Localization") + { + std::wstring ageName, setName, elementName, elementLanguage; + SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage); + std::wstring key = ageName + L"." + setName + L"." + elementName; + if (!pfLocalizationDataMgr::Instance().DeleteLocalization(key, elementLanguage)) + MessageBox(gEditDlg, L"Couldn't delete localization!", L"Error", MB_ICONERROR | MB_OK); + else + { + std::wstring path = gCurrentPath; + gCurrentPath = L""; + plLocTreeView::ClearTreeView(gTreeView); + plLocTreeView::FillTreeViewFromData(gTreeView, path); + UpdateEditDlg(path); + } + } + } + } + return FALSE; + } + } + return (BOOL)DefWindowProc(hWnd, msg, wParam, lParam); +} + +// our dialog's window procedure +BOOL CALLBACK EditDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + gEditDlg = hWnd; + EnableDlg(FALSE); + } + break; + + case WM_COMMAND: + return HandleCommandMessage(hWnd, msg, wParam, lParam); + } + + return FALSE; +} diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.h b/Sources/Tools/plLocalizationEditor/plEditDlg.h new file mode 100644 index 00000000..31a20bd6 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.h @@ -0,0 +1,72 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +// Basic edit dialog stuff +#ifndef _pfEditDlg_h +#define _pfEditDlg_h + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +// Little trick to show a wait cursor while something is working +class plWaitCursor +{ + HCURSOR fOrig; +public: + plWaitCursor() + { + fOrig = SetCursor(LoadCursor(NULL, IDC_WAIT)); + } + + ~plWaitCursor() + { + SetCursor(fOrig); + } +}; + +void SplitLocalizationPath(std::wstring path, std::wstring &ageName, std::wstring &setName, std::wstring &locName, std::wstring &locLanguage); +void SaveLocalizationText(); +void UpdateEditDlg(std::wstring subtitlePath); +BOOL CALLBACK EditDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +#endif diff --git a/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp b/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp new file mode 100644 index 00000000..7f68a83d --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp @@ -0,0 +1,213 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#include "plLocTreeView.h" +#include "plEditDlg.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include "res\resource.h" + +#include +#include + +#include "hsUtils.h" +#include "pfLocalizationMgr/pfLocalizationDataMgr.h" + +extern HINSTANCE gInstance; + +std::wstring plLocTreeView::fPath = L""; + +HTREEITEM AddLeaf(HWND hTree, HTREEITEM hParent, std::wstring text, bool sort = true) +{ + TVITEM tvi = {0}; + tvi.mask = TVIF_TEXT | TVIF_PARAM; + tvi.pszText = (wchar_t*)text.c_str(); + tvi.cchTextMax = (int)text.length(); + tvi.lParam = NULL; + + TVINSERTSTRUCT tvins = {0}; + tvins.item = tvi; + tvins.hParent = hParent; + if (sort) + tvins.hInsertAfter = TVI_SORT; + else + tvins.hInsertAfter = TVI_LAST; + + return TreeView_InsertItem(hTree, &tvins); +} + +void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, std::wstring selectionPath) +{ + std::wstring targetAge, targetSet, targetElement, targetLang; + SplitLocalizationPath(selectionPath, targetAge, targetSet, targetElement, targetLang); + bool ageMatched = false; + bool setMatched = false; + bool elementMatched = false; + + std::vector ages = pfLocalizationDataMgr::Instance().GetAgeList(); + for (int curAge = 0; curAge < ages.size(); curAge++) + { + // add the age to the tree + HTREEITEM ageItem = AddLeaf(treeCtrl, NULL, ages[curAge]); + + if (ages[curAge] == targetAge) + { + TreeView_SelectItem(treeCtrl, ageItem); + TreeView_EnsureVisible(treeCtrl, ageItem); + ageMatched = true; + } + else + ageMatched = false; + + std::vector sets = pfLocalizationDataMgr::Instance().GetSetList(ages[curAge]); + for (int curSet = 0; curSet < sets.size(); curSet++) + { + std::vector elements = pfLocalizationDataMgr::Instance().GetElementList(ages[curAge], sets[curSet]); + + HTREEITEM setItem = AddLeaf(treeCtrl, ageItem, sets[curSet]); + + if ((sets[curSet] == targetSet) && ageMatched) + { + TreeView_SelectItem(treeCtrl, setItem); + TreeView_EnsureVisible(treeCtrl, setItem); + setMatched = true; + } + else + setMatched = false; + + for (int curElement = 0; curElement < elements.size(); curElement++) + { + HTREEITEM subItem = AddLeaf(treeCtrl, setItem, elements[curElement]); + + if (elements[curElement] == targetElement && setMatched) + { + TreeView_SelectItem(treeCtrl, subItem); + TreeView_EnsureVisible(treeCtrl, subItem); + elementMatched = true; + + if (targetLang.empty()) + targetLang = L"English"; + } + else + elementMatched = false; + + std::vector languages = pfLocalizationDataMgr::Instance().GetLanguages(ages[curAge], sets[curSet], elements[curElement]); + for (int curLang = 0; curLang < languages.size(); curLang++) + { + HTREEITEM langItem = AddLeaf(treeCtrl, subItem, languages[curLang]); + + if (languages[curLang] == targetLang && elementMatched) + { + TreeView_SelectItem(treeCtrl, langItem); + TreeView_EnsureVisible(treeCtrl, langItem); + } + } + } + } + } +} + +void plLocTreeView::ClearTreeView(HWND treeCtrl) +{ + TreeView_DeleteAllItems(treeCtrl); +} + +void plLocTreeView::SelectionChanged(HWND treeCtrl) +{ + HTREEITEM hItem = TreeView_GetSelection(treeCtrl); + std::vector path; + fPath = L""; + + while (hItem) + { + wchar_t s[200]; + TVITEM tvi = {0}; + tvi.hItem = hItem; + tvi.mask = TVIF_TEXT; + tvi.pszText = s; + tvi.cchTextMax = 200; + TreeView_GetItem(treeCtrl, &tvi); + path.push_back(tvi.pszText); + hItem = TreeView_GetParent(treeCtrl, hItem); + } + + while (!path.empty()) + { + fPath += path.back(); + + path.pop_back(); + if (!path.empty()) + fPath += L"."; + } +} + +void plLocTreeView::SelectionDblClicked(HWND treeCtrl) +{ + HTREEITEM hItem = TreeView_GetSelection(treeCtrl); + std::vector path; + fPath = L""; + + while (hItem) + { + wchar_t s[200]; + TVITEM tvi = {0}; + tvi.hItem = hItem; + tvi.mask = TVIF_TEXT; + tvi.pszText = s; + tvi.cchTextMax = 200; + TreeView_GetItem(treeCtrl, &tvi); + path.push_back(tvi.pszText); + hItem = TreeView_GetParent(treeCtrl, hItem); + } + + while (!path.empty()) + { + fPath += path.back(); + + path.pop_back(); + if (!path.empty()) + fPath += L"."; + } +} diff --git a/Sources/Tools/plLocalizationEditor/plLocTreeView.h b/Sources/Tools/plLocalizationEditor/plLocTreeView.h new file mode 100644 index 00000000..bf8317d8 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plLocTreeView.h @@ -0,0 +1,65 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#ifndef _plLocTreeView_h +#define _plLocTreeView_h + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +class plLocTreeView +{ +protected: + static std::wstring fPath; + +public: + static void FillTreeViewFromData(HWND treeCtrl, std::wstring selectionPath); + static void ClearTreeView(HWND treeCtrl); + + static void SelectionChanged(HWND treeCtrl); + static void SelectionDblClicked(HWND treeCtrl); + + static std::wstring GetPath() {return fPath;} +}; + +#endif //_plLocTreeView_h diff --git a/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp b/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp new file mode 100644 index 00000000..b15a0ea4 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp @@ -0,0 +1,394 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program 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. + +This program 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 this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ +#define CLASSNAME L"plLocalizationEditor" +#define WINDOWNAME L"plLocalizationEditor" +#define IDC_REGTREEVIEW 1000 + +#define FILE_MENU_POS 0 // 0-based index of the file sub menu + +#include "pnAllCreatables.h" +#include "plResMgr/plResMgrCreatable.h" + +// These are so that we don't have to link in stuff we don't have to +#include "plMessage/plResMgrHelperMsg.h" +#include "plMessage/plAgeLoadedMsg.h" +REGISTER_CREATABLE(plResMgrHelperMsg); +REGISTER_CREATABLE(plAgeLoadedMsg); +REGISTER_CREATABLE(plAgeLoaded2Msg); +REGISTER_CREATABLE(plAgeBeginLoadingMsg); +REGISTER_CREATABLE(plInitialAgeStateLoadedMsg); + +#include "pfLocalizationMgr/pfLocalizationMgr.h" +#include "pfLocalizationMgr/pfLocalizationDataMgr.h" +#include "plResMgr/plResManager.h" + +#include "plLocTreeView.h" +#include "plEditDlg.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include +#include "res/resource.h" + +HINSTANCE gInstance = NULL; +HWND gMainWindow = NULL; +HWND gTreeView = NULL; // the tree view for display of localization strings +extern HWND gEditDlg; // the main edit dialog for the localization strings +std::wstring gCurPath = L""; // current data path + +LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +BOOL WinInit(HINSTANCE hInst, int nCmdShow); + +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + HACCEL accelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1)); + + if (!WinInit(hInst, nCmdShow)) + return -1; + + plResManager *rMgr = new plResManager; + hsgResMgr::Init(rMgr); + + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(gMainWindow, accelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + pfLocalizationMgr::Shutdown(); + + hsgResMgr::Shutdown(); + + return 0; +} + +BOOL WinInit(HINSTANCE hInst, int nCmdShow) +{ + LoadLibrary(L"Riched20.dll"); // so we can use our rich edit control + gInstance = hInst; + + WNDCLASSEX wcEx; + wcEx.cbSize = sizeof(WNDCLASSEX); + wcEx.style = CS_HREDRAW | CS_VREDRAW; + wcEx.lpfnWndProc = MainWndProc; + wcEx.cbClsExtra = 0; + wcEx.cbWndExtra = 0; + wcEx.hInstance = hInst; + wcEx.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPICON)); + wcEx.hCursor = LoadCursor(NULL, IDC_ARROW); + wcEx.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wcEx.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU); + wcEx.lpszClassName = CLASSNAME; + wcEx.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + if (!RegisterClassEx(&wcEx)) + return FALSE; + + DWORD dwStyle = WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + DWORD dwExStyle = WS_EX_CONTROLPARENT; + + // Create a window + gMainWindow = CreateWindowEx(dwExStyle, CLASSNAME, WINDOWNAME, dwStyle, 10, 10, 800, 500, NULL, NULL, hInst, NULL); + if (gMainWindow == NULL) + return FALSE; + + return TRUE; +} + +void SetWindowTitle(HWND hWnd, std::wstring path) +{ + std::wstring title = L"plLocalizationEditor"; + if (path != L"") + title += L"-" + path; + + SetWindowText(hWnd, title.c_str()); +} + +BOOL CALLBACK AboutDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if(msg == WM_COMMAND) + EndDialog(hWnd, 0); + return 0; +} + +void RequestSaveOnExit() +{ + if (gCurPath == L"") // no data open + return; + + static bool alreadyRequested = false; // make sure we don't ask multiple times + if (alreadyRequested) + return; + alreadyRequested = true; + + SaveLocalizationText(); // make sure any changed text is saved to the manager + + int res = MessageBox(NULL, L"Do you wish to save your changes?", L"Save Changes", MB_ICONQUESTION | MB_YESNO); + if (res == IDYES) + { + // save it to a new directory + BROWSEINFO bInfo; + LPITEMIDLIST itemList; + LPMALLOC shMalloc; + wchar_t path[MAX_PATH]; + + memset(&bInfo, 0, sizeof(bInfo)); + bInfo.hwndOwner = NULL; + bInfo.pidlRoot = NULL; + bInfo.pszDisplayName = path; + bInfo.lpszTitle = L"Select a directory to save the localization data to:"; + bInfo.ulFlags = BIF_EDITBOX; + + itemList = SHBrowseForFolder(&bInfo); + if (itemList != NULL) + { + plWaitCursor waitCursor; + + SHGetPathFromIDList(itemList, path); + SHGetMalloc(&shMalloc); + shMalloc->Free(itemList); + shMalloc->Release(); + + gCurPath = path; + char *sPath = hsWStringToString(gCurPath.c_str()); + pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath); + delete [] sPath; + } + } +} + +LRESULT CALLBACK HandleCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + switch (LOWORD(wParam)) + { + case ID_FILE_EXIT: + RequestSaveOnExit(); + PostQuitMessage(0); + break; + case ID_FILE_OPENDATADIRECTORY: + { + BROWSEINFO bInfo; + LPITEMIDLIST itemList; + LPMALLOC shMalloc; + wchar_t path[MAX_PATH]; + + memset(&bInfo, 0, sizeof(bInfo)); + bInfo.hwndOwner = hWnd; + bInfo.pidlRoot = NULL; + bInfo.pszDisplayName = path; + bInfo.lpszTitle = L"Select a localization data directory:"; + bInfo.ulFlags = BIF_EDITBOX; + + itemList = SHBrowseForFolder(&bInfo); + if (itemList != NULL) + { + plWaitCursor waitCursor; + + SHGetPathFromIDList(itemList, path); + SHGetMalloc(&shMalloc); + shMalloc->Free(itemList); + shMalloc->Release(); + + pfLocalizationMgr::Shutdown(); + + char *sPath = hsWStringToString(path); + pfLocalizationMgr::Initialize(sPath); + delete [] sPath; + + plLocTreeView::ClearTreeView(gTreeView); + plLocTreeView::FillTreeViewFromData(gTreeView, L""); + + gCurPath = path; + SetWindowTitle(hWnd, path); + + HMENU menu = GetMenu(hWnd); + HMENU fileMenu = GetSubMenu(menu, FILE_MENU_POS); + EnableMenuItem(fileMenu, ID_FILE_SAVETOCUR, MF_ENABLED); + EnableMenuItem(fileMenu, ID_FILE_SAVETONEW, MF_ENABLED); + } + } + break; + case ID_FILE_SAVETOCUR: + { + SaveLocalizationText(); // make sure any changed text is saved to the manager + + // save it to our current directory + int res = MessageBox(hWnd, L"Are you sure you want to save to the current directory? Current data will be overwritten!", L"Save to Current Directory", MB_ICONQUESTION | MB_YESNOCANCEL); + if (res == IDYES) + { + plWaitCursor waitCursor; + char *sPath = hsWStringToString(gCurPath.c_str()); + pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath); + delete [] sPath; + } + else if (res == IDNO) + SendMessage(hWnd, WM_COMMAND, (WPARAM)ID_FILE_SAVETONEW, (LPARAM)0); + // and if it's cancel we don't do anything + } + break; + case ID_FILE_SAVETONEW: + { + SaveLocalizationText(); // make sure any changed text is saved to the manager + + // save it to a new directory + BROWSEINFO bInfo; + LPITEMIDLIST itemList; + LPMALLOC shMalloc; + wchar_t path[MAX_PATH]; + + memset(&bInfo, 0, sizeof(bInfo)); + bInfo.hwndOwner = hWnd; + bInfo.pidlRoot = NULL; + bInfo.pszDisplayName = path; + bInfo.lpszTitle = L"Select a directory to save the localization data to:"; + bInfo.ulFlags = BIF_EDITBOX; + + itemList = SHBrowseForFolder(&bInfo); + if (itemList != NULL) + { + plWaitCursor waitCursor; + + SHGetPathFromIDList(itemList, path); + SHGetMalloc(&shMalloc); + shMalloc->Free(itemList); + shMalloc->Release(); + + gCurPath = path; + SetWindowTitle(hWnd, path); + char *sPath = hsWStringToString(gCurPath.c_str()); + pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath); + delete [] sPath; + } + } + break; + + case ID_HELP_ABOUT: + DialogBox(gInstance, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDialogProc); + break; + } + return 0; +} + +void SizeControls(HWND parent) +{ + RECT clientRect, editRect; + + GetClientRect(parent, &clientRect); + GetClientRect(gEditDlg, &editRect); + + SetWindowPos(gTreeView, NULL, 0, 0, clientRect.right - editRect.right - 4, clientRect.bottom, 0); + + OffsetRect(&editRect, clientRect.right - editRect.right, (clientRect.bottom >> 1) - (editRect.bottom >> 1)); + SetWindowPos(gEditDlg, NULL, editRect.left, editRect.top, 0, 0, SWP_NOSIZE); +} + +void InitWindowControls(HWND hWnd) +{ + RECT clientRect; + + GetClientRect(hWnd, &clientRect); + + gTreeView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, L"Tree View", WS_VISIBLE | WS_CHILD | WS_BORDER | + TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS, + 0, 0, 0, 0, hWnd, (HMENU)IDC_REGTREEVIEW, gInstance, NULL); + + gEditDlg = CreateDialog(gInstance, MAKEINTRESOURCE(IDD_EDITDLG), hWnd, EditDlgProc); + + SizeControls(hWnd); +} + +LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CREATE: + InitCommonControls(); + InitWindowControls(hWnd); + break; + case WM_CLOSE: + RequestSaveOnExit(); + DestroyWindow(hWnd); + break; + case WM_DESTROY: + RequestSaveOnExit(); + plLocTreeView::ClearTreeView(gTreeView); + PostQuitMessage(0); + break; + case WM_SIZING: + case WM_SIZE: + SizeControls(hWnd); + break; + case WM_GETMINMAXINFO: + { + MINMAXINFO* pmmi = (MINMAXINFO*)lParam; + pmmi->ptMinTrackSize.x = 800; + pmmi->ptMinTrackSize.y = 500; + return 0; + } + case WM_NOTIFY: + if(wParam == IDC_REGTREEVIEW) + { + SaveLocalizationText(); // save any current changes to the database + + NMHDR *hdr = (NMHDR*)lParam; + if(hdr->code == TVN_SELCHANGED) + plLocTreeView::SelectionChanged(gTreeView); + else if(hdr->code == NM_DBLCLK) + plLocTreeView::SelectionDblClicked(gTreeView); + UpdateEditDlg(plLocTreeView::GetPath()); + } + break; + case WM_COMMAND: + return HandleCommand(hWnd, wParam, lParam); + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} diff --git a/Sources/Tools/plLocalizationEditor/res/icon1.ico b/Sources/Tools/plLocalizationEditor/res/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..13431c59e29ef15a8fcc81873bcdc5d138803c42 GIT binary patch literal 2998 zcmd6pO=ufO6o8*9vlh#;TKTVGk&A0VX>_vLOL8k4>0|=A^ZqKG~h#uViOxmB526;n~`P9CD2PK9qY~R`rwg4|d)%Z)oI$UOcX)~nCg z3ipC5L219Uy}xJNvz=bh>*lWYdi!_9`EqT))06GpoD_OHC!3-Qoz8Xv6F~Zu_0s8d zSsMhs9ldSnIvo?zmHpoK3H8)$rwi)6oa}$tMJHfH?OyJR(HPFGU10V&9-BLNN!XpJ zWEjm-?{$4K(}ndI~U=_0iLE%F8#A?z^s z3>hF@gkhe?c2BI=FOWD$FW?$eqFj> zX}NVvOJ5#~KFZ{m$1mma^XKx-k3Uf;LKKoB*;tLRMc5*2k+IPs6QZ!2JFl=S>=}j(yGGaOIFE7 z2!;rT2!;p-iwQ#nLj*$vLj;3GharL?f+2z-f+5n_;E3Re3RtB3I@|U1&4w`!I0T+tZdvu z>WqKTZF^03prUq4oNYC=QL^;7Dn)Hg?zQa`0P zDGVtLDSa@SeHHaAef8M{79fK?X-=IM|pyZWd**WUypFWE8Yl z0G5n}89^C_3>H2Jc{q~{mdy0SvY6XoP5~PX8U_u6hC#!iVX)T;h71M`gN7l4fiwv5 zFlZPw3>pSfBiLckFlZPw0Gj$4$utW!L5ds-UBRJkZWE*AWBE?*+_}SdRY&&r_T>Kk z`|{|~BYF7np*(r=M4mo9lqmi8arRCcP5B~M7f0vFGv)k|ciO zxUP4ZEskA0iQ^;*Fx;TsaC5Md<(_Ja#)=9lfAmW>UzHC`$4N!4#R_CoJ{hAyI5UYMJ?7g8tr~R4a2Z} zQ6P>>)wPPZ?0WV3M)S-cdS?avBnc|jRd@L#*IlmHC+ow-WV}OmU0tubrTVH{bEo`8 zIzpG&X9cvNR$um;{wf8=^$$F=9<-!Vb%RD@qwdz4brKkVxz#8SjXzGjO4Td(`^`qp zZMB