text:
> Dalziel and Pascoe
> Why Dalziel And Pascoe Are The Perfect Partnership
Dalziel and Pascoe
Why Dalziel And Pascoe Are The Perfect Partnership
One's a rough, old school copper, the other's a degree-educated smart alec, and together they're… magic. Here's why.
1. THEY'RE NOT QUITE CHALK AND CHEESE
You'd think Andy Dalziel and Peter Pascoe are the very definition of chalk and cheese. But in an important way, the phrase doesn't do them justice. Because, while they're really, really different, they also happen to go together really, really well. So they're not so much chalk and cheese as, well, peanut butter and jam. Totally different in taste, texture and appearance, and yet add them together and you've got the best possible partnership which has no right to exist whatsoever. (Although if you asked Pascoe, he'd probably say they're more like dark chocolate and sea salt. A classier analogy for our cultivated copper.)
Watch This Bank Holiday
2. THEY COMPLETE EACH OTHER
Not to go all soppy and sentimental (Dalziel would roll his eyes if we did), but these two blokes do complete each other, in terms of their interlocking skill sets. Dalziel may be a cantankerous curmudgeon who sticks his foot in it with everyone, but he has a dogged determination and no-nonsense attitude which is essential to good sleuthing. Pascoe, meanwhile, can be a bit too timid and reserved for his own good, yet he also helps smooth over his partner's rough approach, while offering a cooler, more analytical approach to cases. Slot their skills together and you have the perfect crime-solving package.
3. PASCOE KNOWS WHEN TO KEEP SHTUM
For all their professionalism, these two wouldn't have lasted a day together if Pascoe didn't have the patience of a saint. Fortunately, he knows exactly when to keep his mouth shut and let Dalziel's barbs, jibes, and utterly inappropriate insults just bounce off him. A lesser man would probably deck Dalziel before the end of their shift, but Pascoe somehow manages to tolerate the verbal barrage. Some part of Dalziel knows this and respects it. (Probably.)
4. DALZIEL KNOWS WHEN TO BACK DOWN
Of course, even Pascoe's patience wouldn't be enough to maintain their partnership if Dalziel himself didn't know when to put a sock in it occasionally. He does, though. Just when you think he might take it too far with the grumbling and mickey taking, he does the decent thing and acts like a normal, everyday human being to his long-suffering colleague. What a gent.
Warren Clarke as Det. Supt. Andy Dalziel and Colin Buchanan as DI Peter Pascoe.
5. THEY CAN ALWAYS BLAME THE OTHER ONE
Pascoe once accused Dalziel of treating him like a "part time slave, part time scapegoat". Which is absolutely 100% true. And yet, Pascoe also scapegoats Dalziel when he has to. That's the great thing about working alongside someone who is your total opposite, and who is constantly arguing with you about everything. You can make yourself feel better by blaming them whenever anything goes wrong. That's the key to a good working partnership, that is.
6. THEY (SECRETLY) LIKE EACH OTHER
Don't ever say it to their faces, but Dalziel and Pascoe do actually genuinely like each other. Sometimes. When they can be bothered. Think of the touching speech Dalziel gave at Pascoe's wedding. Or how Pascoe got all concerned when Dalziel had serious health problems. They can be so sweet when they want to be.
7. THEY'VE GOT THE BANTER
"Look at the face on you - like a bull terrier with haemorrhoids." That's Dalziel casual greeting to Pascoe when he calls him over to a crime scene. And when Pascoe objects it's supposed to be his night off, Dalziel is unrepentant. "Thought it was just a quiet night in. Horlicks and Pride and Prejudice." You see, it's that kind of close communication that really make a partnership work...
Hear More From Us
Enter your email below for more about Drama's shows.
Warren Clarke and Colin Buchanan star in the top-rated crime drama series.
TV's Top 5 Most Terrifying Killers
From the slaughter spree at Sun Hill, to the ritual killing which baffled Taggart.
5 Cracking Crime Adaptations
These telly detectives all started out in the pages of a book…
Dalziel and Pascoe's 6 Maddest Cases
Some of the situations they've dealt with have been downright bizarre.
Dalziel and Pascoe's Funniest Quips And Comebacks
Being able to take the mickey is a vital job skill…


text:
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "fusion/fusionui/AssetManager.h"

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <iostream>

#include <qstring.h>
#include <qstringlist.h>
#include <qcombobox.h>
#include <qapplication.h>
#include <qpopupmenu.h>
#include <qmessagebox.h>
#include <qpixmap.h>
#include <qheader.h>
#include <qprogressdialog.h>
#include <qlineedit.h>
#include <qtabwidget.h>
#include <qimage.h>
#include <qpushbutton.h>
#include <qinputdialog.h>
#include <qlayout.h>
#include <qpainter.h>
#include <qcheckbox.h>
#include <qsplitter.h>
#include <qwidgetstack.h>
#include <qcursor.h>
#include <qthread.h>

#include "fusion/autoingest/plugins/RasterProductAsset.h"
#include "fusion/autoingest/plugins/MercatorRasterProductAsset.h"
#include "fusion/autoingest/plugins/RasterProjectAsset.h"
#include "fusion/autoingest/plugins/MercatorRasterProjectAsset.h"
#include "fusion/autoingest/plugins/VectorProductAsset.h"
#include "fusion/autoingest/plugins/VectorProjectAsset.h"
#include "fusion/autoingest/plugins/VectorLayerXAsset.h"
#include "fusion/autoingest/plugins/MapLayerAsset.h"
#include "fusion/autoingest/plugins/MapProjectAsset.h"
#include "fusion/autoingest/plugins/MapDatabaseAsset.h"
#include "fusion/autoingest/plugins/MercatorMapDatabaseAsset.h"
#include "fusion/autoingest/plugins/SourceAsset.h"
#include "fusion/autoingest/plugins/DatabaseAsset.h"
#include "fusion/autoingest/plugins/KMLProjectAsset.h"
#include "fusion/autoingest/plugins/GEDBAsset.h"
#include "fusion/autoingest/.idl/ServerCombination.h"
#include "fusion/autoingest/.idl/gstProvider.h"
#include "fusion/fusionui/AssetBase.h"
#include "fusion/fusionui/AssetDisplayHelper.h"
#include "fusion/fusionui/Preferences.h"
#include "fusion/fusionui/AssetVersionProperties.h"
#include "fusion/fusionui/AssetIconView.h"
#include "fusion/fusionui/AssetTableView.h"
#include "fusion/fusionui/AssetProperties.h"
#include "fusion/fusionui/SourceFileDialog.h"
#include "fusion/fusionui/ImageryAsset.h"
#include "fusion/fusionui/MercatorImageryAsset.h"
#include "fusion/fusionui/TerrainAsset.h"
#include "fusion/fusionui/VectorAsset.h"
#include "fusion/fusionui/SystemListener.h"
#include "fusion/fusionui/MainWindow.h"
#include "fusion/fusionui/Database.h"
#include "fusion/fusionui/NewAsset.h"
#include "fusion/fusionui/MapLayer.h"
#include "fusion/fusionui/MapProject.h"
#include "fusion/fusionui/MapDatabase.h"
#include "fusion/fusionui/MercatorMapDatabase.h"
#include "fusion/fusionui/ImageryProject.h"
#include "fusion/fusionui/MercatorImageryProject.h"
#include "fusion/fusionui/KMLProject.h"
#include "fusion/fusionui/VectorLayer.h"
#include "fusion/fusionui/VectorProject.h"
#include "fusion/fusionui/TerrainProject.h"
#include "fusion/fusionui/PushDatabaseDialog.h"
#include "fusion/fusionui/PublishDatabaseDialog.h"
#include "fusion/fusionui/geGuiProgress.h"
#include "fusion/fusionui/geGuiAuth.h"
#include "fusion/gepublish/PublisherClient.h"
#include "fusion/gst/gstAssetManager.h"
#include "fusion/gst/gstRegistry.h"
#include "fusion/fusionversion.h"
#include "common/notify.h"

namespace {

const char* folder_closed_xpm[]={
  "16 16 9 1",
  "g c #808080",
  "b c #c0c000",
  "e c #c0c0c0",
  "# c #000000",
  "c c #ffff00",
  ". c None",
  "a c #585858",
  "f c #a0a0a4",
  "d c #ffffff",
  "..###...........",
  ".#abc##.........",
  ".#daabc#####....",
  ".#ddeaabbccc#...",
  ".#dedeeabbbba...",
  ".#edeeeeaaaab#..",
  ".#deeeeeeefe#ba.",
  ".#eeeeeeefef#ba.",
  ".#eeeeeefeff#ba.",
  ".#eeeeefefff#ba.",
  ".##geefeffff#ba.",
  "...##gefffff#ba.",
  ".....##fffff#ba.",
  ".......##fff#b##",
  ".........##f#b##",
  "...........####." };

const char* folder_open_xpm[]={
  "16 16 11 1",
  "# c #000000",
  "g c #c0c0c0",
  "e c #303030",
  "a c #ffa858",
  "b c #808080",
  "d c #a0a0a4",
  "f c #585858",
  "c c #ffdca8",
  "h c #dcdcdc",
  "i c #ffffff",
  ". c None",
  "....###.........",
  "....#ab##.......",
  "....#acab####...",
  "###.#acccccca#..",
  "#ddefaaaccccca#.",
  "#bdddbaaaacccab#",
  ".eddddbbaaaacab#",
  ".#bddggdbbaaaab#",
  "..edgdggggbbaab#",
  "..#bgggghghdaab#",
  "...ebhggghicfab#",
  "....#edhhiiidab#",
  "......#egiiicfb#",
  "........#egiibb#",
  "..........#egib#",
  "............#ee#" };

QPixmap* folderClosed = 0;
QPixmap* folderOpen = 0;

class AssetFolder : public QListViewItem {
 public:
  AssetFolder(QListViewItem* parent, const gstAssetFolder& f);
  AssetFolder(QListView* parent, const gstAssetFolder& f);

