<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_disabled_ui.h"

#include <string>

#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/global_error.h"
#include "chrome/browser/ui/global_error_service.h"
#include "chrome/browser/ui/global_error_service_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

static base::LazyInstance<
    std::bitset<IDC_EXTENSION_DISABLED_LAST -
                IDC_EXTENSION_DISABLED_FIRST + 1> >
    menu_command_ids = LAZY_INSTANCE_INITIALIZER;

// Get an available menu ID.
int GetMenuCommandID() {
  int id;
  for (id = IDC_EXTENSION_DISABLED_FIRST;
       id <= IDC_EXTENSION_DISABLED_LAST; ++id) {
    if (!menu_command_ids.Get()[id - IDC_EXTENSION_DISABLED_FIRST]) {
      menu_command_ids.Get().set(id - IDC_EXTENSION_DISABLED_FIRST);
      return id;
    }
  }
  // This should not happen.
  DCHECK(id <= IDC_EXTENSION_DISABLED_LAST) <<
      "No available menu command IDs for ExtensionDisabledGlobalError";
  return IDC_EXTENSION_DISABLED_LAST;
}

// Make a menu ID available when it is no longer used.
void ReleaseMenuCommandID(int id) {
  menu_command_ids.Get().reset(id - IDC_EXTENSION_DISABLED_FIRST);
}

}  // namespace

// ExtensionDisabledDialogDelegate --------------------------------------------

class ExtensionDisabledDialogDelegate
    : public ExtensionInstallUI::Delegate,
      public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> {
 public:
  ExtensionDisabledDialogDelegate(Profile* profile,
                                  ExtensionService* service,
                                  const Extension* extension);

 private:
  friend class base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate>;

  virtual ~ExtensionDisabledDialogDelegate();

  // ExtensionInstallUI::Delegate:
  virtual void InstallUIProceed() OVERRIDE;
  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;

  // The UI for showing the install dialog when enabling.
  scoped_ptr<ExtensionInstallUI> install_ui_;

  ExtensionService* service_;
  const Extension* extension_;
};

ExtensionDisabledDialogDelegate::ExtensionDisabledDialogDelegate(
    Profile* profile,
    ExtensionService* service,
    const Extension* extension)
    : service_(service), extension_(extension) {
  AddRef();  // Balanced in Proceed or Abort.

  install_ui_.reset(new ExtensionInstallUI(profile));
  install_ui_->ConfirmReEnable(this, extension_);
}

ExtensionDisabledDialogDelegate::~ExtensionDisabledDialogDelegate() {
}

void ExtensionDisabledDialogDelegate::InstallUIProceed() {
  service_->GrantPermissionsAndEnableExtension(extension_);
  Release();
}

void ExtensionDisabledDialogDelegate::InstallUIAbort(bool user_initiated) {
  std::string histogram_name = user_initiated ?
      "Extensions.Permissions_ReEnableCancel" :
      "Extensions.Permissions_ReEnableAbort";
  ExtensionService::RecordPermissionMessagesHistogram(
      extension_, histogram_name.c_str());

  // Do nothing. The extension will remain disabled.
  Release();
}

// ExtensionDisabledGlobalError -----------------------------------------------

class ExtensionDisabledGlobalError : public GlobalError,
                                     public content::NotificationObserver,
                                     public ExtensionUninstallDialog::Delegate {
 public:
  ExtensionDisabledGlobalError(ExtensionService* service,
                               const Extension* extension);
  virtual ~ExtensionDisabledGlobalError();

  // GlobalError implementation.
  virtual bool HasBadge() OVERRIDE;
  virtual bool HasMenuItem() OVERRIDE;
  virtual int MenuItemCommandID() OVERRIDE;
  virtual string16 MenuItemLabel() OVERRIDE;
  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
  virtual bool HasBubbleView() OVERRIDE;
  virtual string16 GetBubbleViewTitle() OVERRIDE;
  virtual string16 GetBubbleViewMessage() OVERRIDE;
  virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
  virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
  virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
  virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
  virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;

  // ExtensionUninstallDialog::Delegate implementation.
  virtual void ExtensionUninstallAccepted() OVERRIDE;
  virtual void ExtensionUninstallCanceled() OVERRIDE;

  // content::NotificationObserver implementation.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

 private:
  ExtensionService* service_;
  const Extension* extension_;

  // How the user responded to the error; used for metrics.
  enum UserResponse {
    IGNORED,
    REENABLE,
    UNINSTALL,
    EXTENSION_DISABLED_UI_BUCKET_BOUNDARY
  };
  UserResponse user_response_;

  scoped_ptr<ExtensionUninstallDialog> uninstall_dialog_;

  // Menu command ID assigned for this extension's error.
  int menu_command_id_;

  content::NotificationRegistrar registrar_;
};

// TODO(yoz): create error at startup for disabled extensions.
ExtensionDisabledGlobalError::ExtensionDisabledGlobalError(
    ExtensionService* service,
    const Extension* extension)
    : service_(service),
      extension_(extension),
      user_response_(IGNORED),
      menu_command_id_(GetMenuCommandID()) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
                 content::Source<Profile>(service->profile()));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
                 content::Source<Profile>(service->profile()));
}

ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() {
  ReleaseMenuCommandID(menu_command_id_);
  HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponse",
                        user_response_, EXTENSION_DISABLED_UI_BUCKET_BOUNDARY);
}

bool ExtensionDisabledGlobalError::HasBadge() {
  return true;
}

bool ExtensionDisabledGlobalError::HasMenuItem() {
  return true;
}

int ExtensionDisabledGlobalError::MenuItemCommandID() {
  return menu_command_id_;
}

string16 ExtensionDisabledGlobalError::MenuItemLabel() {
  return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
                                    UTF8ToUTF16(extension_->name()));
}

void ExtensionDisabledGlobalError::ExecuteMenuItem(Browser* browser) {
  ShowBubbleView(browser);
}

bool ExtensionDisabledGlobalError::HasBubbleView() {
   return true;
}

string16 ExtensionDisabledGlobalError::GetBubbleViewTitle() {
  return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
                                    UTF8ToUTF16(extension_->name()));
}

string16 ExtensionDisabledGlobalError::GetBubbleViewMessage() {
  return l10n_util::GetStringFUTF16(extension_->is_app() ?
      IDS_APP_DISABLED_ERROR_LABEL : IDS_EXTENSION_DISABLED_ERROR_LABEL,
      UTF8ToUTF16(extension_->name()));
}

string16 ExtensionDisabledGlobalError::GetBubbleViewAcceptButtonLabel() {
  return l10n_util::GetStringUTF16(
      IDS_EXTENSION_DISABLED_ERROR_ENABLE_BUTTON);
}

string16 ExtensionDisabledGlobalError::GetBubbleViewCancelButtonLabel() {
  return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL);
}

void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) {
}

void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed(
    Browser* browser) {
  new ExtensionDisabledDialogDelegate(service_->profile(), service_,
                                      extension_);
}

void ExtensionDisabledGlobalError::BubbleViewCancelButtonPressed(
    Browser* browser) {
#if !defined(OS_ANDROID)
  uninstall_dialog_.reset(
      ExtensionUninstallDialog::Create(service_->profile(), this));
  // Delay showing the uninstall dialog, so that this function returns
  // immediately, to close the bubble properly. See crbug.com/121544.
  MessageLoop::current()->PostTask(FROM_HERE,
      base::Bind(&ExtensionUninstallDialog::ConfirmUninstall,
                 uninstall_dialog_->AsWeakPtr(), extension_));
#endif  // !defined(OS_ANDROID)
}

void ExtensionDisabledGlobalError::ExtensionUninstallAccepted() {
  service_->UninstallExtension(extension_->id(), false, NULL);
}

void ExtensionDisabledGlobalError::ExtensionUninstallCanceled() {
  // Nothing happens, and the error is still there.
}

void ExtensionDisabledGlobalError::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  const Extension* extension = NULL;
  // The error is invalidated if the extension has been reloaded
  // or unloaded.
  if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
    extension = content::Details<const Extension>(details).ptr();
  } else {
    DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type);
    UnloadedExtensionInfo* info =
        content::Details<UnloadedExtensionInfo>(details).ptr();
    extension = info->extension;
  }
  if (extension == extension_) {
    GlobalErrorServiceFactory::GetForProfile(service_->profile())->
        RemoveGlobalError(this);

    if (type == chrome::NOTIFICATION_EXTENSION_LOADED)
      user_response_ = REENABLE;
    else if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED)
      user_response_ = UNINSTALL;
    delete this;
  }
}

// Globals --------------------------------------------------------------------

namespace extensions {

void AddExtensionDisabledError(ExtensionService* service,
                               const Extension* extension) {
  GlobalErrorServiceFactory::GetForProfile(service->profile())->
      AddGlobalError(new ExtensionDisabledGlobalError(service, extension));
}

void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile,
                                 const Extension* extension) {
  // This object manages its own lifetime.
  new ExtensionDisabledDialogDelegate(profile, service, extension);
}

}  // namespace extensions
<commit_msg>Hack: add an ellipsis to Re-enable button for extension permissions increase.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_disabled_ui.h"

#include <string>

#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/global_error.h"
#include "chrome/browser/ui/global_error_service.h"
#include "chrome/browser/ui/global_error_service_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

static base::LazyInstance<
    std::bitset<IDC_EXTENSION_DISABLED_LAST -
                IDC_EXTENSION_DISABLED_FIRST + 1> >
    menu_command_ids = LAZY_INSTANCE_INITIALIZER;

// Get an available menu ID.
int GetMenuCommandID() {
  int id;
  for (id = IDC_EXTENSION_DISABLED_FIRST;
       id <= IDC_EXTENSION_DISABLED_LAST; ++id) {
    if (!menu_command_ids.Get()[id - IDC_EXTENSION_DISABLED_FIRST]) {
      menu_command_ids.Get().set(id - IDC_EXTENSION_DISABLED_FIRST);
      return id;
    }
  }
  // This should not happen.
  DCHECK(id <= IDC_EXTENSION_DISABLED_LAST) <<
      "No available menu command IDs for ExtensionDisabledGlobalError";
  return IDC_EXTENSION_DISABLED_LAST;
}

