diff --git a/xLights/TabSetup.cpp b/xLights/TabSetup.cpp index 02206fb18..bcd6d3a54 100644 --- a/xLights/TabSetup.cpp +++ b/xLights/TabSetup.cpp @@ -70,6 +70,7 @@ const long xLightsFrame::ID_NETWORK_ACTIVEXLIGHTS = wxNewId(); const long xLightsFrame::ID_NETWORK_INACTIVE = wxNewId(); const long xLightsFrame::ID_NETWORK_DELETE = wxNewId(); const long xLightsFrame::ID_NETWORK_UNLINKFROMBASE = wxNewId(); +const long xLightsFrame::ID_NETWORK_UPLOADOUTPUT = wxNewId(); #pragma region Show Directory void xLightsFrame::OnMenuMRU(wxCommandEvent& event) { @@ -2198,6 +2199,8 @@ void xLightsFrame::OnListControllersItemRClick(wxListEvent& event) { bool allSelectedControllersFromBase = std::all_of(selectedControllers.begin(), selectedControllers.end(), [](const Controller* controller) { return controller->IsFromBase(); }); bool enableActivateMenuItems = selectedControllers.size() > 0 && !anySelectedControllersFromBase; bool enableUnlinkFromBaseMenuItem = selectedControllers.size() > 0 && allSelectedControllersFromBase; + bool anySelectedControllersSupportUpload = std::any_of(selectedControllers.begin(), selectedControllers.end(), [](const Controller* controller) { return controller->SupportsUpload(); }); + bool enableUploadMenuItem = selectedControllers.size() == 1 && anySelectedControllersSupportUpload; mnu.Append(ID_NETWORK_ADDETHERNET, ethernet)->Enable(ButtonAddControllerSerial->IsEnabled()); mnu.Append(ID_NETWORK_ADDNULL, "Insert NULL")->Enable(ButtonAddControllerSerial->IsEnabled()); @@ -2207,6 +2210,7 @@ void xLightsFrame::OnListControllersItemRClick(wxListEvent& event) { mnu.Append(ID_NETWORK_INACTIVE, "Inactivate")->Enable(ButtonAddControllerSerial->IsEnabled() && enableActivateMenuItems); mnu.Append(ID_NETWORK_DELETE, "Delete")->Enable(ButtonAddControllerSerial->IsEnabled()); mnu.Append(ID_NETWORK_UNLINKFROMBASE, "Unlink from Base Show Folder")->Enable(ButtonAddControllerSerial->IsEnabled() && enableUnlinkFromBaseMenuItem); + mnu.Append(ID_NETWORK_UPLOADOUTPUT, "Upload Output")->Enable(ButtonAddControllerSerial->IsEnabled() && enableUploadMenuItem); mnu.Connect(wxEVT_MENU, (wxObjectEventFunction)&xLightsFrame::OnListControllerPopup, nullptr, this); PopupMenu(&mnu); @@ -2274,6 +2278,9 @@ void xLightsFrame::OnListControllerPopup(wxCommandEvent& event) { _outputModelManager.AddASAPWork(OutputModelManager::WORK_UPDATE_NETWORK_LIST, "OnListControllerPopup:DELETE"); _outputModelManager.AddLayoutTabWork(OutputModelManager::WORK_CALCULATE_START_CHANNELS, "OnListControllerPopup:DELETE"); } + else if (id == ID_NETWORK_UPLOADOUTPUT) { + OnButtonUploadOutputClick(event); + } } #pragma endregion diff --git a/xLights/controllers/FPP.cpp b/xLights/controllers/FPP.cpp index b7bf572f7..f8315d2f3 100644 --- a/xLights/controllers/FPP.cpp +++ b/xLights/controllers/FPP.cpp @@ -778,8 +778,10 @@ bool FPP::uploadFile(const std::string &utfFilename, const std::string &file) { logger_base.debug("Renaming done."); } } + logger_base.debug(utfFilename + " upload complete to " + this->hostName + " (" + this->ipAddress + "). Bytes sent:" + std::to_string(data->totalWritten) + "."); } else { messages.push_back("ERROR Uploading file: " + utfFilename + " Response Code: " + std::to_string(response_code)); + faileduploads.push_back(filename); logger_base.warn("Did not get 200 response code: %d", response_code); } @@ -840,7 +842,8 @@ int progress_callback(void *clientp, void prepareCurlForMulti(V7ProgressStruct *ps) { static log4cpp::Category& logger_curl = log4cpp::Category::getInstance(std::string("log_curl")); - + static log4cpp::Category& logger_base = log4cpp::Category::getInstance(std::string("log_base")); + constexpr uint64_t BLOCK_SIZE = 16*1024*1024; CurlManager::CurlPrivateData *cpd = nullptr; CURL *curl = CurlManager::INSTANCE.createCurl(ps->fullUrl, &cpd, true); @@ -869,6 +872,7 @@ void prepareCurlForMulti(V7ProgressStruct *ps) { if (read != remaining) { logger_curl.info("ERROR Uploading file: " + ps->filename + " Could not read source file."); ps->instance->messages.push_back("ERROR Uploading file: " + ps->filename + " Could not read source file."); + ps->instance->faileduploads.push_back(ps->filename); } std::string contentSizeHeader = "Content-Length: " + std::to_string(remaining); headers = curl_slist_append(headers, contentSizeHeader.c_str()); @@ -898,6 +902,7 @@ void prepareCurlForMulti(V7ProgressStruct *ps) { ++ps->errorCount; } else if (response_code != 200) { ps->instance->messages.push_back("ERROR Uploading file: " + ps->filename + ". Response code: " + std::to_string(response_code)); + ps->instance->faileduploads.push_back(ps->filename); cancelled = true; } else { ps->offset += remaining; @@ -905,6 +910,7 @@ void prepareCurlForMulti(V7ProgressStruct *ps) { uint64_t pct = (ps->offset * 1000) / ps->length; cancelled |= ps->instance->updateProgress(pct, false); if (cancelled || ps->offset >= ps->length) { + logger_base.debug(ps->filename + " upload complete to " + ps->instance->hostName + " (" + ps->instance->ipAddress + "). Bytes sent:" + std::to_string(ps->length) + "."); delete ps; } else { prepareCurlForMulti(ps); @@ -3845,6 +3851,7 @@ void FPP::MapToFPPInstances(Discovery &discovery, std::list &instances, Ou FPP *fpp = new FPP(res->ip, res->proxy, res->pixelControllerType); fpp->ipAddress = res->ip;//not needed, in constructor fpp->hostName = res->hostname; + fpp->uuid = res->uuid; fpp->description = res->description; fpp->platform = res->platform; fpp->model = res->platformModel; @@ -3874,6 +3881,7 @@ void FPP::MapToFPPInstances(Discovery &discovery, std::list &instances, Ou } else { setIfEmpty(fpp->proxy, res->proxy); setIfEmpty(fpp->hostName, res->hostname); + setIfEmpty(fpp->uuid, res->uuid); setIfEmpty(fpp->description, res->description); setIfEmpty(fpp->platform, res->platform); setIfEmpty(fpp->model, res->platformModel); diff --git a/xLights/controllers/FPP.h b/xLights/controllers/FPP.h index 3828f06b2..6c794dafd 100644 --- a/xLights/controllers/FPP.h +++ b/xLights/controllers/FPP.h @@ -67,6 +67,7 @@ class FPP : public BaseController std::string controllerVendor; std::string controllerModel; std::string controllerVariant; + bool upload; wxWindow *parent = nullptr; void setProgress(FPPUploadProgressDialog*d, wxGauge *g) { progressDialog = d; progress = g; } @@ -74,6 +75,7 @@ class FPP : public BaseController std::list messages; + std::list faileduploads; int defaultConnectTimeout = 2000; std::map GetExpansionPorts(ControllerCaps* caps) const; @@ -232,10 +234,22 @@ static inline int case_insensitive_match(std::string s1, std::string s2) static inline bool sortByName(const FPP* i, const FPP* j) { - return i->hostName < j->hostName; + std::string lowerI = i->hostName; + std::string lowerJ = j->hostName; + + std::transform(lowerI.begin(), lowerI.end(), lowerI.begin(), + [](unsigned char c) { return std::tolower(c); }); + std::transform(lowerJ.begin(), lowerJ.end(), lowerJ.begin(), + [](unsigned char c) { return std::tolower(c); }); + + return lowerI < lowerJ; } static inline bool sortByIP(const FPP* i, const FPP* j) { return i->ipAddress < j->ipAddress; } + +static inline bool sortByUpload(const FPP* i, const FPP* j) { + return i->upload > j->upload; +} diff --git a/xLights/controllers/FPPConnectDialog.cpp b/xLights/controllers/FPPConnectDialog.cpp index 8b04de119..7fbced526 100644 --- a/xLights/controllers/FPPConnectDialog.cpp +++ b/xLights/controllers/FPPConnectDialog.cpp @@ -49,6 +49,8 @@ const wxWindowID FPPConnectDialog::ID_PANEL2 = wxNewId(); const wxWindowID FPPConnectDialog::ID_PANEL1 = wxNewId(); const wxWindowID FPPConnectDialog::ID_SPLITTERWINDOW1 = wxNewId(); const wxWindowID FPPConnectDialog::ID_BUTTON1 = wxNewId(); +const wxWindowID FPPConnectDialog::ID_BUTTON2 = wxNewId(); +const wxWindowID FPPConnectDialog::ID_CHECKBOX1 = wxNewId(); const wxWindowID FPPConnectDialog::ID_BUTTON_Upload = wxNewId(); //*) @@ -58,9 +60,14 @@ static const long ID_POPUP_MNU_SORT_NAME = wxNewId(); static const long ID_POPUP_MNU_SORT_IP = wxNewId(); static const long ID_POPUP_MNU_SELECT_ALL = wxNewId(); static const long ID_POPUP_MNU_DESELECT_ALL = wxNewId(); +static const long ID_POPUP_MNU_SORT_UPLOAD = wxNewId(); +static const long ID_POPUP_MNU_CAPE_SELECT_ALL = wxNewId(); +static const long ID_POPUP_MNU_CAPE_DESELECT_ALL = wxNewId(); +static const long ID_POPUP_MNU_MEDIA_DESELECT_ALL = wxNewId(); static const long ID_POPUP_MNU_SELECT_HIGH = wxNewId(); static const long ID_POPUP_MNU_DESELECT_HIGH = wxNewId(); static const long ID_POPUP_MNU_SELECT_BATCH = wxNewId(); +static const long ID_POPUP_MNU_SELECT_FAILED = wxNewId(); static const long ID_POPUP_MNU_SELECT_SUBNET = wxNewId(); wxString locationSortCol = "ip"; @@ -135,13 +142,18 @@ FPPConnectDialog::FPPConnectDialog(wxWindow* parent, OutputManager* outputManage Panel1->SetSizer(FlexGridSizer2); SplitterWindow1->SplitHorizontally(FPPInstanceList, Panel1); FlexGridSizer1->Add(SplitterWindow1, 1, wxALL|wxEXPAND, 5); - FlexGridSizer4 = new wxFlexGridSizer(0, 4, 0, 0); + FlexGridSizer4 = new wxFlexGridSizer(0, 6, 0, 0); FlexGridSizer4->AddGrowableCol(1); FlexGridSizer4->AddGrowableRow(0); AddFPPButton = new wxButton(this, ID_BUTTON1, _("Add FPP"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1")); FlexGridSizer4->Add(AddFPPButton, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); + ReDiscover = new wxButton(this, ID_BUTTON2, _("Re-Discover"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2")); + FlexGridSizer4->Add(ReDiscover, 1, wxALL, 5); StaticText3 = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY")); FlexGridSizer4->Add(StaticText3, 1, wxALL|wxEXPAND, 5); + KeepWinOpen = new wxCheckBox(this, ID_CHECKBOX1, _("Keep Open"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_CHECKBOX1")); + KeepWinOpen->SetValue(false); + FlexGridSizer4->Add(KeepWinOpen, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); Button_Upload = new wxButton(this, ID_BUTTON_Upload, _("Upload"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON_Upload")); FlexGridSizer4->Add(Button_Upload, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); cancelButton = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("wxID_CANCEL")); @@ -153,6 +165,7 @@ FPPConnectDialog::FPPConnectDialog(wxWindow* parent, OutputManager* outputManage Connect(ID_CHOICE_FILTER, wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&FPPConnectDialog::OnChoiceFilterSelect); Connect(ID_CHOICE_FOLDER, wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&FPPConnectDialog::OnChoiceFolderSelect); Connect(ID_BUTTON1, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&FPPConnectDialog::OnAddFPPButtonClick); + Connect(ID_BUTTON2, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&FPPConnectDialog::OnFPPReDiscoverClick); Connect(ID_BUTTON_Upload, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&FPPConnectDialog::OnButton_UploadClick); Connect(wxID_ANY, wxEVT_CLOSE_WINDOW, (wxObjectEventFunction)&FPPConnectDialog::OnClose); //*) @@ -403,6 +416,7 @@ void FPPConnectDialog::UploadPopupMenu(wxContextMenuEvent& event) { wxMenu mnu; mnu.Append(ID_POPUP_MNU_SELECT_ALL, "Select All"); mnu.Append(ID_POPUP_MNU_DESELECT_ALL, "Deselect All"); + mnu.Append(ID_POPUP_MNU_SORT_UPLOAD, "Sort"); mnu.Append(ID_POPUP_MNU_SELECT_SUBNET, "Select Subnet"); mnu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(FPPConnectDialog::OnUploadPopupClick), NULL, this); PopupMenu(&mnu); @@ -413,21 +427,26 @@ void FPPConnectDialog::OnUploadPopupClick(wxCommandEvent& event) { SelectIPsWithSubnet(); return; } - int row = 0; - for (const auto& inst : instances) { - std::string l = inst->hostName + " - " + inst->ipAddress; - if (inst->fppType == FPP_TYPE::FPP) { - if (inst->supportedForFPPConnect()) { - std::string rowStr = std::to_string(row); - if (event.GetId() == ID_POPUP_MNU_SELECT_ALL) { - SetCheckValue(CHECK_COL + rowStr, true); - } else if (event.GetId() == ID_POPUP_MNU_DESELECT_ALL) { - SetCheckValue(CHECK_COL + rowStr, false); - } - } - } - row++; + if (event.GetId() == ID_POPUP_MNU_SORT_UPLOAD) { + instances.sort(sortByUpload); + PopulateFPPInstanceList(); + return; } + int row = 0; + for (const auto& inst : instances) { + std::string l = inst->hostName + " - " + inst->ipAddress; + if (inst->fppType == FPP_TYPE::FPP) { + if (inst->supportedForFPPConnect()) { + std::string rowStr = std::to_string(row); + if (event.GetId() == ID_POPUP_MNU_SELECT_ALL) { + SetCheckValue(CHECK_COL + rowStr, true); + } else if (event.GetId() == ID_POPUP_MNU_DESELECT_ALL) { + SetCheckValue(CHECK_COL + rowStr, false); + } + } + } + row++; + } } void FPPConnectDialog::SelectIPsWithSubnet() { @@ -504,7 +523,6 @@ void FPPConnectDialog::PopulateFPPInstanceList(wxProgressDialog *prgs) { for (const auto& inst : instances) { std::string rowStr = std::to_string(row); wxCheckBox *doUploadCheckbox = new wxCheckBox(FPPInstanceList, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, CHECK_COL + rowStr); - doUploadCheckbox->SetValue(true); FPPInstanceSizer->Add(doUploadCheckbox, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 1); std::string l = inst->hostName + " - " + inst->ipAddress; @@ -580,7 +598,6 @@ void FPPConnectDialog::PopulateFPPInstanceList(wxProgressDialog *prgs) { prgs->Pulse("Probing information from " + l); } wxCheckBox *CheckBox1 = new wxCheckBox(FPPInstanceList, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, MEDIA_COL + rowStr); - CheckBox1->SetValue(inst->mode != "remote"); FPPInstanceSizer->Add(CheckBox1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 1); wxChoice* Choice1 = new wxChoice(FPPInstanceList, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, MODELS_COL + rowStr); wxFont font = Choice1->GetFont(); @@ -694,7 +711,11 @@ void FPPConnectDialog::OnPopup(wxCommandEvent &event) { int id = event.GetId(); if (ID_POPUP_MNU_SELECT_BATCH == id) { - SelectBatchRenderSeq(); + SequenceSelector("BatchRendererItemList"); + return; + } + if (ID_POPUP_MNU_SELECT_FAILED == id) { + SequenceSelector("FPPConnectFailedList"); return; } wxTreeListItem item = CheckListBox_Sequences->GetFirstItem(); @@ -715,22 +736,22 @@ void FPPConnectDialog::OnPopup(wxCommandEvent &event) UpdateSeqCount(); } -void FPPConnectDialog::SelectBatchRenderSeq() { +void FPPConnectDialog::SequenceSelector(const std::string regexKey) { wxConfigBase* config = wxConfigBase::Get(); if (nullptr == config) { return; } wxString itcsv; - config->Read("BatchRendererItemList", &itcsv, ""); + config->Read(regexKey, &itcsv, ""); if (!itcsv.IsEmpty()) { - auto const& savedBatchItems = wxSplit(itcsv, ','); + auto const& list = wxSplit(itcsv, ','); xLightsFrame* frame = static_cast(GetParent()); wxString const& showDirectory = frame->GetShowDirectory(); wxString const& fseqDirectory = frame->GetFseqDirectory(); - if (savedBatchItems.empty()) { + if (list.empty()) { return; } auto uitem = CheckListBox_Sequences->GetFirstItem(); @@ -741,8 +762,8 @@ void FPPConnectDialog::SelectBatchRenderSeq() { } uitem = CheckListBox_Sequences->GetNextItem(uitem); } - for (auto const& bat_seq : savedBatchItems) { - auto const& xsqName = showDirectory + wxFileName::GetPathSeparator() + bat_seq; + for (auto const& seq : list) { + auto const& xsqName = showDirectory + wxFileName::GetPathSeparator() + seq; wxFileName fseqFile(xsqName); fseqFile.SetExt("fseq"); @@ -1053,6 +1074,14 @@ void FPPConnectDialog::OnButton_UploadClick(wxCommandEvent& event) Button_Upload->Enable(false); AddFPPButton->Enable(false); + wxConfigBase* config = wxConfigBase::Get(); + if (config != nullptr) { + config->Write("FPPConnectFailedList", ""); + } + config->Flush(); + for (const auto& inst : instances) { + inst->faileduploads.clear(); + } std::vector doUpload(instances.size()); int row = 0; @@ -1093,9 +1122,12 @@ void FPPConnectDialog::OnButton_UploadClick(wxCommandEvent& event) if (!c) { SaveSettings(); + auto kwo = this->KeepWinOpen->Get3StateValue(); + if (kwo != wxCHK_CHECKED) { #ifndef _DEBUG EndDialog(wxID_CLOSE); #endif + } } Button_Upload->Enable(true); AddFPPButton->Enable(true); @@ -1375,6 +1407,7 @@ void FPPConnectDialog::doUpload(FPPUploadProgressDialog *prgs, std::vector std::string messages; + wxString failedUploadsList; for (const auto& inst : instances) { std::string rowStr = std::to_string(row); if (inst->fppType == FPP_TYPE::FPP) { @@ -1399,8 +1432,25 @@ void FPPConnectDialog::doUpload(FPPUploadProgressDialog *prgs, std::vector messages += "\n"; } } + if (!inst->faileduploads.empty()) { + for (auto& m : inst->faileduploads) { + if (failedUploadsList.empty()) { + failedUploadsList = m; + } else { + failedUploadsList += ","; + failedUploadsList += m; + } + } + } row++; } + if (!failedUploadsList.empty()) { + wxConfigBase* config = wxConfigBase::Get(); + if (config != nullptr) { + config->Write("FPPConnectFailedList", failedUploadsList); + } + config->Flush(); + }; xLightsFrame* xlframe = static_cast(GetParent()); if (messages != "") { xlframe->SetStatusText("FPP Connect Upload had errors or warnings", 0); @@ -1501,11 +1551,8 @@ void FPPConnectDialog::SaveSettings(bool onlyInsts) int row = 0; for (const auto& inst : instances) { std::string rowStr = std::to_string(row); - wxString keyPostfx = inst->ipAddress; - keyPostfx.Replace(":", "_"); - keyPostfx.Replace("/", "_"); - keyPostfx.Replace("\\", "_"); - keyPostfx.Replace(".", "_"); + wxString keyPostfx = (inst->uuid.empty() ? inst->ipAddress : inst->uuid); + keyPostfx = Fixitup(keyPostfx); config->Write("FPPConnectUpload_" + keyPostfx, GetCheckValue(CHECK_COL + rowStr)); config->Write("FPPConnectUploadMedia_" + keyPostfx, GetCheckValue(MEDIA_COL + rowStr)); config->Write("FPPConnectUploadFSEQType_" + keyPostfx, GetChoiceValueIndex(FSEQ_COL + rowStr)); @@ -1518,51 +1565,59 @@ void FPPConnectDialog::SaveSettings(bool onlyInsts) config->Flush(); } +wxString FPPConnectDialog::Fixitup(wxString val) { + val.Replace(":", "_"); + val.Replace("/", "_"); + val.Replace("\\", "_"); + val.Replace(".", "_"); + return val; +} + void FPPConnectDialog::ApplySavedHostSettings() { - /* - static const std::string CHECK_COL = "ID_UPLOAD_"; - static const std::string FSEQ_COL = "ID_FSEQTYPE_"; - static const std::string MEDIA_COL = "ID_MEDIA_"; - static const std::string MODELS_COL = "ID_MODELS_"; - static const std::string UDP_COL = "ID_UDPOUT_"; - static const std::string PLAYLIST_COL = "ID_PLAYLIST_"; - static const std::string UPLOAD_CONTROLLER_COL = "ID_CONTROLLER_"; - */ - - wxConfigBase* config = wxConfigBase::Get(); if (config != nullptr) { int row = 0; for (const auto& inst : instances) { std::string rowStr = std::to_string(row); - wxString keyPostfx = inst->ipAddress; - keyPostfx.Replace(":", "_"); - keyPostfx.Replace("/", "_"); - keyPostfx.Replace("\\", "_"); - keyPostfx.Replace(".", "_"); bool bval; int lval; - if (config->Read("FPPConnectUpload_" + keyPostfx, &bval)) { + if (config->Read("FPPConnectUpload_" + Fixitup(inst->uuid), &bval)) { + SetCheckValue(CHECK_COL + rowStr, bval); + inst->upload = bval; + } else if (config->Read("FPPConnectUpload_" + Fixitup(inst->ipAddress), &bval)) { SetCheckValue(CHECK_COL + rowStr, bval); + inst->upload = bval; } - if (config->Read("FPPConnectUploadFSEQType_" + keyPostfx, &lval)) { + if (config->Read("FPPConnectUploadFSEQType_" + Fixitup(inst->uuid), &lval)) { SetChoiceValueIndex(FSEQ_COL + rowStr, lval); + } else if (config->Read("FPPConnectUploadFSEQType_" + Fixitup(inst->ipAddress), &lval)) { + SetCheckValue(FSEQ_COL + rowStr, lval); } - if (config->Read("FPPConnectUploadMedia_" + keyPostfx, &bval)) { + if (config->Read("FPPConnectUploadMedia_" + Fixitup(inst->uuid), &bval)) { + SetCheckValue(MEDIA_COL + rowStr, bval); + } else if (config->Read("FPPConnectUploadMedia_" + Fixitup(inst->ipAddress), &bval)) { SetCheckValue(MEDIA_COL + rowStr, bval); } - if (config->Read("FPPConnectUploadModels_" + keyPostfx, &lval)) { + if (config->Read("FPPConnectUploadModels_" + Fixitup(inst->uuid), &lval)) { SetChoiceValueIndex(MODELS_COL + rowStr, lval); + } else if (config->Read("FPPConnectUploadModels_" + Fixitup(inst->ipAddress), &lval)) { + SetCheckValue(MODELS_COL + rowStr, lval); } - if (config->Read("FPPConnectUploadUDPOut_" + keyPostfx, &lval)) { + if (config->Read("FPPConnectUploadUDPOut_" + Fixitup(inst->uuid), &lval)) { SetChoiceValueIndex(UDP_COL + rowStr, lval); + } else if (config->Read("FPPConnectUploadUDPOut_" + Fixitup(inst->ipAddress), &lval)) { + SetCheckValue(UDP_COL + rowStr, lval); } - if (config->Read("FPPConnectUploadPixelOut_" + keyPostfx, &bval)) { + if (config->Read("FPPConnectUploadPixelOut_" + Fixitup(inst->uuid), &bval)) { + SetCheckValue(UPLOAD_CONTROLLER_COL + rowStr, bval); + } else if (config->Read("FPPConnectUploadPixelOut_" + Fixitup(inst->ipAddress), &bval)) { SetCheckValue(UPLOAD_CONTROLLER_COL + rowStr, bval); } - if (config->Read("FPPConnectUploadProxy_" + keyPostfx, &bval)) { + if (config->Read("FPPConnectUploadProxy_" + Fixitup(inst->uuid), &bval)) { + SetCheckValue(PROXY_COL + rowStr, bval); + } else if (config->Read("FPPConnectUploadProxy_" + Fixitup(inst->ipAddress), &bval)) { SetCheckValue(PROXY_COL + rowStr, bval); } row++; @@ -1570,7 +1625,6 @@ void FPPConnectDialog::ApplySavedHostSettings() } } - void FPPConnectDialog::OnClose(wxCloseEvent& event) { EndDialog(0); @@ -1584,10 +1638,58 @@ void FPPConnectDialog::SequenceListPopup(wxTreeListEvent& event) mnu.Append(ID_POPUP_MNU_SELECT_HIGH, "Select Highlighted"); mnu.Append(ID_POPUP_MNU_DESELECT_HIGH, "Deselect Highlighted"); mnu.Append(ID_POPUP_MNU_SELECT_BATCH, "Select Batch Render"); + mnu.Append(ID_POPUP_MNU_SELECT_FAILED, "Select Failed Uploads"); mnu.Connect(wxEVT_MENU, (wxObjectEventFunction)&FPPConnectDialog::OnPopup, nullptr, this); PopupMenu(&mnu); } +void FPPConnectDialog::OnFPPReDiscoverClick(wxCommandEvent& event) { + int curSize = instances.size(); + std::list add; + + wxProgressDialog prgs("Discovering FPP Instances", + "Discovering FPP Instances", 100, this); + prgs.Pulse("Discovering FPP Instances"); + + std::string fppConnectIP = ""; + prgs.Show(); + instances = FPP::GetInstances(this, _outputManager); + + if (curSize < instances.size()) { + int cur = 0; + for (const auto& fpp : instances) { + if (cur >= curSize) { + prgs.Pulse("Gathering configuration for " + fpp->hostName + " - " + fpp->ipAddress); + fpp->AuthenticateAndUpdateVersions(); + fpp->probePixelControllerType(); + } + cur++; + } + + instances.sort(sortByIP); + // it worked, we found some new instances, record this + wxConfigBase* config = wxConfigBase::Get(); + wxString ip; + config->Read("FPPConnectForcedIPs", &ip); + if (locationSortCol == "name") { + instances.sort(sortByName); + } else { + instances.sort([this](const FPP* a, const FPP* b) { + std::vector aComponents = SplitIP(a->ipAddress); + std::vector bComponents = SplitIP(b->ipAddress); + for (size_t i = 0; i < aComponents.size() && i < bComponents.size(); ++i) { + if (aComponents[i] != bComponents[i]) + return aComponents[i] < bComponents[i]; + } + return aComponents.size() < bComponents.size(); + }); + } + PopulateFPPInstanceList(); + } + + prgs.Hide(); +} + void FPPConnectDialog::OnAddFPPButtonClick(wxCommandEvent& event) { wxTextEntryDialog dlg(this, "Find FPP Instance", "Enter IP address or hostname for FPP Instance"); diff --git a/xLights/controllers/FPPConnectDialog.h b/xLights/controllers/FPPConnectDialog.h index b087c0757..6920b2ab1 100644 --- a/xLights/controllers/FPPConnectDialog.h +++ b/xLights/controllers/FPPConnectDialog.h @@ -6,6 +6,7 @@ //(*Headers(FPPConnectDialog) #include +#include #include #include #include @@ -27,6 +28,7 @@ class FPPConnectDialog: public wxDialog { void SaveSettings(bool onlyInsts = false); void ApplySavedHostSettings(); + wxString Fixitup(wxString val); public: @@ -36,6 +38,8 @@ class FPPConnectDialog: public wxDialog //(*Declarations(FPPConnectDialog) wxButton* AddFPPButton; wxButton* Button_Upload; + wxButton* ReDiscover; + wxCheckBox* KeepWinOpen; wxChoice* ChoiceFilter; wxChoice* ChoiceFolder; wxFlexGridSizer* FPPInstanceSizer; @@ -63,6 +67,8 @@ class FPPConnectDialog: public wxDialog static const wxWindowID ID_PANEL1; static const wxWindowID ID_SPLITTERWINDOW1; static const wxWindowID ID_BUTTON1; + static const wxWindowID ID_BUTTON2; + static const wxWindowID ID_CHECKBOX1; static const wxWindowID ID_BUTTON_Upload; //*) @@ -79,6 +85,7 @@ class FPPConnectDialog: public wxDialog void OnClose(wxCloseEvent& event); void SequenceListPopup(wxTreeListEvent& event); void OnAddFPPButtonClick(wxCommandEvent& event); + void OnFPPReDiscoverClick(wxCommandEvent& event); void OnChoiceFolderSelect(wxCommandEvent& event); void OnChoiceFilterSelect(wxCommandEvent& event); void HostSortMenu(wxContextMenuEvent& event); @@ -119,7 +126,7 @@ class FPPConnectDialog: public wxDialog void doUpload(FPPUploadProgressDialog *prgs, std::vector doUpload); std::vector SplitIP(const wxString& ip) const; - void SelectBatchRenderSeq(); + void SequenceSelector(const std::string regexKey); void SelectIPsWithSubnet(); DECLARE_EVENT_TABLE() diff --git a/xLights/wxsmith/FPPConnectDialog.wxs b/xLights/wxsmith/FPPConnectDialog.wxs index 7f83e777a..2550a765c 100644 --- a/xLights/wxsmith/FPPConnectDialog.wxs +++ b/xLights/wxsmith/FPPConnectDialog.wxs @@ -96,7 +96,7 @@ - 4 + 6 1 0 @@ -108,6 +108,15 @@ 5 + + + + + + wxALL + 5 + + @@ -116,6 +125,14 @@ 5 + + + + + wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL + 5 + + diff --git a/xLights/xLightsMain.h b/xLights/xLightsMain.h index 2851c2c6c..874517559 100755 --- a/xLights/xLightsMain.h +++ b/xLights/xLightsMain.h @@ -1878,6 +1878,7 @@ private : static const long ID_NETWORK_UNLINKFROMBASE; static const long ID_NETWORK_INACTIVE; static const long ID_NETWORK_DELETE; + static const long ID_NETWORK_UPLOADOUTPUT; #define isRandom(ctl) isRandom_(ctl, #ctl) //(buttonState[std::string(ctl->GetName())] == Random)