  const gstAssetFolder& getFolder() const { return folder; }

  void setOpen(bool m);
  void populate();

  AssetFolder* newFolder(const QString& text, QString &error);

  int rtti() const { return type_; }

 private:
  gstAssetFolder folder;
  int type_;
};

// -----------------------------------------------------------------------------

AssetFolder::AssetFolder(QListView* parent, const gstAssetFolder& f)
    : QListViewItem(parent, f.name()),
      folder(f),
      type_(ASSET_MANAGER) {
  setPixmap(0, *folderClosed);
  setExpandable(true);
}

AssetFolder::AssetFolder(QListViewItem* parent, const gstAssetFolder& f)
    : QListViewItem(parent, f.name()),
      folder(f),
      type_(ASSET_FOLDER) {
  setPixmap(0, *folderClosed);
  setExpandable(f.getAssetFolders().size() != 0);
  setRenameEnabled(0, false);
}

void AssetFolder::setOpen(bool o) {
  // always clear out all children
  QListViewItem* item = firstChild();
  while (item) {
    takeItem(item);
    delete item;
    item = firstChild();
  }

  if (o && folder.getAssetFolders().size() != 0) {
    setPixmap(0, *folderOpen);
    populate();
  } else {
    setPixmap(0, *folderClosed);
  }

  QListViewItem::setOpen(o);
}

void AssetFolder::populate() {
  std::vector<gstAssetFolder> folders = folder.getAssetFolders();
  std::vector<gstAssetFolder>::iterator it = folders.begin();
  for (; it != folders.end(); ++it) {
    (void)new AssetFolder(this, *it);
  }
}

AssetFolder* AssetFolder::newFolder(const QString& text, QString &error) {
  if (!folder.newFolder(text, error))
    return NULL;

  if (!isExpandable())
    setExpandable(true);

  // if the folder was already opened, we need to create the
  // AssetFolder object
  if (isOpen())
    return new AssetFolder(this, folder.getChildFolder(text));

  // however, if it is closed, the setOpen() call will see this
  // new directory and build the AssetFolder object, so we need to find it
  setOpen(true);

  QListViewItem* child = firstChild();
  while (child) {
    if (child->text(0) == text)
      return dynamic_cast<AssetFolder*>(child);
    child = child->nextSibling();
  }

  return NULL;
}

// -----------------------------------------------------------------------------

static QPixmap uic_load_pixmap_AssetManager(const QString& name) {
  const QMimeSource* m = QMimeSourceFactory::defaultFactory()->data(name);
  if (!m)
    return QPixmap();
  QPixmap pix;
  QImageDrag::decode(m, pix);
  return pix;
}

bool DatabaseHasValidVersion(const Asset &asset) {
  AssetStorage::VersionList::const_iterator version = asset->versions.begin();
  for (; version != asset->versions.end(); ++version) {
    AssetVersion asset_version(*version);
    if (asset_version->state != AssetDefs::Succeeded)
      continue;
    if (asset_version->subtype == kMapDatabaseSubtype) {
      MapDatabaseAssetVersion mdav(asset_version);
      if (!mdav->GetMapdbChild())
        continue;
    } else if (asset_version->subtype == kMercatorMapDatabaseSubtype) {
      MercatorMapDatabaseAssetVersion mdav(asset_version);
      if (!mdav->GetMapdbChild())
        continue;
    } else {
      DatabaseAssetVersion dav(asset_version);
      // Make sure it's a new database with a gedb child
      GEDBAssetVersion gedb(dav->GetGedbChild());
      if (!gedb)
        continue;
      // Make sure that the gedb child has the newest config version
      if (!gedb->config._IsCurrentIdlVersion()) {
        continue;
      }
    }

    return true;
  }
  return false;
}

}  // namespace

// -----------------------------------------------------------------------------

const AssetDefs::Type TypeSet[] = {
  AssetDefs::Invalid,
  AssetDefs::Vector,
  AssetDefs::Imagery,
  AssetDefs::Terrain,
  AssetDefs::Map,
  AssetDefs::Database
};
const std::string SubTypeSet[] = {
  "",
  kResourceSubtype,
  kLayer,
  kProjectSubtype,
  kDatabaseSubtype
};

// -----------------------------------------------------------------------------

QString AssetManager::AssetRoot() {
  PrefsConfig prefs = Preferences::getConfig();

  if (prefs.showFullAssetPath) {
    return QString(AssetDefs::AssetRoot().c_str());
  } else {
    return QString("ASSET_ROOT");
  }
}

// -----------------------------------------------------------------------------

std::vector<AssetAction*> AssetAction::all_actions;

AssetAction::AssetAction(QObject* parent, AssetBase* asset_window)
  : QAction(parent),
    asset_window_(asset_window) {
  setText(asset_window->Name());
  AssetDisplayHelper helper(asset_window->AssetType(),
                            asset_window->AssetSubtype());
  setIconSet(QIconSet(helper.GetPixmap()));
  connect(this, SIGNAL(activated()), asset_window, SLOT(showNormal()));
  connect(this, SIGNAL(activated()), asset_window, SLOT(raise()));
  connect(asset_window, SIGNAL(NameChanged(const QString&)),
          this, SLOT(NameChanged(const QString&)));
  connect(asset_window, SIGNAL(destroyed()), this, SLOT(Cleanup()));
  all_actions.push_back(this);
}

void AssetAction::NameChanged(const QString& text) {
  setText(text);
}

void AssetAction::Cleanup() {
  std::vector<AssetAction*>::iterator pos = std::find(all_actions.begin(),
                                                      all_actions.end(), this);
  if (pos != all_actions.end())
    all_actions.erase(pos);
  delete this;
}

QString AssetAction::Name() const {
  return asset_window_->Name();
}

AssetAction* AssetAction::FindAsset(const QString& txt) {
  for (std::vector<AssetAction*>::iterator it = all_actions.begin();
       it != all_actions.end(); ++it) {
    if ((*it)->Name() == txt)
      return *it;
  }
  return NULL;
}

bool AssetAction::OkToCloseAll() {
  for (std::vector<AssetAction*>::iterator it = all_actions.begin();
       it != all_actions.end(); ++it) {
    if (!(*it)->asset_window_->OkToQuit())
      return false;
  }
  return true;
}

void AssetAction::CloseAll() {
  // make a copy of our asset window vector since deleting will
  // invalidate iterators on the original
  std::vector<AssetAction*> close_actions = all_actions;
  for (std::vector<AssetAction*>::iterator it = close_actions.begin();
       it != close_actions.end(); ++it) {
    if ((*it)->asset_window_->OkToQuit()) {
      delete (*it)->asset_window_;
    } else {
      // terminate at first failure
      return;
    }
  }
}

void AssetAction::Cascade(const QPoint& start_pos) {
  const int xoffset = 13;
  const int yoffset = 20;
  int x = start_pos.x() + xoffset;
  int y = start_pos.y() + yoffset;
  for (std::vector<AssetAction*>::iterator it = all_actions.begin();
       it != all_actions.end(); ++it) {
    (*it)->asset_window_->move(x, y);
    (*it)->asset_window_->showNormal();
    (*it)->asset_window_->raise();
    x += xoffset;
    y += yoffset;
  }
}

//------------------------------------------------------------------------------
ServeThread::ServeThread(PublisherClient* publisher_client,
                         const std::string& gedb_path)
    : publisher_client_(publisher_client),
      gedb_path_(gedb_path),
      retval_(false) {
}

ServeThread::~ServeThread() {
}

void ServeThread::start() {
  QThread::start();
}

PushThread::PushThread(PublisherClient* publisher_client,
                       const std::string& gedb_path)
    : ServeThread(publisher_client, gedb_path) {
}

void PushThread::run(void) {
#if 1
  retval_ = publisher_client_->PushDatabase(gedb_path_);
#else
  // Note: can be used for testing.
  while (progress_->done() < progress_->total()) {
    notify(NFY_WARN,
           "PushThread: %zd/%zd", progress_->done(), progress_->total());
    progress_->incrementDone(1);
    sleep(1);
  }
  retval_ = true;
#endif
  emit sfinished();
}