// Make a menu ID available when it is no longer used.
void ReleaseMenuCommandID(int id) {
  menu_command_ids.Get().reset(id - IDC_EXTENSION_DISABLED_FIRST);
}

}  // namespace

// ExtensionDisabledDialogDelegate --------------------------------------------

class ExtensionDisabledDialogDelegate
    : public ExtensionInstallUI::Delegate,
      public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> {
 public:
  ExtensionDisabledDialogDelegate(Profile* profile,
                                  ExtensionService* service,
                                  const Extension* extension);

 private:
  friend class base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate>;

  virtual ~ExtensionDisabledDialogDelegate();

  // ExtensionInstallUI::Delegate:
  virtual void InstallUIProceed() OVERRIDE;
  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;

  // The UI for showing the install dialog when enabling.
  scoped_ptr<ExtensionInstallUI> install_ui_;

  ExtensionService* service_;
  const Extension* extension_;
};

ExtensionDisabledDialogDelegate::ExtensionDisabledDialogDelegate(
    Profile* profile,
    ExtensionService* service,
    const Extension* extension)
    : service_(service), extension_(extension) {
  AddRef();  // Balanced in Proceed or Abort.

  install_ui_.reset(new ExtensionInstallUI(profile));
  install_ui_->ConfirmReEnable(this, extension_);
}

ExtensionDisabledDialogDelegate::~ExtensionDisabledDialogDelegate() {
}

void ExtensionDisabledDialogDelegate::InstallUIProceed() {
  service_->GrantPermissionsAndEnableExtension(extension_);
  Release();
}

void ExtensionDisabledDialogDelegate::InstallUIAbort(bool user_initiated) {
  std::string histogram_name = user_initiated ?
      "Extensions.Permissions_ReEnableCancel" :
      "Extensions.Permissions_ReEnableAbort";
  ExtensionService::RecordPermissionMessagesHistogram(
      extension_, histogram_name.c_str());

  // Do nothing. The extension will remain disabled.
  Release();
}

// ExtensionDisabledGlobalError -----------------------------------------------

class ExtensionDisabledGlobalError : public GlobalError,
                                     public content::NotificationObserver,
                                     public ExtensionUninstallDialog::Delegate {
 public:
  ExtensionDisabledGlobalError(ExtensionService* service,
                               const Extension* extension);
  virtual ~ExtensionDisabledGlobalError();

  // GlobalError implementation.
  virtual bool HasBadge() OVERRIDE;
  virtual bool HasMenuItem() OVERRIDE;
  virtual int MenuItemCommandID() OVERRIDE;
  virtual string16 MenuItemLabel() OVERRIDE;
  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
  virtual bool HasBubbleView() OVERRIDE;
  virtual string16 GetBubbleViewTitle() OVERRIDE;
  virtual string16 GetBubbleViewMessage() OVERRIDE;
  virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
  virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
  virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
  virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
  virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;

  // ExtensionUninstallDialog::Delegate implementation.
  virtual void ExtensionUninstallAccepted() OVERRIDE;
  virtual void ExtensionUninstallCanceled() OVERRIDE;

  // content::NotificationObserver implementation.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

 private:
  ExtensionService* service_;
  const Extension* extension_;

  // How the user responded to the error; used for metrics.
  enum UserResponse {
    IGNORED,
    REENABLE,
    UNINSTALL,
    EXTENSION_DISABLED_UI_BUCKET_BOUNDARY
  };
  UserResponse user_response_;

  scoped_ptr<ExtensionUninstallDialog> uninstall_dialog_;

  // Menu command ID assigned for this extension's error.
  int menu_command_id_;

  content::NotificationRegistrar registrar_;
};

// TODO(yoz): create error at startup for disabled extensions.
ExtensionDisabledGlobalError::ExtensionDisabledGlobalError(
    ExtensionService* service,
    const Extension* extension)
    : service_(service),
      extension_(extension),
      user_response_(IGNORED),
      menu_command_id_(GetMenuCommandID()) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
                 content::Source<Profile>(service->profile()));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
                 content::Source<Profile>(service->profile()));
}

ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() {
  ReleaseMenuCommandID(menu_command_id_);
  HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponse",
                        user_response_, EXTENSION_DISABLED_UI_BUCKET_BOUNDARY);
}

bool ExtensionDisabledGlobalError::HasBadge() {
  return true;
}

bool ExtensionDisabledGlobalError::HasMenuItem() {
  return true;
}

int ExtensionDisabledGlobalError::MenuItemCommandID() {
  return menu_command_id_;
}

string16 ExtensionDisabledGlobalError::MenuItemLabel() {
  return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
                                    UTF8ToUTF16(extension_->name()));
}

void ExtensionDisabledGlobalError::ExecuteMenuItem(Browser* browser) {
  ShowBubbleView(browser);
}

bool ExtensionDisabledGlobalError::HasBubbleView() {
   return true;
}

string16 ExtensionDisabledGlobalError::GetBubbleViewTitle() {
  return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
                                    UTF8ToUTF16(extension_->name()));
}

string16 ExtensionDisabledGlobalError::GetBubbleViewMessage() {
  return l10n_util::GetStringFUTF16(extension_->is_app() ?
      IDS_APP_DISABLED_ERROR_LABEL : IDS_EXTENSION_DISABLED_ERROR_LABEL,
      UTF8ToUTF16(extension_->name()));
}

string16 ExtensionDisabledGlobalError::GetBubbleViewAcceptButtonLabel() {
  if (!base::i18n::IsRTL()) {
    return l10n_util::GetStringUTF16(
        IDS_EXTENSION_DISABLED_ERROR_ENABLE_BUTTON) + UTF8ToUTF16("...");
  } else {
    return UTF8ToUTF16("...") + l10n_util::GetStringUTF16(
        IDS_EXTENSION_DISABLED_ERROR_ENABLE_BUTTON);
  }
}

string16 ExtensionDisabledGlobalError::GetBubbleViewCancelButtonLabel() {
  return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL);
}

void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) {
}

void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed(
    Browser* browser) {
  new ExtensionDisabledDialogDelegate(service_->profile(), service_,
                                      extension_);
}

void ExtensionDisabledGlobalError::BubbleViewCancelButtonPressed(
    Browser* browser) {
#if !defined(OS_ANDROID)
  uninstall_dialog_.reset(
      ExtensionUninstallDialog::Create(service_->profile(), this));
  // Delay showing the uninstall dialog, so that this function returns
  // immediately, to close the bubble properly. See crbug.com/121544.
  MessageLoop::current()->PostTask(FROM_HERE,
      base::Bind(&ExtensionUninstallDialog::ConfirmUninstall,
                 uninstall_dialog_->AsWeakPtr(), extension_));
#endif  // !defined(OS_ANDROID)
}

void ExtensionDisabledGlobalError::ExtensionUninstallAccepted() {
  service_->UninstallExtension(extension_->id(), false, NULL);
}

void ExtensionDisabledGlobalError::ExtensionUninstallCanceled() {
  // Nothing happens, and the error is still there.
}

void ExtensionDisabledGlobalError::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  const Extension* extension = NULL;
  // The error is invalidated if the extension has been reloaded
  // or unloaded.
  if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
    extension = content::Details<const Extension>(details).ptr();
  } else {
    DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type);
    UnloadedExtensionInfo* info =
        content::Details<UnloadedExtensionInfo>(details).ptr();
    extension = info->extension;
  }
  if (extension == extension_) {
    GlobalErrorServiceFactory::GetForProfile(service_->profile())->
        RemoveGlobalError(this);

    if (type == chrome::NOTIFICATION_EXTENSION_LOADED)
      user_response_ = REENABLE;
    else if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED)
      user_response_ = UNINSTALL;
    delete this;
  }
}

// Globals --------------------------------------------------------------------

namespace extensions {

void AddExtensionDisabledError(ExtensionService* service,
                               const Extension* extension) {
  GlobalErrorServiceFactory::GetForProfile(service->profile())->
      AddGlobalError(new ExtensionDisabledGlobalError(service, extension));
}

void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile,
                                 const Extension* extension) {
  // This object manages its own lifetime.
  new ExtensionDisabledDialogDelegate(profile, service, extension);
}

}  // namespace extensions
<|endoftext|>


<commit_before><commit_msg>Fix linux unittest that I broke.<commit_after><|endoftext|>


<commit_before>/*
    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qobject.h>
#include <qlabel.h>
#include <qlayout.h>

#include <dcopclient.h>
#include <dcopref.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kurllabel.h>
#include <kstandarddirs.h>

#include <knotes/resourcenotes.h>
#include <knotes/resourcemanager.h>

#include "core.h"
#include "plugin.h"

#include "summarywidget.h"

SummaryWidget::SummaryWidget( Kontact::Plugin *plugin,
                              QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ), mLayout( 0 ), mMainLayout( 0 ),
    mPlugin( plugin )
{
  mMainLayout = new QVBoxLayout( this, 3, 3 );

  mCalendar = new KCal::CalendarLocal();
  KNotesResourceManager *manager = new KNotesResourceManager();
  QObject::connect( manager, SIGNAL( sigRegisteredNote( KCal::Journal* ) ),
                    this, SLOT( addNote( KCal::Journal* ) ) );
  QObject::connect( manager, SIGNAL( sigDeregisteredNote( KCal::Journal* ) ),
                    this, SLOT( removeNote( KCal::Journal* ) ) );
  manager->load();

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kontact_notes", KIcon::Desktop, KIcon::SizeMedium );
  QWidget* heading = createHeader( this, icon, i18n( "Notes" ) );

  mMainLayout->addWidget(heading);
  mLayout = new QVBoxLayout( mMainLayout );

  updateView();
}

void SummaryWidget::updateView()
{
  mNotes = mCalendar->journals();

  delete mLayout;
  mLayout = new QVBoxLayout( mMainLayout );

  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  KCal::Journal::List::Iterator it;
  for (it = mNotes.begin(); it != mNotes.end(); ++it) {
    KURLLabel *urlLabel = new KURLLabel(
        (*it)->uid(), (*it)->summary(), this );
    urlLabel->setTextFormat(RichText);
    urlLabel->show();
    mLayout->addWidget( urlLabel );
    mLabels.append( urlLabel );

    connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
        this, SLOT( urlClicked( const QString& ) ) );
  }
}

void SummaryWidget::urlClicked( const QString &/*uid*/ )
{
  if ( !mPlugin->isRunningStandalone() )
    mPlugin->core()->selectPlugin( mPlugin );
  else
    mPlugin->bringToForeground();
}

