void CCompareResultsDlg::OnCompareSynchronize()
{
  if (m_bOriginalDBReadOnly)
    return;

  CGeneralMsgBox gmb;
  CString cs_temp, cs_title;
  // Initialize set
  GTUSet setGTU;

  // First check database
  if (!m_pcore0->GetUniqueGTUValidated() && !m_pcore0->InitialiseGTU(setGTU)) {
    // Database is not unique to start with - tell user to validate it first
    cs_title.LoadString(IDS_SYNCHFAILED);
    cs_temp.Format(IDS_DBHASDUPLICATES, m_pcore0->GetCurFile().c_str());
    gmb.MessageBox(cs_temp, cs_title, MB_ICONEXCLAMATION);
    return;
  }
  setGTU.clear();  // Don't need it anymore - so clear it now

  DWORD_PTR dwItemData = m_LCResults.GetItemData(m_LCResults.GetRow());
  st_CompareData *pst_data = GetCompareData(dwItemData);
  ASSERT(pst_data != NULL);

  ProcessFunction(SYNCH, pst_data);
}
Exemple #2
0
void CompareDlg::OnSyncItemsWithCurrentDB(wxCommandEvent& evt)
{
  if (m_currentCore->IsReadOnly()) {
    wxMessageBox(_("Current safe was opened read-only"), _("Synchronize"), wxOK|wxICON_INFORMATION, this);
    return;
  }

  GTUSet setGTU;
  if (!m_currentCore->GetUniqueGTUValidated() && !m_currentCore->InitialiseGTU(setGTU)) {
    // Database is not unique to start with - tell user to validate it first
    wxMessageBox(wxString::Format(_("The database:\n\n%ls\n\nhas duplicate entries with the same group/title/user combination. Please fix by validating database."), m_currentCore->GetCurFile().c_str()),
                  _("Synchronization failed"), wxOK|wxICON_EXCLAMATION, this);
    return;
  }
  setGTU.clear();  // Don't need it anymore - so clear it now

  //we only synchronize these fields
  const CItemData::FieldType syncFields[] = {
    CItemData::PASSWORD, CItemData::URL, CItemData::EMAIL, CItemData::AUTOTYPE, CItemData::NOTES,
    CItemData::PWHIST, CItemData::POLICY, CItemData::CTIME, CItemData::PMTIME, CItemData::ATIME,
    CItemData::XTIME, CItemData::RMTIME, CItemData::XTIME_INT,
    CItemData::RUNCMD, CItemData::DCA, CItemData::PROTECTED, CItemData::SYMBOLS, CItemData::SHIFTDCA,
  };

  FieldSet userSelection(syncFields, syncFields + WXSIZEOF(syncFields));

  //let the user choose which fields to synchronize
  FieldSelectionDlg dlg(this,
                        NULL, 0, //no fields are left unselected by default
                        NULL, 0, //But no fields are mandatory
                        userSelection,
                        _T("Synchronize"));
  if (dlg.ShowModal() == wxID_OK) {
    wxCHECK_RET(userSelection.size() > 0, wxT("User did not select any fields to sync?"));
    ContextMenuData* menuContext = reinterpret_cast<ContextMenuData*>(evt.GetClientData());
    wxCHECK_RET(menuContext, wxT("No menu context available"));
    //start with the selected items
    wxArrayInt syncIndexes(menuContext->selectedItems);
    if (evt.GetId() == ID_SYNC_ALL_ITEMS_WITH_CURRENT_DB) {
      //add all items to the sync Index list
      syncIndexes.Empty();
      const size_t numIndexes = menuContext->cdata->data.size();
      syncIndexes.Alloc(numIndexes);
      for(size_t i = 0; i < numIndexes; ++i)
        syncIndexes.Add(i);
    }
    else {
      wxCHECK_RET(evt.GetId() == ID_SYNC_SELECTED_ITEMS_WITH_CURRENT_DB, wxT("Sync menu id is neither for all nor for selected items"));
    }

    //use a wxScopedPtr to clean up the heap object if we trip on any of the wxCHECK_RETs below
    MultiCommandsPtr pMultiCmds(MultiCommands::Create(m_currentCore));
    for (size_t idx = 0; idx < syncIndexes.Count(); ++idx) {
      ItemListIter fromPos = m_otherCore->Find(menuContext->cdata->data[syncIndexes[idx]].uuid1);
      wxCHECK_RET(fromPos != m_otherCore->GetEntryEndIter(), wxT("Could not find sync item in other db"));
      const CItemData *pfromEntry = &fromPos->second;

      ItemListIter toPos = m_currentCore->Find(menuContext->cdata->data[syncIndexes[idx]].uuid0);
      wxCHECK_RET(toPos != m_currentCore->GetEntryEndIter(), wxT("Could not find sync item in current db"));
      CItemData *ptoEntry = &toPos->second;
      CItemData updtEntry(*ptoEntry);

      //create a copy of the "to" object, with only the to-be-sync'ed fields changed
      bool bUpdated(false);
      for (FieldSet::const_iterator itr = userSelection.begin(); itr != userSelection.end(); ++itr) {
        const StringX sxValue = pfromEntry->GetFieldValue(*itr);
        if (sxValue != updtEntry.GetFieldValue(*itr)) {
          bUpdated = true;
          updtEntry.SetFieldValue(*itr, sxValue);
        }
      }
      //Don't change anything yet.  Just keep track of the differences.
      if (bUpdated) {
        updtEntry.SetStatus(CItemData::ES_MODIFIED);
        Command *pcmd = EditEntryCommand::Create(m_currentCore, *ptoEntry, updtEntry);
        pMultiCmds->Add(pcmd);
      }
    }
    //Update all or nothing.  And there's no way of knowing if any of the sub-commands
    //inside MultiCommands failed
    if (pMultiCmds->GetSize() > 0) {
      m_currentCore->Execute(pMultiCmds.release());
      ComparisonGridTable* ptable = wxDynamicCast(menuContext->cdata->grid->GetTable(), ComparisonGridTable);
      wxCHECK_RET(ptable, wxT("Could not find ComparisonGridTable derived object in comparison grid"));
      const ComparisonGridTable& table = *ptable;
      wxCHECK_RET(menuContext->cdata == m_conflicts, wxT("Sync happened in unexpected grid"));
      for( size_t idx = 0; idx < syncIndexes.Count(); ++idx) {
        //refresh every even-numbered row
        table.RefreshRow(syncIndexes[idx]*2);
      }
    }
  }
}