PublishThread::PublishThread(PublisherClient* publisher_client,
                             const std::string& gedb_path,
                             const std::string& target_path)
    : ServeThread(publisher_client, gedb_path),
      target_path_(target_path) {
}

void PublishThread::run(void) {
  retval_ = publisher_client_->PublishDatabase(gedb_path_, target_path_);
  emit sfinished();
}

ServeAssistant::ServeAssistant(QProgressDialog* progress_dialog,
                               geGuiProgress* progress,
                               geGuiAuth* auth)
    : progress_dialog_(progress_dialog),
      progress_(progress),
      auth_(auth) {
  QObject::connect(&timer_, SIGNAL(timeout()), this, SLOT(Perform()));
}

ServeAssistant::~ServeAssistant() {
}

void ServeAssistant::Start() {
  timer_.start(100);
}

void ServeAssistant::Stop() {
  timer_.stop();
}

void ServeAssistant::SetCanceled() {
  progress_->setCanceled();
}

void ServeAssistant::Perform() {
  progress_dialog_->setTotalSteps(progress_->total());
  progress_dialog_->setProgress(progress_->done());

  // Check to see if a request for user authentication has been made.
  // If so, pop up the dialog and signal when we are finished.
  // Note: IsRequestPending() has a mutex to prevent a race condition.
  if (auth_->IsRequestPending()) {
    auth_->ExecAndSignal();
  }
}

//------------------------------------------------------------------------------

AssetManager* AssetManager::self = NULL;

std::string AssetManager::GetProviderById(uint32 id) {
  ProviderMap::const_iterator found = provider_map_.find(id);
  if (found != provider_map_.end()) {
    return found->second;
  }
  return std::string();
}

AssetManager::AssetManager(QWidget* parent)
    : AssetManagerBase(parent),
      icon_grid_(128),
      filter_type_(0),
      filter_subtype_(0),
      asset_manager_icon_choice_orig_(
          Preferences::getConfig().assetManagerIconChoice) {
  RemoveToolBarIcons();  // Icons will be set at Show
  {
    gstProviderSet providers;
    if (providers.Load()) {
      for (uint i = 0; i < providers.items.size(); ++i) {
        provider_map_[providers.items[i].id] = providers.items[i].key;
      }
    }
  }

  connect(categories,
          SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
          this, SLOT(rmbClicked(QListViewItem*, const QPoint&, int)));

  connect(assetTabWidget, SIGNAL(currentChanged(QWidget*)),
          this, SLOT(selectFolder()));

  connect(assetTableView, SIGNAL(doubleClicked(int, int, int, const QPoint&)),
          this, SLOT(doubleClicked(int, int, int, const QPoint&)));

  connect(assetTableView, SIGNAL(contextMenuRequested(int, int, const QPoint&)),
          this, SLOT(tableAssetMenu(int, int, const QPoint&)));

  connect(assetIconView,
          SIGNAL(contextMenuRequested(QIconViewItem*, const QPoint&)),
          this, SLOT(iconAssetMenu(QIconViewItem*, const QPoint&)));

  connect(assetTableView, SIGNAL(currentChanged(int, int)),
          this, SLOT(CurrentAssetChanged(int, int)));

  if (folderOpen == 0) {
    folderOpen = new QPixmap(folder_open_xpm);
    folderClosed = new QPixmap(folder_closed_xpm);
  }

  categories->header()->setStretchEnabled(true);
  categories->header()->hide();

  if (khExists(Preferences::filepath("assetmanager.layout").latin1())) {
    if (layout_persist_.Load(
            Preferences::filepath("assetmanager.layout").latin1())) {
      // update filter combox
      filter_type_ = layout_persist_.filterType;
      filter_subtype_ = layout_persist_.filterSubType;
      typeCombo->setCurrentItem(filter_type_);
      subtypeCombo->setCurrentItem(filter_subtype_);

      // update position
      resize(layout_persist_.width, layout_persist_.height);
      move(layout_persist_.xpos, layout_persist_.ypos);

      // update viewmode
      if (layout_persist_.viewMode == AssetManagerLayout::List) {
        assetTabWidget->setCurrentPage(0);
      } else if (layout_persist_.viewMode == AssetManagerLayout::Preview) {
        assetTabWidget->setCurrentPage(1);
      }

      // update visibility
      if (layout_persist_.showme)
        show();

      showHiddenAssets(layout_persist_.showHidden);
      showHiddenCheck->setChecked(layout_persist_.showHidden);

      if (layout_persist_.folderSplitter.front() != 0) {
        QValueList<int> splitter_list = layout_persist_.folderSplitter;
        folder_splitter->setSizes(splitter_list);
      }
    }
  }

  setCaption(tr("Asset Manager") + Preferences::CaptionText());
  self = this;

  // disable some buttons in LT Mode
  if (GetFusionProductType() == FusionLT) {
    newImageryResourceAction->removeFrom(Toolbar);
    newTerrainResourceAction->removeFrom(Toolbar);
    newImageryProjectAction->removeFrom(Toolbar);
    newTerrainProjectAction->removeFrom(Toolbar);
  }
  toolbar_chooser_combo->setCurrentItem(asset_manager_icon_choice_orig_);
}

AssetManager::~AssetManager() {
  if (asset_manager_icon_choice_orig_ !=
      Preferences::getConfig().assetManagerIconChoice) {
    Preferences::getConfig().Save(Preferences::filepath("preferences.xml"));
  }
  layout_persist_.showme = isShown();
  if (assetTabWidget->currentPageIndex() == 0) {
    layout_persist_.viewMode = AssetManagerLayout::List;
  } else if (assetTabWidget->currentPageIndex() == 1) {
    layout_persist_.viewMode = AssetManagerLayout::Preview;
  }

  gstAssetFolder folder = GetSelectedFolder();
  if (folder.isValid()) {
    layout_persist_.selectedPath = folder.relativePath();
  } else {
    layout_persist_.selectedPath = QString::null;
  }

  layout_persist_.folderSplitter.clear();
  QValueList<int> folder_splitter_list = folder_splitter->sizes();
  for (QValueList<int>::Iterator it = folder_splitter_list.begin();
       it != folder_splitter_list.end(); ++it) {
    layout_persist_.folderSplitter.push_back(*it);
  }

  layout_persist_.filterType = filter_type_;
  layout_persist_.filterSubType = filter_subtype_;
  layout_persist_.Save(Preferences::filepath("assetmanager.layout").latin1());
}

AssetManagerLayout::Size AssetManager::GetLayoutSize(const QString& name) {
  return self->layout_persist_.FindLayoutByName(name);
}

void AssetManager::SetLayoutSize(const QString& name, int width, int height) {
  self->layout_persist_.SetLayoutSize(name, width, height);
}

void AssetManager::HandleNewWindow(AssetBase* asset_window) {
  AssetDisplayHelper helper(asset_window->AssetType(),
                            asset_window->AssetSubtype());
  AssetAction* action = new AssetAction(this, asset_window);
  action->addTo(Window);
  asset_window->setIcon(helper.GetPixmap());
  asset_window->move(QCursor::pos());
  asset_window->show();
}

bool AssetManager::RestoreExisting(const std::string& asset_ref) {
  AssetAction* action = AssetAction::FindAsset(asset_ref);
  if (action == NULL) {
    return false;
  } else {
    action->activate();
    return true;
  }
}

bool AssetManager::OkToQuit() {
  return AssetAction::OkToCloseAll();
}

void AssetManager::CloseAllWindows() {
  AssetAction::CloseAll();
}

void AssetManager::CascadeWindows() {
  AssetAction::Cascade(pos());
}

void AssetManager::CreateNewAsset() {
  NewAsset new_asset(this);
  AssetDisplayHelper::AssetKey asset_type  = new_asset.ChooseAssetType();

  switch (asset_type) {
    case AssetDisplayHelper::Key_VectorProduct:
      HandleNewWindow(new VectorAsset(this));
      break;
    case AssetDisplayHelper::Key_VectorLayer:
      HandleNewWindow(new VectorLayer(this));
      break;
    case AssetDisplayHelper::Key_VectorProject:
      HandleNewWindow(new VectorProject(this));
      break;
    case AssetDisplayHelper::Key_ImageryProduct:
      HandleNewWindow(new ImageryAsset(this));
      break;
    case AssetDisplayHelper::Key_MercatorImageryProduct:
      HandleNewWindow(new MercatorImageryAsset(this));
      break;
    case AssetDisplayHelper::Key_ImageryProject:
      HandleNewWindow(new ImageryProject(this));
      break;
    case AssetDisplayHelper::Key_MercatorImageryProject:
      HandleNewWindow(new ImageryProject(this));
      break;
    case AssetDisplayHelper::Key_TerrainProduct:
      HandleNewWindow(new TerrainAsset(this));
      break;
    case AssetDisplayHelper::Key_TerrainProject:
      HandleNewWindow(new TerrainProject(this));
      break;
    case AssetDisplayHelper::Key_Database:
      HandleNewWindow(new Database(this));
      break;
    case AssetDisplayHelper::Key_MapLayer:
      HandleNewWindow(new MapLayer(this));
      break;
    case AssetDisplayHelper::Key_MapProject:
      HandleNewWindow(new MapProject(this));
      break;
    case AssetDisplayHelper::Key_MapDatabase:
      HandleNewWindow(new MapDatabase(this));
      break;
    case AssetDisplayHelper::Key_MercatorMapDatabase:
      HandleNewWindow(new MercatorMapDatabase(this));
      break;
    case AssetDisplayHelper::Key_KMLProject:
      HandleNewWindow(new KMLProject(this));
      break;
    case AssetDisplayHelper::Key_Invalid:
    case AssetDisplayHelper::Key_Unknown:
      // do nothing
      break;
  }
}