void SummaryWidget::addNote( KCal::Journal *j )
{
  mCalendar->addJournal( j );
  updateView();
}

void SummaryWidget::removeNote( KCal::Journal *j )
{
  mCalendar->deleteJournal( j );
  updateView();
}

#include "summarywidget.moc"
<commit_msg>Fix wrong constructor chain order, and mMainLayout is initialized as the first line anyway.<commit_after>/*
    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qobject.h>
#include <qlabel.h>
#include <qlayout.h>

#include <dcopclient.h>
#include <dcopref.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kurllabel.h>
#include <kstandarddirs.h>

#include <knotes/resourcenotes.h>
#include <knotes/resourcemanager.h>

#include "core.h"
#include "plugin.h"

#include "summarywidget.h"

SummaryWidget::SummaryWidget( Kontact::Plugin *plugin,
                              QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ), mLayout( 0 ), mPlugin( plugin )
{
  mMainLayout = new QVBoxLayout( this, 3, 3 );

  mCalendar = new KCal::CalendarLocal();
  KNotesResourceManager *manager = new KNotesResourceManager();
  QObject::connect( manager, SIGNAL( sigRegisteredNote( KCal::Journal* ) ),
                    this, SLOT( addNote( KCal::Journal* ) ) );
  QObject::connect( manager, SIGNAL( sigDeregisteredNote( KCal::Journal* ) ),
                    this, SLOT( removeNote( KCal::Journal* ) ) );
  manager->load();

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kontact_notes", KIcon::Desktop, KIcon::SizeMedium );
  QWidget* heading = createHeader( this, icon, i18n( "Notes" ) );

  mMainLayout->addWidget(heading);
  mLayout = new QVBoxLayout( mMainLayout );

  updateView();
}

void SummaryWidget::updateView()
{
  mNotes = mCalendar->journals();

  delete mLayout;
  mLayout = new QVBoxLayout( mMainLayout );

  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  KCal::Journal::List::Iterator it;
  for (it = mNotes.begin(); it != mNotes.end(); ++it) {
    KURLLabel *urlLabel = new KURLLabel(
        (*it)->uid(), (*it)->summary(), this );
    urlLabel->setTextFormat(RichText);
    urlLabel->show();
    mLayout->addWidget( urlLabel );
    mLabels.append( urlLabel );

    connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
        this, SLOT( urlClicked( const QString& ) ) );
  }
}

void SummaryWidget::urlClicked( const QString &/*uid*/ )
{
  if ( !mPlugin->isRunningStandalone() )
    mPlugin->core()->selectPlugin( mPlugin );
  else
    mPlugin->bringToForeground();
}

void SummaryWidget::addNote( KCal::Journal *j )
{
  mCalendar->addJournal( j );
  updateView();
}

void SummaryWidget::removeNote( KCal::Journal *j )
{
  mCalendar->deleteJournal( j );
  updateView();
}

#include "summarywidget.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS HEADER
#include <dali/internal/accessibility/bridge/bridge-base.h>

// EXTERNAL INCLUDES
#include <atomic>
#include <cstdlib>
#include <memory>

// INTERNAL INCLUDES
#include <dali/public-api/adaptor-framework/timer.h>

using namespace Dali::Accessibility;

static Dali::Timer tickTimer;

BridgeBase::~BridgeBase()
{
}

BridgeBase::BridgeBase()
{
}

void BridgeBase::addFilteredEvent( FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor )
{
  if( delay < 0 )
  {
    delay = 0;
  }

  auto it = filteredEvents.insert({ { kind, obj }, { static_cast<unsigned int>(delay * 10), {} } });
  if (it.second)
  {
    functor();
  }
  else
  {
    it.first->second.second = std::move(functor);
  }

  if (!tickTimer)
  {
    tickTimer = Dali::Timer::New(100);
    tickTimer.TickSignal().Connect(this, &BridgeBase::tickFilteredEvents);
  }
}

bool BridgeBase::tickFilteredEvents()
{
  for(auto it = filteredEvents.begin(); it != filteredEvents.end(); )
  {
    if (it->second.first)
    {
      --it->second.first;
    }
    else
    {
      if (it->second.second)
      {
        it->second.second();
        it->second.second = {};
      }
      else
      {
        it = filteredEvents.erase(it);
        continue;
      }
    }
    ++it;
  }
  return !filteredEvents.empty();
}

BridgeBase::ForceUpResult BridgeBase::ForceUp()
{
  if( Bridge::ForceUp() == ForceUpResult::ALREADY_UP )
  {
    return ForceUpResult::ALREADY_UP;
  }
  auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
  auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call();

  if( !addr )
  {
    throw std::domain_error{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
  }

  con = DBusWrapper::Installed()->eldbus_address_connection_get_impl( std::get< 0 >( addr ) );
  data->busName = DBus::getConnectionName( con );
  dbusServer = { con };

  {
    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"};
    AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems );
    dbusServer.addInterface( "/org/a11y/atspi/cache", desc );
  }
  {
    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"};
    AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet );
    dbusServer.addInterface( AtspiPath, desc );
  }

  return ForceUpResult::JUST_STARTED;
}

void BridgeBase::ForceDown()
{
  Bridge::ForceDown();
  dbusServer = {};
  con = {};
}

const std::string& BridgeBase::GetBusName() const
{
  static std::string empty;
  return data ? data->busName : empty;
}

Accessible* BridgeBase::FindByPath( const std::string& name ) const
{
  try
  {
    return Find( name );
  }
  catch( std::domain_error& )
  {
    return nullptr;
  }
}

void BridgeBase::AddPopup( Accessible* obj )
{
  if( std::find( popups.begin(), popups.end(), obj ) != popups.end() )
  {
    return;
  }
  popups.push_back( obj );
  if (IsUp())
  {
    obj->Emit( WindowEvent::ACTIVATE, 0 );
  }
}

void BridgeBase::RemovePopup( Accessible* obj )
{
  auto it = std::find( popups.begin(), popups.end(), obj );
  if( it == popups.end() )
  {
    return;
  }
  popups.erase( it );
  if (IsUp())
  {
    obj->Emit( WindowEvent::DEACTIVATE, 0 );
    if( popups.empty() )
    {
      application.children.back()->Emit( WindowEvent::ACTIVATE, 0 );
    }
    else
    {
      popups.back()->Emit( WindowEvent::ACTIVATE, 0 );
    }
  }
}

void BridgeBase::AddTopLevelWindow( Accessible* root )
{
  application.children.push_back( root );
  SetIsOnRootLevel( root );
}

void BridgeBase::RemoveTopLevelWindow( Accessible* root )
{
  for(auto i = 0u; i < application.children.size(); ++i)
  {
    if( application.children[i] == root )
    {
      application.children.erase(application.children.begin() + i);
      break;
    }
  }
}

std::string BridgeBase::StripPrefix( const std::string& path )
{
  auto size = strlen( AtspiPath );
  return path.substr( size + 1 );
}

Accessible* BridgeBase::Find( const std::string& path ) const
{
  if( path == "root" )
  {
    return &application;
  }
  void* p;
  std::istringstream tmp{ path };
  if (! ( tmp >> p) )
  {
    throw std::domain_error{"invalid path '" + path + "'"};
  }
  auto it = data->knownObjects.find( static_cast<Accessible*>( p ) );
  if( it == data->knownObjects.end() || (*it)->GetStates()[State::DEFUNCT] )
  {
    throw std::domain_error{"unknown object '" + path + "'"};
  }
  return static_cast<Accessible*>( p );
}

Accessible* BridgeBase::Find( const Address& ptr ) const
{
  assert( ptr.GetBus() == data->busName );
  return Find( ptr.GetPath() );
}

Accessible* BridgeBase::FindSelf() const
{
  auto pth = DBus::DBusServer::getCurrentObjectPath();
  auto size = strlen( AtspiPath );
  if( pth.size() <= size )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  if( pth.substr( 0, size ) != AtspiPath )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  if( pth[size] != '/' )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  return Find( StripPrefix( pth ) );
}

void BridgeBase::IdSet( int id )
{
  this->id = id;
}

int BridgeBase::IdGet()
{
  return this->id;
}

auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > >
{
  auto root = &application;

  std::vector< CacheElementType > res;

  std::function< void(Accessible*) > proc =
    [&]( Accessible* item )
    {
      res.emplace_back( std::move( CreateCacheElement( root ) ) );
      for( auto i = 0u; i < item->GetChildCount(); ++i )
      {
        proc( item->GetChildAtIndex( i ) );
      }
    };

  return res;
}

auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType
{
  if( !item )
  {
    return {};
  }

  auto root = &application;
  auto parent = item->GetParent();

  std::vector< Address > children;
  for( auto i = 0u; i < item->GetChildCount(); ++i )
  {
    children.emplace_back( item->GetChildAtIndex( i )->GetAddress() );
  }

  return std::make_tuple(
    item->GetAddress(),
    root->GetAddress(),
    parent ? parent->GetAddress() : Address{},
    children,
    item->GetInterfaces(),
    item->GetName(),
    item->GetRole(),
    item->GetDescription(),
    item->GetStates().GetRawData()
  );
}

<commit_msg>[AT-SPI] Remove check for DEFUNCT in BridgeBase::Find<commit_after>/*
 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

// CLASS HEADER
#include <dali/internal/accessibility/bridge/bridge-base.h>

// EXTERNAL INCLUDES
#include <atomic>
#include <cstdlib>
#include <memory>

// INTERNAL INCLUDES
#include <dali/public-api/adaptor-framework/timer.h>

using namespace Dali::Accessibility;

static Dali::Timer tickTimer;

BridgeBase::~BridgeBase()
{
}

BridgeBase::BridgeBase()
{
}

void BridgeBase::addFilteredEvent( FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor )
{
  if( delay < 0 )
  {
    delay = 0;
  }

  auto it = filteredEvents.insert({ { kind, obj }, { static_cast<unsigned int>(delay * 10), {} } });
  if (it.second)
  {
    functor();
  }
  else
  {
    it.first->second.second = std::move(functor);
  }

  if (!tickTimer)
  {
    tickTimer = Dali::Timer::New(100);
    tickTimer.TickSignal().Connect(this, &BridgeBase::tickFilteredEvents);
  }
}

bool BridgeBase::tickFilteredEvents()
{
  for(auto it = filteredEvents.begin(); it != filteredEvents.end(); )
  {
    if (it->second.first)
    {
      --it->second.first;
    }
    else
    {
      if (it->second.second)
      {
        it->second.second();
        it->second.second = {};
      }
      else
      {
        it = filteredEvents.erase(it);
        continue;
      }
    }
    ++it;
  }
  return !filteredEvents.empty();
}

BridgeBase::ForceUpResult BridgeBase::ForceUp()
{
  if( Bridge::ForceUp() == ForceUpResult::ALREADY_UP )
  {
    return ForceUpResult::ALREADY_UP;
  }
  auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
  auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call();

  if( !addr )
  {
    throw std::domain_error{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
  }

  con = DBusWrapper::Installed()->eldbus_address_connection_get_impl( std::get< 0 >( addr ) );
  data->busName = DBus::getConnectionName( con );
  dbusServer = { con };

  {
    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"};
    AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems );
    dbusServer.addInterface( "/org/a11y/atspi/cache", desc );
  }
  {
    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"};
    AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet );
    dbusServer.addInterface( AtspiPath, desc );
  }

  return ForceUpResult::JUST_STARTED;
}

void BridgeBase::ForceDown()
{
  Bridge::ForceDown();
  dbusServer = {};
  con = {};
}

const std::string& BridgeBase::GetBusName() const
{
  static std::string empty;
  return data ? data->busName : empty;
}

Accessible* BridgeBase::FindByPath( const std::string& name ) const
{
  try
  {
    return Find( name );
  }
  catch( std::domain_error& )
  {
    return nullptr;
  }
}

void BridgeBase::AddPopup( Accessible* obj )
{
  if( std::find( popups.begin(), popups.end(), obj ) != popups.end() )
  {
    return;
  }
  popups.push_back( obj );
  if (IsUp())
  {
    obj->Emit( WindowEvent::ACTIVATE, 0 );
  }
}

void BridgeBase::RemovePopup( Accessible* obj )
{
  auto it = std::find( popups.begin(), popups.end(), obj );
  if( it == popups.end() )
  {
    return;
  }
  popups.erase( it );
  if (IsUp())
  {
    obj->Emit( WindowEvent::DEACTIVATE, 0 );
    if( popups.empty() )
    {
      application.children.back()->Emit( WindowEvent::ACTIVATE, 0 );
    }
    else
    {
      popups.back()->Emit( WindowEvent::ACTIVATE, 0 );
    }
  }
}

void BridgeBase::AddTopLevelWindow( Accessible* root )
{
  application.children.push_back( root );
  SetIsOnRootLevel( root );
}

void BridgeBase::RemoveTopLevelWindow( Accessible* root )
{
  for(auto i = 0u; i < application.children.size(); ++i)
  {
    if( application.children[i] == root )
    {
      application.children.erase(application.children.begin() + i);
      break;
    }
  }
}

std::string BridgeBase::StripPrefix( const std::string& path )
{
  auto size = strlen( AtspiPath );
  return path.substr( size + 1 );
}

Accessible* BridgeBase::Find( const std::string& path ) const
{
  if( path == "root" )
  {
    return &application;
  }
  void* p;
  std::istringstream tmp{ path };
  if (! ( tmp >> p) )
  {
    throw std::domain_error{"invalid path '" + path + "'"};
  }
  auto it = data->knownObjects.find( static_cast<Accessible*>( p ) );
  if( it == data->knownObjects.end() )
  {
    throw std::domain_error{"unknown object '" + path + "'"};
  }
  return static_cast<Accessible*>( p );
}

Accessible* BridgeBase::Find( const Address& ptr ) const
{
  assert( ptr.GetBus() == data->busName );
  return Find( ptr.GetPath() );
}

Accessible* BridgeBase::FindSelf() const
{
  auto pth = DBus::DBusServer::getCurrentObjectPath();
  auto size = strlen( AtspiPath );
  if( pth.size() <= size )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  if( pth.substr( 0, size ) != AtspiPath )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  if( pth[size] != '/' )
  {
    throw std::domain_error{"invalid path '" + pth + "'"};
  }
  return Find( StripPrefix( pth ) );
}

void BridgeBase::IdSet( int id )
{
  this->id = id;
}

int BridgeBase::IdGet()
{
  return this->id;
}

auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > >
{
  auto root = &application;

  std::vector< CacheElementType > res;

  std::function< void(Accessible*) > proc =
    [&]( Accessible* item )
    {
      res.emplace_back( std::move( CreateCacheElement( root ) ) );
      for( auto i = 0u; i < item->GetChildCount(); ++i )
      {
        proc( item->GetChildAtIndex( i ) );
      }
    };

  return res;
}

auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType
{
  if( !item )
  {
    return {};
  }

  auto root = &application;
  auto parent = item->GetParent();

  std::vector< Address > children;
  for( auto i = 0u; i < item->GetChildCount(); ++i )
  {
    children.emplace_back( item->GetChildAtIndex( i )->GetAddress() );
  }

  return std::make_tuple(
    item->GetAddress(),
    root->GetAddress(),
    parent ? parent->GetAddress() : Address{},
    children,
    item->GetInterfaces(),
    item->GetName(),
    item->GetRole(),
    item->GetDescription(),
    item->GetStates().GetRawData()
  );
}

<|endoftext|>


<commit_before>//===- IndVarSimplify.cpp - Induction Variable Elimination ----------------===//
//
// Guarantees that all loops with identifiable, linear, induction variables will
// be transformed to have a single, cannonical, induction variable.  After this
// pass runs, it guarantees the the first PHI node of the header block in the
// loop is the cannonical induction variable if there is one.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h"

namespace {
  Statistic<> NumRemoved ("indvars", "Number of aux indvars removed");
  Statistic<> NumInserted("indvars", "Number of cannonical indvars added");
}

// InsertCast - Cast Val to Ty, setting a useful name on the cast if Val has a
// name...
//
static Instruction *InsertCast(Value *Val, const Type *Ty,
                               Instruction *InsertBefore) {
  return new CastInst(Val, Ty, Val->getName()+"-casted", InsertBefore);
}

static bool TransformLoop(LoopInfo *Loops, Loop *Loop) {
  // Transform all subloops before this loop...
  bool Changed = reduce_apply_bool(Loop->getSubLoops().begin(),
                                   Loop->getSubLoops().end(),
                              std::bind1st(std::ptr_fun(TransformLoop), Loops));
  // Get the header node for this loop.  All of the phi nodes that could be
  // induction variables must live in this basic block.
  //
  BasicBlock *Header = Loop->getBlocks().front();

  // Loop over all of the PHI nodes in the basic block, calculating the
  // induction variables that they represent... stuffing the induction variable
  // info into a vector...
  //
  std::vector<InductionVariable> IndVars;    // Induction variables for block
  BasicBlock::iterator AfterPHIIt = Header->begin();
  for (; PHINode *PN = dyn_cast<PHINode>(AfterPHIIt); ++AfterPHIIt)
    IndVars.push_back(InductionVariable(PN, Loops));
  // AfterPHIIt now points to first nonphi instruction...

  // If there are no phi nodes in this basic block, there can't be indvars...
  if (IndVars.empty()) return Changed;

  // Loop over the induction variables, looking for a cannonical induction
  // variable, and checking to make sure they are not all unknown induction
  // variables.
  //
  bool FoundIndVars = false;
  InductionVariable *Cannonical = 0;
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    if (IndVars[i].InductionType == InductionVariable::Cannonical &&
        !isa<PointerType>(IndVars[i].Phi->getType()))
      Cannonical = &IndVars[i];
    if (IndVars[i].InductionType != InductionVariable::Unknown)
      FoundIndVars = true;
  }

  // No induction variables, bail early... don't add a cannonnical indvar
  if (!FoundIndVars) return Changed;

  // Okay, we want to convert other induction variables to use a cannonical
  // indvar.  If we don't have one, add one now...
  if (!Cannonical) {
    // Create the PHI node for the new induction variable, and insert the phi
    // node at the end of the other phi nodes...
    PHINode *PN = new PHINode(Type::UIntTy, "cann-indvar", AfterPHIIt);

    // Create the increment instruction to add one to the counter...
    Instruction *Add = BinaryOperator::create(Instruction::Add, PN,
                                              ConstantUInt::get(Type::UIntTy,1),
                                              "add1-indvar", AfterPHIIt);

    // Figure out which block is incoming and which is the backedge for the loop
    BasicBlock *Incoming, *BackEdgeBlock;
    pred_iterator PI = pred_begin(Header);
    assert(PI != pred_end(Header) && "Loop headers should have 2 preds!");
    if (Loop->contains(*PI)) {  // First pred is back edge...
      BackEdgeBlock = *PI++;
      Incoming      = *PI++;
    } else {
      Incoming      = *PI++;
      BackEdgeBlock = *PI++;
    }
    assert(PI == pred_end(Header) && "Loop headers should have 2 preds!");

    // Add incoming values for the PHI node...
    PN->addIncoming(Constant::getNullValue(Type::UIntTy), Incoming);
    PN->addIncoming(Add, BackEdgeBlock);

    // Analyze the new induction variable...
    IndVars.push_back(InductionVariable(PN, Loops));
    assert(IndVars.back().InductionType == InductionVariable::Cannonical &&
           "Just inserted cannonical indvar that is not cannonical!");
    Cannonical = &IndVars.back();
    ++NumInserted;
    Changed = true;
  }

  DEBUG(std::cerr << "Induction variables:\n");

  // Get the current loop iteration count, which is always the value of the
  // cannonical phi node...
  //
  PHINode *IterCount = Cannonical->Phi;

  // Loop through and replace all of the auxillary induction variables with
  // references to the primary induction variable...
  //
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    InductionVariable *IV = &IndVars[i];

    DEBUG(IV->print(std::cerr));

    // Don't do math with pointers...
    const Type *IVTy = IV->Phi->getType();
    if (isa<PointerType>(IVTy)) IVTy = Type::ULongTy;

    // Don't modify the cannonical indvar or unrecognized indvars...
    if (IV != Cannonical && IV->InductionType != InductionVariable::Unknown) {
      Instruction *Val = IterCount;
      if (!isa<ConstantInt>(IV->Step) ||   // If the step != 1
          !cast<ConstantInt>(IV->Step)->equalsInt(1)) {

        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Step->getType() != IVTy)
          IV->Step = InsertCast(IV->Step, IVTy, AfterPHIIt);

        Val = BinaryOperator::create(Instruction::Mul, Val, IV->Step,
                                     IV->Phi->getName()+"-scale", AfterPHIIt);
      }

      // If the start != 0
      if (IV->Start != Constant::getNullValue(IV->Start->getType())) {
        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Start->getType() != IVTy)
          IV->Start = InsertCast(IV->Start, IVTy, AfterPHIIt);

        // Insert the instruction after the phi nodes...
        Val = BinaryOperator::create(Instruction::Add, Val, IV->Start,
                                     IV->Phi->getName()+"-offset", AfterPHIIt);
      }

      // If the PHI node has a different type than val is, insert a cast now...
      if (Val->getType() != IV->Phi->getType())
        Val = InsertCast(Val, IV->Phi->getType(), AfterPHIIt);

      // Replace all uses of the old PHI node with the new computed value...
      IV->Phi->replaceAllUsesWith(Val);

      // Move the PHI name to it's new equivalent value...
      std::string OldName = IV->Phi->getName();
      IV->Phi->setName("");
      Val->setName(OldName);

      // Delete the old, now unused, phi node...
      Header->getInstList().erase(IV->Phi);
      Changed = true;
      ++NumRemoved;
    }
  }

  return Changed;
}

namespace {
  struct InductionVariableSimplify : public FunctionPass {
    virtual bool runOnFunction(Function &) {
      LoopInfo &LI = getAnalysis<LoopInfo>();

      // Induction Variables live in the header nodes of loops
      return reduce_apply_bool(LI.getTopLevelLoops().begin(),
                               LI.getTopLevelLoops().end(),
                               std::bind1st(std::ptr_fun(TransformLoop), &LI));
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LoopInfo>();
      AU.setPreservesCFG();
    }
  };
  RegisterOpt<InductionVariableSimplify> X("indvars",
                                           "Cannonicalize Induction Variables");
}

Pass *createIndVarSimplifyPass() {
  return new InductionVariableSimplify();
}
<commit_msg>Spelling fixes.  I think that "cannonical" is ok, but "canonical" appears to be the canonical form for the word<commit_after>//===- IndVarSimplify.cpp - Induction Variable Elimination ----------------===//
//
// Guarantees that all loops with identifiable, linear, induction variables will
// be transformed to have a single, canonical, induction variable.  After this
// pass runs, it guarantees the the first PHI node of the header block in the
// loop is the canonical induction variable if there is one.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h"

namespace {
  Statistic<> NumRemoved ("indvars", "Number of aux indvars removed");
  Statistic<> NumInserted("indvars", "Number of canonical indvars added");
}

// InsertCast - Cast Val to Ty, setting a useful name on the cast if Val has a
// name...
//
static Instruction *InsertCast(Value *Val, const Type *Ty,
                               Instruction *InsertBefore) {
  return new CastInst(Val, Ty, Val->getName()+"-casted", InsertBefore);
}

static bool TransformLoop(LoopInfo *Loops, Loop *Loop) {
  // Transform all subloops before this loop...
  bool Changed = reduce_apply_bool(Loop->getSubLoops().begin(),
                                   Loop->getSubLoops().end(),
                              std::bind1st(std::ptr_fun(TransformLoop), Loops));
  // Get the header node for this loop.  All of the phi nodes that could be
  // induction variables must live in this basic block.
  //
  BasicBlock *Header = Loop->getHeader();

  // Loop over all of the PHI nodes in the basic block, calculating the
  // induction variables that they represent... stuffing the induction variable
  // info into a vector...
  //
  std::vector<InductionVariable> IndVars;    // Induction variables for block
  BasicBlock::iterator AfterPHIIt = Header->begin();
  for (; PHINode *PN = dyn_cast<PHINode>(AfterPHIIt); ++AfterPHIIt)
    IndVars.push_back(InductionVariable(PN, Loops));
  // AfterPHIIt now points to first nonphi instruction...

  // If there are no phi nodes in this basic block, there can't be indvars...
  if (IndVars.empty()) return Changed;

  // Loop over the induction variables, looking for a canonical induction
  // variable, and checking to make sure they are not all unknown induction
  // variables.
  //
  bool FoundIndVars = false;
  InductionVariable *Canonical = 0;
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    if (IndVars[i].InductionType == InductionVariable::Canonical &&
        !isa<PointerType>(IndVars[i].Phi->getType()))
      Canonical = &IndVars[i];
    if (IndVars[i].InductionType != InductionVariable::Unknown)
      FoundIndVars = true;
  }

  // No induction variables, bail early... don't add a canonical indvar
  if (!FoundIndVars) return Changed;

  // Okay, we want to convert other induction variables to use a canonical
  // indvar.  If we don't have one, add one now...
  if (!Canonical) {
    // Create the PHI node for the new induction variable, and insert the phi
    // node at the end of the other phi nodes...
    PHINode *PN = new PHINode(Type::UIntTy, "cann-indvar", AfterPHIIt);

    // Create the increment instruction to add one to the counter...
    Instruction *Add = BinaryOperator::create(Instruction::Add, PN,
                                              ConstantUInt::get(Type::UIntTy,1),
                                              "add1-indvar", AfterPHIIt);

    // Figure out which block is incoming and which is the backedge for the loop
    BasicBlock *Incoming, *BackEdgeBlock;
    pred_iterator PI = pred_begin(Header);
    assert(PI != pred_end(Header) && "Loop headers should have 2 preds!");
    if (Loop->contains(*PI)) {  // First pred is back edge...
      BackEdgeBlock = *PI++;
      Incoming      = *PI++;
    } else {
      Incoming      = *PI++;
      BackEdgeBlock = *PI++;
    }
    assert(PI == pred_end(Header) && "Loop headers should have 2 preds!");

    // Add incoming values for the PHI node...
    PN->addIncoming(Constant::getNullValue(Type::UIntTy), Incoming);
    PN->addIncoming(Add, BackEdgeBlock);

    // Analyze the new induction variable...
    IndVars.push_back(InductionVariable(PN, Loops));
    assert(IndVars.back().InductionType == InductionVariable::Canonical &&
           "Just inserted canonical indvar that is not canonical!");
    Canonical = &IndVars.back();
    ++NumInserted;
    Changed = true;
  }

  DEBUG(std::cerr << "Induction variables:\n");

  // Get the current loop iteration count, which is always the value of the
  // canonical phi node...
  //
  PHINode *IterCount = Canonical->Phi;

  // Loop through and replace all of the auxiliary induction variables with
  // references to the canonical induction variable...
  //
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    InductionVariable *IV = &IndVars[i];

    DEBUG(IV->print(std::cerr));

    // Don't do math with pointers...
    const Type *IVTy = IV->Phi->getType();
    if (isa<PointerType>(IVTy)) IVTy = Type::ULongTy;

    // Don't modify the canonical indvar or unrecognized indvars...
    if (IV != Canonical && IV->InductionType != InductionVariable::Unknown) {
      Instruction *Val = IterCount;
      if (!isa<ConstantInt>(IV->Step) ||   // If the step != 1
          !cast<ConstantInt>(IV->Step)->equalsInt(1)) {

        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Step->getType() != IVTy)
          IV->Step = InsertCast(IV->Step, IVTy, AfterPHIIt);

        Val = BinaryOperator::create(Instruction::Mul, Val, IV->Step,
                                     IV->Phi->getName()+"-scale", AfterPHIIt);
      }

      // If the start != 0
      if (IV->Start != Constant::getNullValue(IV->Start->getType())) {
        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Start->getType() != IVTy)
          IV->Start = InsertCast(IV->Start, IVTy, AfterPHIIt);

        // Insert the instruction after the phi nodes...
        Val = BinaryOperator::create(Instruction::Add, Val, IV->Start,
                                     IV->Phi->getName()+"-offset", AfterPHIIt);
      }

      // If the PHI node has a different type than val is, insert a cast now...
      if (Val->getType() != IV->Phi->getType())
        Val = InsertCast(Val, IV->Phi->getType(), AfterPHIIt);

      // Replace all uses of the old PHI node with the new computed value...
      IV->Phi->replaceAllUsesWith(Val);

      // Move the PHI name to it's new equivalent value...
      std::string OldName = IV->Phi->getName();
      IV->Phi->setName("");
      Val->setName(OldName);

      // Delete the old, now unused, phi node...
      Header->getInstList().erase(IV->Phi);
      Changed = true;
      ++NumRemoved;
    }
  }

  return Changed;
}

namespace {
  struct InductionVariableSimplify : public FunctionPass {
    virtual bool runOnFunction(Function &) {
      LoopInfo &LI = getAnalysis<LoopInfo>();

      // Induction Variables live in the header nodes of loops
      return reduce_apply_bool(LI.getTopLevelLoops().begin(),
                               LI.getTopLevelLoops().end(),
                               std::bind1st(std::ptr_fun(TransformLoop), &LI));
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LoopInfo>();
      AU.setPreservesCFG();
    }
  };
  RegisterOpt<InductionVariableSimplify> X("indvars",
                                           "Canonicalize Induction Variables");
}

Pass *createIndVarSimplifyPass() {
  return new InductionVariableSimplify();
}
<|endoftext|>


<commit_before>#line 2 "quanta/core/chrono/time.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Time interface.
@ingroup lib_core_chrono
*/