void AssetManager::NewVectorAsset() {
  HandleNewWindow(new VectorAsset(this));
}

void AssetManager::NewVectorLayer() {
  HandleNewWindow(new VectorLayer(this));
}

void AssetManager::NewVectorProject() {
  HandleNewWindow(new VectorProject(this));
}

void AssetManager::NewImageryAsset() {
  HandleNewWindow(new ImageryAsset(this));
}

void AssetManager::NewMercatorImageryAsset() {
  HandleNewWindow(new MercatorImageryAsset(this));
}

void AssetManager::NewImageryProject() {
  HandleNewWindow(new ImageryProject(this));
}

void AssetManager::NewMercatorImageryProject() {
  HandleNewWindow(new MercatorImageryProject(this));
}

void AssetManager::NewTerrainAsset() {
  HandleNewWindow(new TerrainAsset(this));
}

void AssetManager::NewTerrainProject() {
  HandleNewWindow(new TerrainProject(this));
}

void AssetManager::NewMapLayer() {
  HandleNewWindow(new MapLayer(this));
}

void AssetManager::NewMapProject() {
  HandleNewWindow(new MapProject(this));
}

void AssetManager::NewMapDatabase() {
  HandleNewWindow(new MapDatabase(this));
}

void AssetManager::ToolbarChooserComboActivated(int choice) {
  Preferences::getConfig().assetManagerIconChoice =
      static_cast<PrefsConfig::ShowAssetManagerIconType>(choice);
  HideIcons();
  ShowIcons();
}

void AssetManager::NewMercatorMapDatabase() {
  HandleNewWindow(new MercatorMapDatabase(this));
}

void AssetManager::NewKMLProject() {
  HandleNewWindow(new KMLProject(this));
}

void AssetManager::NewDatabase() {
  HandleNewWindow(new Database(this));
}

void AssetManager::moveEvent(QMoveEvent* event) {
  const QPoint& pt = event->pos();

  // XXX only update if this is a valid event
  // XXX this is clearly a QT bug!
  if (x() != 0 && y() != 0) {
    layout_persist_.xpos = pt.x();
    layout_persist_.ypos = pt.y();
  }
}

void AssetManager::resizeEvent(QResizeEvent* event) {
  const QSize& sz = event->size();
  layout_persist_.width = sz.width();
  layout_persist_.height = sz.height();
}

void AssetManager::RemoveToolBarIcons() {
  newVectorResourceAction->removeFrom(Toolbar);
  newVectorProjectAction->removeFrom(Toolbar);
  newImageryResourceAction->removeFrom(Toolbar);
  newImageryProjectAction->removeFrom(Toolbar);
  newTerrainResourceAction->removeFrom(Toolbar);
  newTerrainProjectAction->removeFrom(Toolbar);
  newDatabaseAction->removeFrom(Toolbar);
  newImageryResourceMercatorAction->removeFrom(Toolbar);
  newImageryProjectMercatorAction->removeFrom(Toolbar);
  newMapLayerAction->removeFrom(Toolbar);
  newMapProjectAction->removeFrom(Toolbar);
  newMapDatabaseMercatorAction->removeFrom(Toolbar);
  newMapDatabaseAction->removeFrom(Toolbar);
}

void AssetManager::ShowIcons() {
  switch (asset_manager_icon_choice_ =
          Preferences::getConfig().assetManagerIconChoice) {
    case PrefsConfig::ShowEarthIcons:
      newImageryResourceAction->addTo(Toolbar);
      newImageryProjectAction->addTo(Toolbar);
      newVectorResourceAction->addTo(Toolbar);
      newVectorProjectAction->addTo(Toolbar);
      newTerrainResourceAction->addTo(Toolbar);
      newTerrainProjectAction->addTo(Toolbar);
      newDatabaseAction->addTo(Toolbar);
      break;
    case PrefsConfig::ShowMercatorMapIcons:
      newImageryResourceMercatorAction->addTo(Toolbar);
      newImageryProjectMercatorAction->addTo(Toolbar);
      newVectorResourceAction->addTo(Toolbar);
      newMapLayerAction->addTo(Toolbar);
      newMapProjectAction->addTo(Toolbar);
      newMapDatabaseMercatorAction->addTo(Toolbar);
      break;
    case PrefsConfig::ShowWjs84MapIcons:
      newImageryResourceAction->addTo(Toolbar);
      newImageryProjectAction->addTo(Toolbar);
      newVectorResourceAction->addTo(Toolbar);
      newMapLayerAction->addTo(Toolbar);
      newMapProjectAction->addTo(Toolbar);
      newMapDatabaseAction->addTo(Toolbar);
      break;
    default:
      break;
  }
}

void AssetManager::show() {
  if (!isVisible()) {
    connect(SystemListener::instance,
            SIGNAL(assetsChanged(const AssetChanges&)),
            this,
            SLOT(assetsChanged(const AssetChanges&)));
    RedrawTree(true);
  }
  HideIcons();
  ShowIcons();
  AssetManagerBase::show();
}

void AssetManager::HideIcons() {
  switch (asset_manager_icon_choice_) {
    case PrefsConfig::ShowEarthIcons:
      newVectorResourceAction->removeFrom(Toolbar);
      newVectorProjectAction->removeFrom(Toolbar);
      newImageryResourceAction->removeFrom(Toolbar);
      newImageryProjectAction->removeFrom(Toolbar);
      newTerrainResourceAction->removeFrom(Toolbar);
      newTerrainProjectAction->removeFrom(Toolbar);
      newDatabaseAction->removeFrom(Toolbar);
      break;
    case PrefsConfig::ShowMercatorMapIcons:
      newVectorResourceAction->removeFrom(Toolbar);
      newImageryResourceMercatorAction->removeFrom(Toolbar);
      newImageryProjectMercatorAction->removeFrom(Toolbar);
      newMapLayerAction->removeFrom(Toolbar);
      newMapProjectAction->removeFrom(Toolbar);
      newMapDatabaseMercatorAction->removeFrom(Toolbar);
      break;
    case PrefsConfig::ShowWjs84MapIcons:
      newVectorResourceAction->removeFrom(Toolbar);
      newImageryResourceAction->removeFrom(Toolbar);
      newImageryProjectAction->removeFrom(Toolbar);
      newMapLayerAction->removeFrom(Toolbar);
      newMapProjectAction->removeFrom(Toolbar);
      newMapDatabaseAction->removeFrom(Toolbar);
      break;
    default:
      break;
  }
}

void AssetManager::hide() {
  disconnect(SystemListener::instance,
             SIGNAL(assetsChanged(const AssetChanges&)),
             this,
             SLOT(assetsChanged(const AssetChanges&)));
  HideIcons();
  AssetManagerBase::hide();
}

void AssetManager::RedrawTree(bool select_top) {
  categories->clear();

  if (theAssetManager == NULL) {
    QMessageBox::warning(this, "Warning",
                         trUtf8("Asset Manager is misconfigured!"),
                         tr("OK"), 0, 0, 1);
    return;
  }

  const gstAssetFolder& assetroot = theAssetManager->getAssetRoot();

  AssetFolder* parent = new AssetFolder(categories, assetroot);
  parent->setText(0, AssetRoot());
  parent->setOpen(true);

  // first time drawing the tree might need to restore
  // previous view.
  if (!layout_persist_.selectedPath.isEmpty()) {
    OpenFolder(layout_persist_.selectedPath);
    layout_persist_.selectedPath = QString::null;
  } else if (select_top && categories->firstChild()) {
    categories->setSelected(categories->firstChild(), true);
  }
}

void AssetManager::addAsset() {
}

void AssetManager::childCollapsed(QListViewItem* item) {
  AssetFolder* assetfolder = dynamic_cast<AssetFolder*>(item);
  if (assetfolder == NULL)
    return;

  gstAssetFolder folder = GetSelectedFolder();
  if (!folder.isValid())
    categories->setSelected(assetfolder, true);
}