#pragma once

#include <quanta/core/config.hpp>
#include <quanta/core/types.hpp>
#include <togo/core/utility/utility.hpp>

#include <quanta/core/chrono/types.hpp>
#include <quanta/core/chrono/internal.hpp>
#include <quanta/core/chrono/time.gen_interface>

namespace quanta {
namespace time {

/**
	@addtogroup lib_core_chrono
	@{
*/

/// Set zone offset (in seconds).
///
/// Does not adjust the time referred to, only its offset from UTC.
inline void set_zone_offset(Time& t, s32 zone_offset) {
	t.zone_offset = zone_offset;
}

/// Set zone offset (clock).
///
/// Does not adjust the time referred to, only its offset from UTC.
inline void set_zone_clock(Time& t, signed h, signed m = 0, signed s = 0) {
	time::set_zone_offset(t, h * SECS_PER_HOUR + m * SECS_PER_MINUTE + s);
}

/// Set zone offset to UTC.
inline void set_zone_utc(Time& t) {
	time::set_zone_offset(t, 0);
}

/// Adjust zone offset (in seconds).
///
/// Applies the difference between the current and new zone offsets.
inline void adjust_zone_offset(Time& t, s32 zone_offset) {
	t.sec += t.zone_offset - zone_offset;
	time::set_zone_offset(t, zone_offset);
}

/// Adjust zone offset (clock).
///
/// Applies the difference between the current and new zone offsets.
inline void adjust_zone_clock(Time& t, signed h, signed m = 0, signed s = 0) {
	time::adjust_zone_offset(t, h * SECS_PER_HOUR + m * SECS_PER_MINUTE + s);
}

/// Adjust zone offset to UTC.
inline void adjust_zone_utc(Time& t) {
	time::adjust_zone_offset(t, 0);
}

/// Make a copy in UTC.
inline Time as_utc(Time const& t) {
	return {t.sec, 0};
}

/// Make a copy in UTC (zone-adjusted).
inline Time as_utc_adjusted(Time const& t) {
	return {t.sec - t.zone_offset, 0};
}

/// The difference between two time points.
inline Duration difference(Time l, Time r) {
	return l.sec - r.sec;
}

/// Add a duration.
inline void add(Time& t, Duration d) {
	t.sec += d;
}

/// Subtract a duration.
inline void sub(Time& t, Duration d) {
	t.sec -= d;
}

/// Seconds relative to the POSIX epoch.
inline s64 posix(Time const& t) {
	return t.sec + QUANTA_TO_POSIX;
}

/// Hour on clock.
inline signed hour(Time const& t) {
	return (time::abs(t) % SECS_PER_DAY) / SECS_PER_HOUR;
}

/// Minute on clock.
inline signed minute(Time const& t) {
	return (time::abs(t) % SECS_PER_HOUR) / SECS_PER_MINUTE;
}

/// Second on clock.
inline signed second(Time const& t) {
	return time::abs(t) % SECS_PER_MINUTE;
}

/// Set the clock time (UTC).
///
/// This sets the clock time independent of the zone offset.
/// If the current time is negative, it is retained when setting the clock time.
inline void set_utc(Time& t, signed h, signed m, signed s) {
	s64 ct = h * SECS_PER_HOUR + m * SECS_PER_MINUTE + s;
	if (t.sec < 0) {
		t.sec += -t.sec % SECS_PER_DAY;
		t.sec -= ct;
	} else {
		t.sec -= t.sec % SECS_PER_DAY;
		t.sec += ct;
	}
}

/// Set the clock time (zone-local time).
inline void set(Time& t, signed h, signed m, signed s) {
	t.sec += t.zone_offset;
	time::set_utc(t, h, m, s);
	t.sec -= t.zone_offset;
}

namespace gregorian {

/// Whether a Gregorian year is a leap year.
inline bool is_leap_year(signed const year) {
	return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

/// Whether the time specified is in a Gregorian leap year.
inline bool is_leap_year(Time const& t) {
	return gregorian::is_leap_year(gregorian::date_internal(t, false).year);
}

/// Gregorian calendar date.
inline Date date(Time const& t) {
	return gregorian::date_internal(t, true);
}

/// Gregorian calendar year.
inline signed year(Time const& t) {
	return gregorian::date_internal(t, false).year;
}

/// Gregorian calendar month.
inline signed month(Time const& t) {
	return gregorian::date_internal(t, true).month;
}

/// Gregorian calendar day.
inline signed day(Time const& t) {
	return gregorian::date_internal(t, true).day;
}

} // namespace gregorian

/** @} */ // end of doc-group lib_core_chrono

} // namespace time
} // namespace quanta
<commit_msg>lib/core/chrono/time: removed seconds param from set_zone_offset() and adjust_zone_offset(); negative hours implies negative minutes.<commit_after>#line 2 "quanta/core/chrono/time.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Time interface.
@ingroup lib_core_chrono
*/

#pragma once

#include <quanta/core/config.hpp>
#include <quanta/core/types.hpp>
#include <togo/core/utility/utility.hpp>

#include <quanta/core/chrono/types.hpp>
#include <quanta/core/chrono/internal.hpp>
#include <quanta/core/chrono/time.gen_interface>

namespace quanta {
namespace time {

/**
	@addtogroup lib_core_chrono
	@{
*/

/// Set zone offset (in seconds).
///
/// Does not adjust the time referred to, only its offset from UTC.
inline void set_zone_offset(Time& t, s32 zone_offset) {
	t.zone_offset = zone_offset;
}

/// Set zone offset (clock).
///
/// Negative hour implies negative minute.
/// Does not adjust the time referred to, only its offset from UTC.
inline void set_zone_clock(Time& t, signed h, signed m = 0) {
	if (h < 0) {
		m = -m;
	}
	time::set_zone_offset(t, h * SECS_PER_HOUR + m * SECS_PER_MINUTE);
}

/// Set zone offset to UTC.
inline void set_zone_utc(Time& t) {
	time::set_zone_offset(t, 0);
}

/// Adjust zone offset (in seconds).
///
/// Applies the difference between the current and new zone offsets.
inline void adjust_zone_offset(Time& t, s32 zone_offset) {
	t.sec += t.zone_offset - zone_offset;
	time::set_zone_offset(t, zone_offset);
}

/// Adjust zone offset (clock).
///
/// Applies the difference between the current and new zone offsets.
inline void adjust_zone_clock(Time& t, signed h, signed m = 0) {
	if (h < 0) {
		m = -m;
	}
	time::adjust_zone_offset(t, h * SECS_PER_HOUR + m * SECS_PER_MINUTE);
}

/// Adjust zone offset to UTC.
inline void adjust_zone_utc(Time& t) {
	time::adjust_zone_offset(t, 0);
}

/// Make a copy in UTC.
inline Time as_utc(Time const& t) {
	return {t.sec, 0};
}

/// Make a copy in UTC (zone-adjusted).
inline Time as_utc_adjusted(Time const& t) {
	return {t.sec - t.zone_offset, 0};
}

/// The difference between two time points.
inline Duration difference(Time l, Time r) {
	return l.sec - r.sec;
}

/// Add a duration.
inline void add(Time& t, Duration d) {
	t.sec += d;
}

/// Subtract a duration.
inline void sub(Time& t, Duration d) {
	t.sec -= d;
}

/// Seconds relative to the POSIX epoch.
inline s64 posix(Time const& t) {
	return t.sec + QUANTA_TO_POSIX;
}

/// Hour on clock.
inline signed hour(Time const& t) {
	return (time::abs(t) % SECS_PER_DAY) / SECS_PER_HOUR;
}

/// Minute on clock.
inline signed minute(Time const& t) {
	return (time::abs(t) % SECS_PER_HOUR) / SECS_PER_MINUTE;
}

/// Second on clock.
inline signed second(Time const& t) {
	return time::abs(t) % SECS_PER_MINUTE;
}

/// Set the clock time (UTC).
///
/// This sets the clock time independent of the zone offset.
/// If the current time is negative, it is retained when setting the clock time.
inline void set_utc(Time& t, signed h, signed m, signed s) {
	s64 ct = h * SECS_PER_HOUR + m * SECS_PER_MINUTE + s;
	if (t.sec < 0) {
		t.sec += -t.sec % SECS_PER_DAY;
		t.sec -= ct;
	} else {
		t.sec -= t.sec % SECS_PER_DAY;
		t.sec += ct;
	}
}

/// Set the clock time (zone-local time).
inline void set(Time& t, signed h, signed m, signed s) {
	t.sec += t.zone_offset;
	time::set_utc(t, h, m, s);
	t.sec -= t.zone_offset;
}

namespace gregorian {

/// Whether a Gregorian year is a leap year.
inline bool is_leap_year(signed const year) {
	return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

/// Whether the time specified is in a Gregorian leap year.
inline bool is_leap_year(Time const& t) {
	return gregorian::is_leap_year(gregorian::date_internal(t, false).year);
}

/// Gregorian calendar date.
inline Date date(Time const& t) {
	return gregorian::date_internal(t, true);
}

/// Gregorian calendar year.
inline signed year(Time const& t) {
	return gregorian::date_internal(t, false).year;
}

/// Gregorian calendar month.
inline signed month(Time const& t) {
	return gregorian::date_internal(t, true).month;
}

/// Gregorian calendar day.
inline signed day(Time const& t) {
	return gregorian::date_internal(t, true).day;
}

} // namespace gregorian

/** @} */ // end of doc-group lib_core_chrono

} // namespace time
} // namespace quanta
<|endoftext|>


<commit_before>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "fileformatmanager.h"

#include "fileformat.h"

#include "cjsonformat.h"
#include "cmlformat.h"
#include "dcdformat.h"
#include "gromacsformat.h"
#include "lammpsformat.h"
#include "mdlformat.h"
#include "pdbformat.h"
#include "trrformat.h"
#include "vaspformat.h"
#include "xyzformat.h"

#ifdef AVO_USE_MMTF
#include "mmtfformat.h"
#endif

#include <algorithm>
#include <memory>

using std::unique_ptr;

namespace Avogadro::Io {

FileFormatManager& FileFormatManager::instance()
{
  static FileFormatManager instance;
  return instance;
}

bool FileFormatManager::readFile(Core::Molecule& molecule,
                                 const std::string& fileName,
                                 const std::string& fileExtension,
                                 const std::string& options) const
{
  FileFormat* format(nullptr);
  if (fileExtension.empty()) {
    // We need to guess the file extension.
    size_t pos = fileName.find_last_of('.');
    format = filteredFormatFromFormatMap(fileName.substr(pos + 1),
                                         FileFormat::Read | FileFormat::File,
                                         m_fileExtensions);
  } else {
    format = filteredFormatFromFormatMap(
      fileExtension, FileFormat::Read | FileFormat::File, m_fileExtensions);
  }
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->readFile(fileName, molecule);
}

bool FileFormatManager::writeFile(const Core::Molecule& molecule,
                                  const std::string& fileName,
                                  const std::string& fileExtension,
                                  const std::string& options) const
{
  FileFormat* format(nullptr);
  if (fileExtension.empty()) {
    // We need to guess the file extension.
    size_t pos = fileName.find_last_of('.');
    format = filteredFormatFromFormatMap(fileName.substr(pos + 1),
                                         FileFormat::Write | FileFormat::File,
                                         m_fileExtensions);
  } else {
    format = filteredFormatFromFormatMap(
      fileExtension, FileFormat::Write | FileFormat::File, m_fileExtensions);
  }
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->writeFile(fileName, molecule);
}

bool FileFormatManager::readString(Core::Molecule& molecule,
                                   const std::string& string,
                                   const std::string& fileExtension,
                                   const std::string& options) const
{
  FileFormat* format(filteredFormatFromFormatMap(
    fileExtension, FileFormat::Read | FileFormat::String, m_fileExtensions));
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->readString(string, molecule);
}

bool FileFormatManager::writeString(const Core::Molecule& molecule,
                                    std::string& string,
                                    const std::string& fileExtension,
                                    const std::string& options) const
{
  FileFormat* format(filteredFormatFromFormatMap(
    fileExtension, FileFormat::Write | FileFormat::String, m_fileExtensions));
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->writeString(string, molecule);
}

bool FileFormatManager::registerFormat(FileFormat* format)
{
  return instance().addFormat(format);
}

bool FileFormatManager::unregisterFormat(const std::string& identifier)
{
  return instance().removeFormat(identifier);
}

bool FileFormatManager::addFormat(FileFormat* format)
{
  if (!format) {
    appendError("Supplied format was null.");
    return false;
  }
  if (m_identifiers.count(format->identifier()) > 0) {
    appendError("Format " + format->identifier() + " already loaded.");
    return false;
  }
  for (auto & m_format : m_formats) {
    if (m_format == format) {
      appendError("The format object was already loaded.");
      return false;
    }
  }

  // If we got here then the format is unique enough to be added.
  size_t index = m_formats.size();
  m_formats.push_back(format);
  m_identifiers[format->identifier()].push_back(index);
  std::vector<std::string> mimes = format->mimeTypes();
  for (auto & mime : mimes) {
    m_mimeTypes[mime].push_back(index);
  }
  std::vector<std::string> extensions = format->fileExtensions();
  for (auto & extension : extensions) {
    m_fileExtensions[extension].push_back(index);
  }

  return true;
}

namespace {
// Lookup each key from "keys" in "map", and remove "val" from the Map's
// data value (which is a vector of ValueType)
template<typename Map, typename VectorOfKeys, typename ValueType>
void removeFromMap(Map& map, const VectorOfKeys& keys, const ValueType& val)
{
  typedef typename VectorOfKeys::const_iterator KeysIter;
  for (auto key = keys.begin(), keyEnd = keys.end(); key != keyEnd; ++key) {
    auto mapMatch = map.find(*key);
    if (mapMatch == map.end())
      continue;
    typename Map::mapped_type& vec = mapMatch->second;
    if (vec.size() <= 1) {
      map.erase(*key);
    } else {
      auto newEnd =
        std::remove(vec.begin(), vec.end(), val);
      vec.resize(newEnd - vec.begin());
    }
  }
}
}

bool FileFormatManager::removeFormat(const std::string& identifier)
{
  FormatIdVector ids = m_identifiers[identifier];
  m_identifiers.erase(identifier);

  if (ids.empty())
    return false;

  for (unsigned long & id : ids) {
    FileFormat* fmt = m_formats[id];

    if (fmt == nullptr)
      continue;

    removeFromMap(m_mimeTypes, fmt->mimeTypes(), id);
    removeFromMap(m_fileExtensions, fmt->fileExtensions(), id);

    m_formats[id] = nullptr;
    delete fmt;
  }

  return true;
}

FileFormat* FileFormatManager::newFormatFromIdentifier(
  const std::string& id, FileFormat::Operations filter) const
{
  FileFormat* format(filteredFormatFromFormatMap(id, filter, m_identifiers));
  return format ? format->newInstance() : nullptr;
}

FileFormat* FileFormatManager::newFormatFromMimeType(
  const std::string& mime, FileFormat::Operations filter) const
{
  FileFormat* format(filteredFormatFromFormatMap(mime, filter, m_mimeTypes));
  return format ? format->newInstance() : nullptr;
}

FileFormat* FileFormatManager::newFormatFromFileExtension(
  const std::string& extension, FileFormat::Operations filter) const
{
  FileFormat* format(
    filteredFormatFromFormatMap(extension, filter, m_fileExtensions));
  return format ? format->newInstance() : nullptr;
}

std::vector<std::string> FileFormatManager::identifiers(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_identifiers);
}

std::vector<std::string> FileFormatManager::mimeTypes(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_mimeTypes);
}

std::vector<std::string> FileFormatManager::fileExtensions(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_fileExtensions);
}