void AssetManager::rmbClicked(QListViewItem* item, const QPoint& pos, int) {
  enum { REFRESH, NEW_FOLDER };

  QPopupMenu menu(this);

  menu.insertItem(trUtf8("Refresh"), REFRESH);
  menu.insertSeparator();

  QString folder_name;
  AssetFolder* asset_folder = dynamic_cast<AssetFolder*>(item);
  if (asset_folder != NULL) {
    folder_name = asset_folder->getFolder().fullPath();
  }

  menu.insertItem(trUtf8("New Subfolder..."), NEW_FOLDER);

  switch (menu.exec(pos)) {
    case REFRESH:
      refresh();
      break;

    case NEW_FOLDER:
      NewFolder(folder_name);
      break;
  }
}

void AssetManager::tableAssetMenu(int row, int col, const QPoint& mouse_pos) {
  gstAssetHandle handle = GetAssetByRow(row);
  if (!handle->isValid())
    return;
  ShowAssetMenu(handle, mouse_pos);
}

void AssetManager::iconAssetMenu(QIconViewItem* item, const QPoint& mouse_pos) {
  AssetIcon* icon = dynamic_cast<AssetIcon*>(item);
  if (icon == NULL)
    return;

  ShowAssetMenu(icon->getAssetHandle(), mouse_pos);
}

void AssetManager::ShowAssetMenu(const gstAssetHandle& asset_handle,
                                 const QPoint& mouse_pos) {
  enum { BUILD_ASSET, CANCEL_ASSET, MODIFY_ASSET,
         PUSH_DB, PUBLISH_DB, ASSET_PROPERTIES,
         CURR_VER_PROPERTIES };
  QPopupMenu menu(this);

  Asset current_asset = asset_handle->getAsset();
  AssetVersion current_version(current_asset->CurrVersionRef());

  // first item in menu should be the asset name since the table
  // might get redrawn after the menu has popped-up
  AssetDisplayHelper a(current_asset->type, current_asset->subtype);
  menu.insertItem(a.GetPixmap(), shortAssetName(asset_handle->getName()));

  menu.insertSeparator();
  menu.insertSeparator();

  if (current_version) {
    menu.insertItem(trUtf8("Current Version Properties"),
                    CURR_VER_PROPERTIES);
  }
  menu.insertItem(trUtf8("Asset Versions"), ASSET_PROPERTIES);
  if (current_version && current_version->CanCancel()) {
    menu.insertItem(trUtf8("Cancel Current Version"),
                    CANCEL_ASSET);
  }

  if (current_asset->type == AssetDefs::Database) {
    int push_item_id = menu.insertItem(trUtf8("Push"), PUSH_DB);
    if (DatabaseHasValidVersion(current_asset)) {
      menu.setItemEnabled(push_item_id, TRUE);
    } else {
      menu.setItemEnabled(push_item_id, FALSE);
    }

    // Note: Switches off Publish functionality.
    // The virtual host is removed from Server Combination,
    // So it contains only URL, while for publishing we need URL + virtual
    // host.
    // Thought is to encourage server UI for all publishing.
    // menu.insertItem(trUtf8("Publish"), PUBLISH_DB);
  }

  menu.insertItem(trUtf8("&Build"), BUILD_ASSET);
  menu.insertItem(trUtf8("Modify"), MODIFY_ASSET);

  switch (menu.exec(mouse_pos)) {
    case BUILD_ASSET:
      BuildAsset(asset_handle);
      break;

    case CANCEL_ASSET:
      CancelAsset(asset_handle);
      break;

    case MODIFY_ASSET:
      ModifyAsset(asset_handle);
      break;

    case ASSET_PROPERTIES:
      ShowAssetProperties(asset_handle);
      break;

    case CURR_VER_PROPERTIES:
      ShowCurrVerProperties(asset_handle);
      break;

    case PUSH_DB:
      PushDatabase(asset_handle);
      break;

    case PUBLISH_DB:
      PublishDatabase(asset_handle);
      break;
  }
}

void AssetManager::showHiddenAssets(bool checked) {
  layout_persist_.showHidden = checked;
  // force redraw of table view or icon view
  selectFolder();
}

void AssetManager::CurrentAssetChanged(int row, int col) {
#if 0
  if (row == -1 || col == -1) {
    detail_stack->raiseWidget(0);
    return;
  }

  gstAssetHandle handle = GetAssetByRow(row);
  Asset current_asset = handle->getAsset();
  AssetVersion current_version(current_asset->CurrVersionRef());
  if (current_asset->type == AssetDefs::Database) {
    detail_stack->raiseWidget(1);
  } else {
    detail_stack->raiseWidget(2);
  }
#endif
}

void AssetManager::doubleClicked(int row, int col, int button,
                                 const QPoint& mouse_pos) {
  // clicking on background deselects current asset
  if (row == -1 || col == -1)
    return;

  gstAssetHandle handle = GetAssetByRow(row);
  if (!handle->isValid())
    return;

  if (col == 0)
    ModifyAsset(handle);
  if (col == 3 || col == 4)
    ShowCurrVerProperties(handle);
}

void AssetManager::ShowAssetProperties(const gstAssetHandle& handle) {
  AssetProperties* properties = new AssetProperties(NULL, handle);
  properties->show();
}

void AssetManager::ShowCurrVerProperties(const gstAssetHandle& handle) {
  Asset currAsset = handle->getAsset();
  AssetVersionProperties::Open(currAsset->CurrVersionRef());
}

gstAssetHandle AssetManager::GetAssetByRow(int row) {
  if (row == -1)
    return gstAssetHandleImpl::Create(gstAssetFolder(QString::null),
                                      QString::null);
  return assetTableView->GetAssetHandle(row);
}

void AssetManager::BuildAsset(const gstAssetHandle& handle) {
  QString error;
  if (!theAssetManager->buildAsset(handle, error)) {
    if (error.isEmpty())
      error =  tr("Build has unknown problems.\n");
    QMessageBox::critical(this, tr("Error"),
                          error,
                          tr("OK"), 0, 0, 0);
  }
}

void AssetManager::CancelAsset(const gstAssetHandle& handle) {
  QString error;
  if (!theAssetManager->cancelAsset(handle, error)) {
    if (error.isEmpty())
      error =  tr("Cancel has unknown problems.\n");
    QMessageBox::critical(this, tr("Error"),
                          error,
                          tr("OK"), 0, 0, 0);
  }
}

class FixCursor {
 public:
  FixCursor(QWidget* p) : parent(p) {}
  ~FixCursor() {
    parent->setCursor(Qt::arrowCursor);
  }
 private:
  QWidget* parent;
};

void AssetManager::PushDatabase(const gstAssetHandle& handle) {
  Asset asset = handle->getAsset();
  ServerCombinationSet sc_set;
  sc_set.Load();

  if (asset->versions.size() == 0) {
    QMessageBox::critical(this, "Error",
            tr("Please build the database first."), 0, 0, 0);
    return;
  }

  if (sc_set.combinations.size() == 0) {
    QMessageBox::critical(this, "Error", tr("Please add at least one server"
      "association using the Publisher tool."), 0, 0, 0);
    return;
  }

  std::vector<QString> nicknames;
  std::vector<ServerCombination>::const_iterator it =
      sc_set.combinations.begin();
  for (; it != sc_set.combinations.end(); ++it) {
    nicknames.push_back(it->nickname);
  }

  PushDatabaseDialog push_db_dlg(this, asset, nicknames);
  if (!push_db_dlg.HasValidVersions()) {
    QMessageBox::critical(
        this, "Error",
        tr("This database does not have a single pushable version."
           " Try rebuilding the database."),
        0, 0, 0);
    return;
  }

  if (push_db_dlg.exec() != QDialog::Accepted)
    return;

  AssetVersion db_asset_version();

  std::string gedb_path;
  AssetVersion gedb_version;
  if (asset->subtype == kMapDatabaseSubtype) {
    MapDatabaseAssetVersion mdav(push_db_dlg.GetSelectedVersion());
    gedb_version = mdav->GetMapdbChild();
  } else if (asset->subtype == kMercatorMapDatabaseSubtype) {
    MercatorMapDatabaseAssetVersion mdav(push_db_dlg.GetSelectedVersion());
    gedb_version = mdav->GetMapdbChild();
  } else {
    DatabaseAssetVersion dav(push_db_dlg.GetSelectedVersion());
    gedb_version = dav->GetGedbChild();
  }

  gedb_path = gedb_version->GetOutputFilename(0);

  QString nickname = push_db_dlg.GetSelectedNickname();

  // Update the preferences with the user's choice. We want to remember these
  // choices so that we can automatically select this server next time they
  // push/publish.
  std::string database_name = shortAssetName(asset->GetRef());
  Preferences::UpdatePublishServerDbMap(database_name, nickname);

  ServerConfig stream_server, search_server;
  for (it = sc_set.combinations.begin();
       it != sc_set.combinations.end(); ++it) {
    if (nickname == it->nickname) {
      stream_server = it->stream;
      search_server = stream_server;
      break;
    }
  }

  geGuiProgress progress(100);
  geGuiAuth auth(this);
  // Currently, the auth dialog will be executed in the current thread.
  auth.SetSynchronous(true);

  PublisherClient publisher_client(AssetDefs::MasterHostName(),
                                   stream_server, search_server,
                                   &progress, &auth);
  if (!publisher_client.AddDatabase(
          gedb_path, push_db_dlg.GetSelectedVersion())) {
    QMessageBox::critical(this, "Push Failed",
            tr("Error: %1 ").arg(publisher_client.ErrMsg()), 0, 0, 0);
    return;
  }

  FixCursor fix_cursor(this);
  QProgressDialog progress_dialog(tr("Pushing database..."),
                                  tr("Cancel"), 100, this, "progress", true);
  progress_dialog.setCaption(tr("Pushing"));

  // PublisherClient will now be run in a separate thread,
  // so any calls to the auth dialog now need to be asynchronous.
  auth.SetSynchronous(false);
  PushThread push_thread(&publisher_client, gedb_path);

  {
    ServeAssistant push_assistant(&progress_dialog, &progress, &auth);
    QObject::connect(&progress_dialog, SIGNAL(canceled()),
                     &push_assistant, SLOT(SetCanceled()));
    QObject::connect(
        &push_thread, SIGNAL(sfinished()), &push_assistant, SLOT(Stop()));
    QObject::connect(&push_thread, SIGNAL(sfinished()), qApp, SLOT(quit()));

    push_thread.start();
    push_assistant.Start();
    progress_dialog.show();

    qApp->exec();
  }

  if (progress_dialog.wasCanceled()) {
    QMessageBox::critical(this, "Push Interrupted",
                          tr("Push Interrupted"), 0, 0, 0);
    return;
  }

  // hide progress dialog
  progress_dialog.reset();

  if (!push_thread.retval()) {
    QMessageBox::critical(this, "Push Failed",
            tr("Error: %1").arg(publisher_client.ErrMsg()), 0, 0, 0);
    return;
  }

  QMessageBox::information(this, tr("Success"),
                          tr("Database Successfully Pushed"),
                          QMessageBox::Ok, 0, 0);
}

void AssetManager::PublishDatabase(const gstAssetHandle& handle) {
  Asset asset = handle->getAsset();
  ServerCombinationSet sc_set;
  sc_set.Load();

  if (asset->versions.size() == 0) {
    QMessageBox::critical(this, "Error",
            tr("Please build the database first."), 0, 0, 0);
    return;
  }

  if (sc_set.combinations.size() == 0) {
    QMessageBox::critical(this, "Error", tr("Please add at least one server"
      "association using the Publisher tool."), 0, 0, 0);
    return;
  }

  std::vector<QString> nicknames;
  std::vector<ServerCombination>::const_iterator it =
      sc_set.combinations.begin();
  for (; it != sc_set.combinations.end(); ++it) {
    nicknames.push_back(it->nickname);
  }

  PublishDatabaseDialog publish_db_dlg(this, asset, nicknames);
  if (!publish_db_dlg.HasValidVersions()) {
    QMessageBox::critical(this, "Error",
      tr("This database does not have a single publishable version."
         " Try rebuilding the database."),
      0, 0, 0);
    return;
  }

  if (publish_db_dlg.exec() != QDialog::Accepted)
    return;

  std::string target_path = publish_db_dlg.GetTargetPath();

  AssetVersion db_asset_version();

  std::string gedb_path;
  AssetVersion gedb_version;
  if (asset->subtype == kMapDatabaseSubtype) {
    MapDatabaseAssetVersion mdav(publish_db_dlg.GetSelectedVersion());
    gedb_version = mdav->GetMapdbChild();
  } else if (asset->subtype == kMercatorMapDatabaseSubtype) {
    MercatorMapDatabaseAssetVersion mdav(publish_db_dlg.GetSelectedVersion());
    gedb_version = mdav->GetMapdbChild();
  } else {
    DatabaseAssetVersion dav(publish_db_dlg.GetSelectedVersion());
    gedb_version = dav->GetGedbChild();
  }

  gedb_path = gedb_version->GetOutputFilename(0);

  QString nickname = publish_db_dlg.GetSelectedNickname();

  // Update the preferences with the user's choice. We want to remember these
  // choices so that we can automatically select this server next time they
  // push/publish.
  std::string database_name = shortAssetName(asset->GetRef());
  Preferences::UpdatePublishServerDbMap(database_name, nickname);

  ServerConfig stream_server, search_server;
  for (it = sc_set.combinations.begin();
       it != sc_set.combinations.end(); ++it) {
    if (nickname == it->nickname) {
      stream_server = it->stream;
      search_server = stream_server;
      break;
    }
  }

  geGuiProgress progress(100);
  geGuiAuth auth(this);

  // Currently, the auth dialog will be executed in the current thread.
  auth.SetSynchronous(true);

  PublisherClient publisher_client(AssetDefs::MasterHostName(),
                                   stream_server, search_server,
                                   &progress, &auth);
  FixCursor fix_cursor(this);
  QProgressDialog progress_dialog(tr("Publishing database..."),
                                  tr("Cancel"), 100, this, "progress", true);
  progress_dialog.setCaption(tr("Publishing"));

  // PublisherClient will now be run in a separate thread,
  // so any calls to the auth dialog now need to be asynchronous.
  auth.SetSynchronous(false);
  PublishThread publish_thread(&publisher_client, gedb_path, target_path);

  {
    ServeAssistant publish_assistant(&progress_dialog, &progress, &auth);
    QObject::connect(&progress_dialog, SIGNAL(canceled()),
                     &publish_assistant, SLOT(SetCanceled()));
    QObject::connect(
        &publish_thread, SIGNAL(sfinished()), &publish_assistant, SLOT(Stop()));
    QObject::connect(&publish_thread, SIGNAL(sfinished()), qApp, SLOT(quit()));

    publish_thread.start();
    publish_assistant.Start();
    progress_dialog.show();

    qApp->exec();
  }

  if (progress_dialog.wasCanceled()) {
    QMessageBox::critical(this, "Publish Interrupted",
                          tr("Publish Interrupted"), 0, 0, 0);
    return;
  }

  // hide progress dialog
  progress_dialog.reset();

  if (!publish_thread.retval()) {
    QMessageBox::critical(this, "Publish Failed",
            tr("Error: %1").arg(publisher_client.ErrMsg()), 0, 0, 0);
    return;
  }

  QMessageBox::information(this, tr("Success"),
                          tr("Database Successfully Published"),
                          QMessageBox::Ok, 0, 0);
}

void AssetManager::ModifyAsset(const gstAssetHandle& handle) {
  Asset current_asset = handle->getAsset();
  std::string assetref = current_asset->GetRef();
  if (RestoreExisting(assetref))
    return;

  AssetBase* asset_window = NULL;
  if (current_asset->type == AssetDefs::Imagery &&
      current_asset->subtype == kProductSubtype) {
    RasterProductAsset prod(assetref);
    RasterProductImportRequest request(prod->type);
    request.assetname = assetref;
    request.config = prod->config;
    request.meta = prod->meta;
    SourceAssetVersion source(prod->inputs[0]);
    assert(source);
    request.sources = source->config;
    asset_window = new ImageryAsset(this, request);
  } else if (current_asset->type == AssetDefs::Imagery &&
      current_asset->subtype == kMercatorProductSubtype) {
    MercatorRasterProductAsset prod(assetref);
    RasterProductImportRequest request(prod->type);
    request.assetname = assetref;
    request.config = prod->config;
    request.meta = prod->meta;
    SourceAssetVersion source(prod->inputs[0]);
    assert(source);
    request.sources = source->config;
    asset_window = new MercatorImageryAsset(this, request);
  } else if (current_asset->type == AssetDefs::Terrain &&
      current_asset->subtype == kProductSubtype) {
    RasterProductAsset prod(assetref);
    RasterProductImportRequest request(prod->type);
    request.assetname = assetref;
    request.config = prod->config;
    request.meta = prod->meta;
    SourceAssetVersion source(prod->inputs[0]);
    assert(source);
    request.sources = source->config;
    asset_window = new TerrainAsset(this, request);
  } else if (current_asset->type == AssetDefs::Vector &&
             current_asset->subtype == kProductSubtype) {
    VectorProductAsset prod(assetref);
    VectorProductImportRequest request;
    request.assetname = assetref;
    request.config = prod->config;
    request.meta = prod->meta;
    SourceAssetVersion source(prod->inputs[0]);
    assert(source);
    request.sources = source->config;
    asset_window = new VectorAsset(this, request);
  } else if (current_asset->type == AssetDefs::Database &&
             current_asset->subtype == kDatabaseSubtype) {
    DatabaseAsset dbasset(assetref);
    DatabaseEditRequest request;
    request.assetname = assetref;
    request.config = dbasset->config;
    request.meta = dbasset->meta;
    asset_window = new Database(this, request);
  } else if (current_asset->type == AssetDefs::Database &&
             current_asset->subtype == kMapDatabaseSubtype) {
    MapDatabaseAsset dbasset(assetref);
    MapDatabaseEditRequest request;
    request.assetname = assetref;
    request.config = dbasset->config;
    request.meta = dbasset->meta;
    asset_window = new MapDatabase(this, request);
  } else if (current_asset->type == AssetDefs::Database &&
             current_asset->subtype == kMercatorMapDatabaseSubtype) {
    MercatorMapDatabaseAsset dbasset(assetref);
    MapDatabaseEditRequest request;
    request.assetname = assetref;
    request.config = dbasset->config;
    request.meta = dbasset->meta;
    asset_window = new MercatorMapDatabase(this, request);
  } else if (current_asset->type == AssetDefs::Map &&
             current_asset->subtype == kLayer) {
    MapLayerEditRequest request;
    request.assetname = assetref;
    MapLayerAsset layer(assetref);
    request.config = layer->config;
    request.meta = layer->meta;
    asset_window = new MapLayer(this, request);
  } else if (current_asset->type == AssetDefs::Map &&
             current_asset->subtype == kProjectSubtype) {
    MapProjectEditRequest request;
    request.assetname = assetref;
    MapProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new MapProject(this, request);
  } else if (current_asset->type == AssetDefs::Vector &&
             current_asset->subtype == kLayer) {
    VectorLayerXEditRequest request;
    request.assetname = assetref;
    VectorLayerXAsset layer(assetref);
    request.config = layer->config;
    request.meta = layer->meta;
    asset_window = new VectorLayer(this, request);
  } else if (current_asset->type == AssetDefs::Vector &&
             current_asset->subtype == kProjectSubtype) {
    VectorProjectEditRequest request;
    request.assetname = assetref;
    VectorProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new VectorProject(this, request);
  } else if (current_asset->type == AssetDefs::Imagery &&
             current_asset->subtype == kProjectSubtype) {
    RasterProjectEditRequest request(AssetDefs::Imagery);
    request.assetname = assetref;
    RasterProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new ImageryProject(this, request);
  } else if (current_asset->type == AssetDefs::Imagery &&
             current_asset->subtype == kMercatorProjectSubtype) {
    RasterProjectEditRequest request(AssetDefs::Imagery);
    request.assetname = assetref;
    MercatorRasterProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new MercatorImageryProject(this, request);
  } else if (current_asset->type == AssetDefs::Terrain &&
             current_asset->subtype == kProjectSubtype) {
    RasterProjectEditRequest request(AssetDefs::Terrain);
    request.assetname = assetref;
    RasterProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new TerrainProject(this, request);
  } else if (current_asset->type == AssetDefs::KML &&
             current_asset->subtype == kProjectSubtype) {
    KMLProjectEditRequest request;
    request.assetname = assetref;
    KMLProjectAsset project(assetref);
    request.config = project->config;
    request.meta = project->meta;
    asset_window = new KMLProject(this, request);
  }

  if (asset_window) {
    HandleNewWindow(asset_window);
  }
}