std::vector<const FileFormat*> FileFormatManager::fileFormats(
  FileFormat::Operations filter) const
{
  std::vector<const FileFormat*> result;

  for (auto m_format : m_formats) {
    if (filter == FileFormat::None ||
        (filter & m_format->supportedOperations()) == filter) {
      result.push_back(m_format);
    }
  }
  return result;
}

std::vector<const FileFormat*> FileFormatManager::fileFormatsFromMimeType(
  const std::string& mimeType, FileFormat::Operations filter) const
{
  std::vector<FileFormat*> matches =
    filteredFormatsFromFormatMap(mimeType, filter, m_mimeTypes);

  return std::vector<const FileFormat*>(matches.begin(), matches.end());
}

std::vector<const FileFormat*> FileFormatManager::fileFormatsFromFileExtension(
  const std::string& extension, FileFormat::Operations filter) const
{
  std::vector<FileFormat*> matches =
    filteredFormatsFromFormatMap(extension, filter, m_fileExtensions);

  return std::vector<const FileFormat*>(matches.begin(), matches.end());
}

std::string FileFormatManager::error() const
{
  return m_error;
}

FileFormatManager::FileFormatManager()
{
  addFormat(new CmlFormat);
  addFormat(new CjsonFormat);
  addFormat(new GromacsFormat);
  addFormat(new MdlFormat);
  addFormat(new OutcarFormat);
  addFormat(new PdbFormat);
  addFormat(new PoscarFormat);
  addFormat(new TrrFormat);
  addFormat(new XyzFormat);
  addFormat(new DcdFormat);
  addFormat(new LammpsTrajectoryFormat);
  addFormat(new LammpsDataFormat);
#ifdef AVO_USE_MMTF
  addFormat(new MMTFFormat);
#endif
}

FileFormatManager::~FileFormatManager()
{
  // Delete the file formats that were loaded.
  for (auto & m_format : m_formats) {
    delete m_format;
  }
  m_formats.clear();
}

std::vector<std::string> FileFormatManager::filteredKeysFromFormatMap(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  std::vector<std::string> result;
  for (const auto & it : fmap) {
    for (auto formatIt = it.second.begin();
         formatIt != it.second.end(); ++formatIt) {
      if (filter == FileFormat::None ||
          (m_formats[*formatIt]->supportedOperations() & filter) == filter) {
        result.push_back(it.first);
        break;
      }
    }
  }
  return result;
}

std::vector<FileFormat*> FileFormatManager::filteredFormatsFromFormatMap(
  const std::string& key, FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  std::vector<FileFormat*> result;

  auto it = fmap.find(key);
  if (it != fmap.end())
    result = filteredFormatsFromFormatVector(filter, it->second);

  return result;
}

FileFormat* FileFormatManager::filteredFormatFromFormatMap(
  const std::string& key, FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  auto it = fmap.find(key);
  if (it != fmap.end())
    return filteredFormatFromFormatVector(filter, it->second);

  return nullptr;
}

std::vector<FileFormat*> FileFormatManager::filteredFormatsFromFormatVector(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdVector& v) const
{
  std::vector<FileFormat*> result;
  for (unsigned long it : v) {
    if (filter == FileFormat::None ||
        (m_formats[it]->supportedOperations() & filter) == filter) {
      result.push_back(m_formats[it]);
    }
  }
  return result;
}

FileFormat* FileFormatManager::filteredFormatFromFormatVector(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdVector& v) const
{
  for (unsigned long it : v) {
    if (filter == FileFormat::None ||
        (m_formats[it]->supportedOperations() & filter) == filter) {
      return m_formats[it];
    }
  }
  return nullptr;
}

void FileFormatManager::appendError(const std::string& errorMessage)
{
  m_error += errorMessage + "\n";
}

} // end Avogadro namespace
<commit_msg>Fix Visual C++ error with range-loop<commit_after>/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include "fileformatmanager.h"

#include "fileformat.h"

#include "cjsonformat.h"
#include "cmlformat.h"
#include "dcdformat.h"
#include "gromacsformat.h"
#include "lammpsformat.h"
#include "mdlformat.h"
#include "pdbformat.h"
#include "trrformat.h"
#include "vaspformat.h"
#include "xyzformat.h"