void AssetManager::refresh() {
  // int row = assetTableView->currentRow();

  // remember which folder is selected
  QString save_path;
  AssetFolder* item = dynamic_cast<AssetFolder*>(categories->selectedItem());
  if (item != NULL) {
    save_path = item->getFolder().relativePath();
  }

  // now reselect the folder
  if (save_path.isEmpty()) {
    RedrawTree(true);
  } else {
    RedrawTree(false);
    OpenFolder(save_path);
  }
}

void AssetManager::assetsChanged(const AssetChanges& changes) {
  // figure out the currently selected directory
  QString currpath;
  AssetFolder* item = dynamic_cast<AssetFolder*>(categories->selectedItem());
  if (item != NULL) {
    currpath = item->getFolder().relativePath();
  }
  if (currpath.isEmpty()) {
    currpath = ".";
  }

  // convert it to std::string only once for speed
  std::string curr = currpath.latin1();

  // check to see if any of the changes are in this directory
  std::set<std::string> changedHere;
  for (AssetChanges::CIterator i = changes.items.begin();
       i != changes.items.end(); ++i) {
    if (khDirname(i->ref) == curr) {
      changedHere.insert(AssetVersionRef(i->ref).AssetRef());
    }
  }

  if (changedHere.size()) {
    gstAssetFolder folder = GetSelectedFolder();
    if (assetTabWidget->currentPageIndex() == 0) {
      TrackChangesInTableView(folder, changedHere);
    } else {
      UpdateIconView(folder);
    }
  }
}

void AssetManager::NewFolder(const QString& folder_name) {
  assert(theAssetManager != NULL);

  bool ok;
  QString text = QInputDialog::getText(tr("New Subfolder"),
                                       tr("Name:"),
                                       QLineEdit::Normal, QString::null,
                                       &ok, this);
  if (!ok || text.isEmpty())
    return;

  QListViewItem* item;

  if (folder_name.isEmpty()) {
    item = categories->firstChild();
  } else {
    item = OpenFolder(gstAssetFolder(folder_name).relativePath());
  }

  if (item == NULL) {
    QMessageBox::warning(this, "Warning",
                         tr("Unable to create new directory: \n") +
                         folder_name + "/" + text + QString("\n\n") +
                         tr("Please confirm directory path in shell."),
                         tr("OK"), 0, 0, 1);
    return;
  }

  AssetFolder* asset_folder = dynamic_cast<AssetFolder*>(item);
  if (!asset_folder)
    return;

  QString error;
  AssetFolder* new_folder = asset_folder->newFolder(text, error);

  if (!new_folder) {
    if (error.isEmpty()) {
      // This error is because we have a problem making the widgetry
      QMessageBox::warning(this, "Warning",
                           tr("Internal error while creating directory"),
                           tr("OK"), 0, 0, 1);
    } else {
      // This is where we will see permissions and other filesytem errors
      QMessageBox::warning(this, "Warning",
                           error, tr("OK"), 0, 0, 1);
    }
    return;
  }

  categories->setSelected(new_folder, true);
}

QListViewItem* AssetManager::OpenFolder(const QString& folder) {
  // this will always be the root item
  QListViewItem* item = categories->firstChild();

  QStringList list = QStringList::split('/', folder);

  for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
    item = item->firstChild();
    if (item == 0)
      return NULL;
    while (item->text(0) != *it) {
      item = item->nextSibling();
      if (item == 0)
        return NULL;
    }
    item->setOpen(true);
  }

  categories->setSelected(item, true);

  return item;
}

gstAssetFolder AssetManager::GetSelectedFolder() const {
  AssetFolder* asset_folder =
      dynamic_cast<AssetFolder*>(categories->selectedItem());
  if (asset_folder)
    return asset_folder->getFolder();

  return gstAssetFolder(QString::null);
}

void AssetManager::selectFolder() {
  gstAssetFolder folder = GetSelectedFolder();
  if (!folder.isValid())
    return;

  locationLineEdit->setText(AssetRoot() + "/" + folder.relativePath());

  if (assetTabWidget->currentPageIndex() == 0) {
    UpdateTableView(folder);
  } else {
    UpdateIconView(folder);
  }
}

void AssetManager::UpdateTableItem(int row, gstAssetHandle handle,
                                   Asset asset) {
  // Only set the AssetTableItem if it doesn't exist yet (new items)
  // If we're doing an assetsChanged update, the AssetTableItem can stay
  // the same.
  QTableItem *prev = assetTableView->item(row, 0);
  if (!prev) {
    assetTableView->setItem(row, 0,
                            new AssetTableItem(assetTableView, handle));
  }

  // now set teh rest of the columns
  int col = 1;
  std::string category = asset->PrettySubtype();
  if (category == kMercatorProductSubtype) {
    category = kResourceSubtype;
  }
  assetTableView->setText(row, col++, category);

  {
    std::string providerstr;
    if ((asset->subtype == kProductSubtype) &&
        ((asset->type == AssetDefs::Imagery) ||
         (asset->type == AssetDefs::Terrain))) {
      RasterProductAsset prod = asset;
      providerstr = GetProviderById(prod->config.provider_id_);
    } else if ((asset->subtype == kMercatorProductSubtype) &&
               (asset->type == AssetDefs::Imagery)) {
      MercatorRasterProductAsset prod = asset;
      providerstr = GetProviderById(prod->config.provider_id_);
    } else if ((asset->subtype == kProductSubtype) &&
               (asset->type == AssetDefs::Vector)) {
      VectorProductAsset prod = asset;
      providerstr = GetProviderById(prod->config.provider_id_);
    } else {
      providerstr = asset->meta.GetValue("provider");
    }
    assetTableView->setText(row, col++, providerstr);
  }

  AssetVersion version(asset->CurrVersionRef());
  if (version) {
    assetTableView->setText(row, col++,
                            version->meta.GetValue("createdtime"));
    assetTableView->setItem(row, col++,
                            new AssetStateItem(assetTableView,
                                               version->PrettyState()));
  } else {
    assetTableView->setText(row, col++, "None");
    assetTableView->setItem(row, col++,
                            new AssetStateItem(assetTableView, "None"));
  }
  assetTableView->adjustRow(row);
}