#ifdef AVO_USE_MMTF
#include "mmtfformat.h"
#endif

#include <algorithm>
#include <memory>

using std::unique_ptr;

namespace Avogadro::Io {

FileFormatManager& FileFormatManager::instance()
{
  static FileFormatManager instance;
  return instance;
}

bool FileFormatManager::readFile(Core::Molecule& molecule,
                                 const std::string& fileName,
                                 const std::string& fileExtension,
                                 const std::string& options) const
{
  FileFormat* format(nullptr);
  if (fileExtension.empty()) {
    // We need to guess the file extension.
    size_t pos = fileName.find_last_of('.');
    format = filteredFormatFromFormatMap(fileName.substr(pos + 1),
                                         FileFormat::Read | FileFormat::File,
                                         m_fileExtensions);
  } else {
    format = filteredFormatFromFormatMap(
      fileExtension, FileFormat::Read | FileFormat::File, m_fileExtensions);
  }
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->readFile(fileName, molecule);
}

bool FileFormatManager::writeFile(const Core::Molecule& molecule,
                                  const std::string& fileName,
                                  const std::string& fileExtension,
                                  const std::string& options) const
{
  FileFormat* format(nullptr);
  if (fileExtension.empty()) {
    // We need to guess the file extension.
    size_t pos = fileName.find_last_of('.');
    format = filteredFormatFromFormatMap(fileName.substr(pos + 1),
                                         FileFormat::Write | FileFormat::File,
                                         m_fileExtensions);
  } else {
    format = filteredFormatFromFormatMap(
      fileExtension, FileFormat::Write | FileFormat::File, m_fileExtensions);
  }
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->writeFile(fileName, molecule);
}

bool FileFormatManager::readString(Core::Molecule& molecule,
                                   const std::string& string,
                                   const std::string& fileExtension,
                                   const std::string& options) const
{
  FileFormat* format(filteredFormatFromFormatMap(
    fileExtension, FileFormat::Read | FileFormat::String, m_fileExtensions));
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->readString(string, molecule);
}

bool FileFormatManager::writeString(const Core::Molecule& molecule,
                                    std::string& string,
                                    const std::string& fileExtension,
                                    const std::string& options) const
{
  FileFormat* format(filteredFormatFromFormatMap(
    fileExtension, FileFormat::Write | FileFormat::String, m_fileExtensions));
  if (!format)
    return false;

  unique_ptr<FileFormat> formatInstance(format->newInstance());
  formatInstance->setOptions(options);
  return formatInstance->writeString(string, molecule);
}

bool FileFormatManager::registerFormat(FileFormat* format)
{
  return instance().addFormat(format);
}

bool FileFormatManager::unregisterFormat(const std::string& identifier)
{
  return instance().removeFormat(identifier);
}

bool FileFormatManager::addFormat(FileFormat* format)
{
  if (!format) {
    appendError("Supplied format was null.");
    return false;
  }
  if (m_identifiers.count(format->identifier()) > 0) {
    appendError("Format " + format->identifier() + " already loaded.");
    return false;
  }
  for (auto & m_format : m_formats) {
    if (m_format == format) {
      appendError("The format object was already loaded.");
      return false;
    }
  }

  // If we got here then the format is unique enough to be added.
  size_t index = m_formats.size();
  m_formats.push_back(format);
  m_identifiers[format->identifier()].push_back(index);
  std::vector<std::string> mimes = format->mimeTypes();
  for (auto & mime : mimes) {
    m_mimeTypes[mime].push_back(index);
  }
  std::vector<std::string> extensions = format->fileExtensions();
  for (auto & extension : extensions) {
    m_fileExtensions[extension].push_back(index);
  }

  return true;
}

namespace {
// Lookup each key from "keys" in "map", and remove "val" from the Map's
// data value (which is a vector of ValueType)
template<typename Map, typename VectorOfKeys, typename ValueType>
void removeFromMap(Map& map, const VectorOfKeys& keys, const ValueType& val)
{
  typedef typename VectorOfKeys::const_iterator KeysIter;
  for (auto key = keys.begin(), keyEnd = keys.end(); key != keyEnd; ++key) {
    auto mapMatch = map.find(*key);
    if (mapMatch == map.end())
      continue;
    typename Map::mapped_type& vec = mapMatch->second;
    if (vec.size() <= 1) {
      map.erase(*key);
    } else {
      auto newEnd =
        std::remove(vec.begin(), vec.end(), val);
      vec.resize(newEnd - vec.begin());
    }
  }
}
}

bool FileFormatManager::removeFormat(const std::string& identifier)
{
  FormatIdVector ids = m_identifiers[identifier];
  m_identifiers.erase(identifier);

  if (ids.empty())
    return false;

  for (size_t id : ids) {
    FileFormat* fmt = m_formats[id];

    if (fmt == nullptr)
      continue;

    removeFromMap(m_mimeTypes, fmt->mimeTypes(), id);
    removeFromMap(m_fileExtensions, fmt->fileExtensions(), id);

    m_formats[id] = nullptr;
    delete fmt;
  }

  return true;
}

FileFormat* FileFormatManager::newFormatFromIdentifier(
  const std::string& id, FileFormat::Operations filter) const
{
  FileFormat* format(filteredFormatFromFormatMap(id, filter, m_identifiers));
  return format ? format->newInstance() : nullptr;
}

FileFormat* FileFormatManager::newFormatFromMimeType(
  const std::string& mime, FileFormat::Operations filter) const
{
  FileFormat* format(filteredFormatFromFormatMap(mime, filter, m_mimeTypes));
  return format ? format->newInstance() : nullptr;
}

FileFormat* FileFormatManager::newFormatFromFileExtension(
  const std::string& extension, FileFormat::Operations filter) const
{
  FileFormat* format(
    filteredFormatFromFormatMap(extension, filter, m_fileExtensions));
  return format ? format->newInstance() : nullptr;
}

std::vector<std::string> FileFormatManager::identifiers(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_identifiers);
}

std::vector<std::string> FileFormatManager::mimeTypes(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_mimeTypes);
}

std::vector<std::string> FileFormatManager::fileExtensions(
  FileFormat::Operations filter) const
{
  return filteredKeysFromFormatMap(filter, m_fileExtensions);
}

std::vector<const FileFormat*> FileFormatManager::fileFormats(
  FileFormat::Operations filter) const
{
  std::vector<const FileFormat*> result;

  for (auto m_format : m_formats) {
    if (filter == FileFormat::None ||
        (filter & m_format->supportedOperations()) == filter) {
      result.push_back(m_format);
    }
  }
  return result;
}

std::vector<const FileFormat*> FileFormatManager::fileFormatsFromMimeType(
  const std::string& mimeType, FileFormat::Operations filter) const
{
  std::vector<FileFormat*> matches =
    filteredFormatsFromFormatMap(mimeType, filter, m_mimeTypes);

  return std::vector<const FileFormat*>(matches.begin(), matches.end());
}

std::vector<const FileFormat*> FileFormatManager::fileFormatsFromFileExtension(
  const std::string& extension, FileFormat::Operations filter) const
{
  std::vector<FileFormat*> matches =
    filteredFormatsFromFormatMap(extension, filter, m_fileExtensions);

  return std::vector<const FileFormat*>(matches.begin(), matches.end());
}

std::string FileFormatManager::error() const
{
  return m_error;
}

FileFormatManager::FileFormatManager()
{
  addFormat(new CmlFormat);
  addFormat(new CjsonFormat);
  addFormat(new GromacsFormat);
  addFormat(new MdlFormat);
  addFormat(new OutcarFormat);
  addFormat(new PdbFormat);
  addFormat(new PoscarFormat);
  addFormat(new TrrFormat);
  addFormat(new XyzFormat);
  addFormat(new DcdFormat);
  addFormat(new LammpsTrajectoryFormat);
  addFormat(new LammpsDataFormat);
#ifdef AVO_USE_MMTF
  addFormat(new MMTFFormat);
#endif
}

FileFormatManager::~FileFormatManager()
{
  // Delete the file formats that were loaded.
  for (auto & m_format : m_formats) {
    delete m_format;
  }
  m_formats.clear();
}

std::vector<std::string> FileFormatManager::filteredKeysFromFormatMap(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  std::vector<std::string> result;
  for (const auto & it : fmap) {
    for (auto formatIt = it.second.begin();
         formatIt != it.second.end(); ++formatIt) {
      if (filter == FileFormat::None ||
          (m_formats[*formatIt]->supportedOperations() & filter) == filter) {
        result.push_back(it.first);
        break;
      }
    }
  }
  return result;
}

std::vector<FileFormat*> FileFormatManager::filteredFormatsFromFormatMap(
  const std::string& key, FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  std::vector<FileFormat*> result;

  auto it = fmap.find(key);
  if (it != fmap.end())
    result = filteredFormatsFromFormatVector(filter, it->second);

  return result;
}

FileFormat* FileFormatManager::filteredFormatFromFormatMap(
  const std::string& key, FileFormat::Operations filter,
  const FileFormatManager::FormatIdMap& fmap) const
{
  auto it = fmap.find(key);
  if (it != fmap.end())
    return filteredFormatFromFormatVector(filter, it->second);

  return nullptr;
}

std::vector<FileFormat*> FileFormatManager::filteredFormatsFromFormatVector(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdVector& v) const
{
  std::vector<FileFormat*> result;
  for (unsigned long it : v) {
    if (filter == FileFormat::None ||
        (m_formats[it]->supportedOperations() & filter) == filter) {
      result.push_back(m_formats[it]);
    }
  }
  return result;
}

FileFormat* FileFormatManager::filteredFormatFromFormatVector(
  FileFormat::Operations filter,
  const FileFormatManager::FormatIdVector& v) const
{
  for (unsigned long it : v) {
    if (filter == FileFormat::None ||
        (m_formats[it]->supportedOperations() & filter) == filter) {
      return m_formats[it];
    }
  }
  return nullptr;
}

void FileFormatManager::appendError(const std::string& errorMessage)
{
  m_error += errorMessage + "\n";
}

} // end Avogadro namespace
<|endoftext|>