void AssetManager::TrackChangesInTableView(
    const gstAssetFolder &folder, const std::set<std::string> &changed) {
  // process each changed assetRef
  for (std::set<std::string>::const_iterator ref = changed.begin();
       ref != changed.end(); ++ref) {
    QString baseRef = khBasename(*ref);
    bool found = false;

    // try to find a match in the existing items
    for (int row = 0; row < assetTableView->numRows(); ++row) {
      AssetTableItem* item = (AssetTableItem*)assetTableView->item(row, 0);
      gstAssetHandle handle = item->GetAssetHandle();
      if (handle->getName() == baseRef) {
        found = true;

        // Will refetch record from disk if it has changed
        // NOTE: Using NFS on linux can cause a race here. The system
        // manager writes the record and then sends me a message. I look at
        // the file on disk but it hasn;t changed yet. :-(
        Asset asset = handle->getAsset();

        if (!IsAssetVisible(asset)) {
          assetTableView->removeRow(row);
        } else {
          UpdateTableItem(row, handle, asset);
        }
        break;
      }
    }

    if (!found) {
      // no match found. This is a new one
      gstAssetHandle handle = gstAssetHandleImpl::Create(folder, baseRef);
      Asset asset = handle->getAsset();

      if (!IsAssetVisible(asset))
        continue;

      int numRows = assetTableView->numRows();
      assetTableView->setNumRows(numRows + 1);
      UpdateTableItem(numRows, handle, asset);
    }
  }

  // resort in case we just changed a sort key
  // This mostly does the right thing by preserving scroll position, etc
  // But it can end up changing the selection
  assetTableView->sortColumn
    (assetTableView->horizontalHeader()->sortIndicatorSection(),
     assetTableView->horizontalHeader()->sortIndicatorOrder() == Ascending,
     true /* whole rows */);
}

void AssetManager::UpdateTableView(const gstAssetFolder& folder) {
  // reset table
  assetTableView->setNumCols(0);
  assetTableView->setNumRows(0);

  if (!folder.isValid())
    return;

  assetTableView->setNumCols(5);
  QHeader* header = assetTableView->horizontalHeader();
  int col = 0;
  header->setLabel(col++, tr("Asset Name"));
  header->setLabel(col++, tr("Category"));
  header->setLabel(col++, tr("Provider"));
  header->setLabel(col++, tr("Current Version"));
  header->setLabel(col++, tr("Current State"));

  // put directories here
  // std::vector<gstAssetGroups>

  std::vector<gstAssetHandle> items = folder.getAssetHandles();

  if (items.size() == 0)
    return;

  assetTableView->setUpdatesEnabled(false);

  int rowcount = 0;
  for (uint row = 0; row < items.size(); ++row) {
    gstAssetHandle handle = items[row];
    Asset asset = handle->getAsset();

    if (!IsAssetVisible(asset))
      continue;

    assetTableView->setNumRows(rowcount + 1);
    UpdateTableItem(rowcount, handle, asset);
    ++rowcount;
  }

  assetTableView->sortColumn(1, true, true);
  assetTableView->horizontalHeader()->setSortIndicator(1, true);

  assetTableView->setUpdatesEnabled(true);

  for (int c = 0; c < assetTableView->numCols(); ++c)
    assetTableView->adjustColumn(c);

  repaint();
}

void AssetManager::filterType(int menuid) {
  if (filter_type_ != menuid) {
    filter_type_ = menuid;
    selectFolder();
  }
}

void AssetManager::filterSubType(int menuid) {
  if (filter_subtype_ != menuid) {
    filter_subtype_ = menuid;
    selectFolder();
  }
}

bool AssetManager::IsAssetVisible(const Asset& asset) const {
  // skip invalid assets
  if (asset->type == AssetDefs::Invalid)
    return false;

  std::string category = asset->PrettySubtype();
  if (category == kMercatorProductSubtype) {
    category = kResourceSubtype;
  }
  // check filters
  if (!MatchFilter(asset->type, category))
    return false;

  // if the "show hidden" check is off, skip any asset that
  // has the "hidden" meta field set
  if (!showHiddenCheck->isChecked()) {
    bool hidden = asset->meta.GetAs("hidden", false);
    if (hidden)
      return false;
  }

  return true;
}

bool AssetManager::MatchFilter(AssetDefs::Type type,
                               const std::string& subtype) const {
  if (GetFusionProductType() == FusionLT) {
    if (type == AssetDefs::Imagery || type == AssetDefs::Terrain)
      return false;
  }

  // quick exit if not filtering
  if (filter_type_ == 0 && filter_subtype_ == 0)
    return true;

  const std::string* subtype_ptr = &subtype;
  // special-case the new maps database
  if (type == AssetDefs::Database && (subtype == kMapDatabaseSubtype ||
                                      subtype == kMercatorMapDatabaseSubtype)) {
    type = AssetDefs::Map;
    subtype_ptr = &kDatabaseSubtype;
  }
  if (type == AssetDefs::Imagery) {
    if (subtype == kMercatorProductSubtype) {
      subtype_ptr = &kProductSubtype;
    } else if (subtype == kMercatorProjectSubtype) {
      subtype_ptr = &kProjectSubtype;
    }
  }

  // check major type
  if (filter_type_ != 0 && TypeSet[filter_type_] != type)
    return false;

  // now check minor type (subtype)
  if (filter_subtype_ != 0 && SubTypeSet[filter_subtype_] != *subtype_ptr)
    return false;

  return true;
}

void AssetManager::UpdateIconView(const gstAssetFolder& folder) {
  assetIconView->clear();

  if (!folder.isValid())
    return;

  std::vector<gstAssetHandle> items = folder.getAssetHandles();

  if (items.size() == 0)
    return;

  for (uint id = 0; id < items.size(); ++id) {
    gstAssetHandle item = items[id];
    Asset asset = item->getAsset();

    if (IsAssetVisible(asset))
      new AssetIcon(assetIconView, item, icon_grid_);
  }

  resetIconView(icon_grid_);
}

void AssetManager::resetIconView(int grid_size) {
  assetIconView->setGridX(grid_size + 20);
  assetIconView->setGridY(grid_size + 20);
  assetIconView->arrangeItemsInGrid();
}

void AssetManager::resizeIconView(int sz) {
  if (icon_grid_ != sz) {
    icon_grid_ = sz;

    for (QIconViewItem* item = assetIconView->firstItem();
         item; item = item->nextItem()) {
      static_cast<AssetIcon*>(item)->resize(sz);
    }
    resetIconView(sz);
  }
}

QColorGroup AssetManager::GetStateDrawStyle(
    const std::string& txt, QPainter* p, const QColorGroup& cg) {
  bool bold = false;
  QColor clr = cg.text();

  if (txt == "Canceled" || txt == "Failed") {
    bold = true;
    clr = red;
  } else if (txt == "Blocked") {
    bold = true;
    clr = QColor(255, 162, 0);  // orange
  } else if (txt == "Succeeded") {
    bold = true;
  } else if (txt == "Queued" || txt == "InProgress" || txt == "Waiting") {
    bold = true;
    clr = QColor(0, 170, 0);    // green
  }

  QFont f = p->font();
  f.setBold(bold);
  p->setFont(f);

  QColorGroup ngrp = cg;
  ngrp.setColor(QColorGroup::Text, clr);

  return ngrp;
}

redpajama_set_name: RedPajamaGithub


Recipients with phones capable of receiving text messages will be able to respond with their confirmation or cancellation via text. Phones that can only receive calls will receive a voice message generated with state of the art text to speech synthesis software, to which the recipient can respond using the keypad.
Telio Reminders features a dynamic interface that lets you send automated messages (SMS or phone) and reminders to an individual or group of people. Messages can include content like the patient's or doctor's name, as well as appointment time and location. You can also customize how you respond to patients, whether they reply or not.
Telio Reminders will automatically resend reminder messages to patients that have not responded within a customizable time-frame, and content of follow-up reminders can be different than the original reminder. Re-sending reminders closer to the day of appointment increases response rates and appointment fulfilment.
The software automatically determines if a phone is capable of receiving SMS messages. Voice messages are generated using industry leading text to speech synthesis software.
Broadcast custom messages to your clients at any time.
Followup messages to unresponsive recipients increases response rates.
Your account includes a free, unique phone number for your business with the ability to forward incoming calls and messages.
Automatic, customizable reporting helps you stay on top of trends and act accordingly as necessary.
We will get you a new, unique phone number that will be used to send text reminders. Any incoming calls to this number will be forwarded to your office. All voice reminders will be routed through your office numbers.
Quickly lookup patient history, including past appointment and interaction history.
Quickly respond to patients with text messages through the Telio interface. You can even send a clickable link with directions to your office!
Daily, weekly, and ad hoc reports are send via email to an unlimited number of recipients. The configurable alerts can be sent when a particular event occurs such as when a patient confirms, cancels, or changes their appointment status. The daily and weekly reports include the status of upcoming appointments and help you identify trends in patient behavior.
Send broadcast messages to patients by creating your message and selecting recipients by their appointment date. It's unfortunate, but occassionally appointments need to be cancelled due to an emergency. Telio broadcast messaging allows you to quickly alert groups of people without individually contacting them.
Stay up to date about major product updates and new product releases.