Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/ui/webui/policy_ui.h" | 5 #include "chrome/browser/ui/webui/policy_ui.h" | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" | 
| 9 #include "base/callback.h" | 9 #include "base/callback.h" | 
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 #include "chrome/browser/policy/cloud/message_util.h" | 25 #include "chrome/browser/policy/cloud/message_util.h" | 
| 26 #include "chrome/browser/policy/configuration_policy_handler_list.h" | 26 #include "chrome/browser/policy/configuration_policy_handler_list.h" | 
| 27 #include "chrome/browser/policy/policy_error_map.h" | 27 #include "chrome/browser/policy/policy_error_map.h" | 
| 28 #include "chrome/browser/policy/policy_map.h" | 28 #include "chrome/browser/policy/policy_map.h" | 
| 29 #include "chrome/browser/policy/policy_service.h" | 29 #include "chrome/browser/policy/policy_service.h" | 
| 30 #include "chrome/browser/policy/policy_types.h" | 30 #include "chrome/browser/policy/policy_types.h" | 
| 31 #include "chrome/browser/policy/profile_policy_connector.h" | 31 #include "chrome/browser/policy/profile_policy_connector.h" | 
| 32 #include "chrome/browser/policy/profile_policy_connector_factory.h" | 32 #include "chrome/browser/policy/profile_policy_connector_factory.h" | 
| 33 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" | 33 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" | 
| 34 #include "chrome/browser/profiles/profile.h" | 34 #include "chrome/browser/profiles/profile.h" | 
| 35 #include "chrome/common/chrome_notification_types.h" | |
| 35 #include "chrome/common/time_format.h" | 36 #include "chrome/common/time_format.h" | 
| 36 #include "chrome/common/url_constants.h" | 37 #include "chrome/common/url_constants.h" | 
| 38 #include "content/public/browser/notification_observer.h" | |
| 39 #include "content/public/browser/notification_registrar.h" | |
| 40 #include "content/public/browser/notification_service.h" | |
| 37 #include "content/public/browser/web_ui.h" | 41 #include "content/public/browser/web_ui.h" | 
| 38 #include "content/public/browser/web_ui_data_source.h" | 42 #include "content/public/browser/web_ui_data_source.h" | 
| 39 #include "content/public/browser/web_ui_message_handler.h" | 43 #include "content/public/browser/web_ui_message_handler.h" | 
| 40 #include "google_apis/gaia/gaia_auth_util.h" | 44 #include "google_apis/gaia/gaia_auth_util.h" | 
| 41 #include "grit/browser_resources.h" | 45 #include "grit/browser_resources.h" | 
| 42 #include "grit/generated_resources.h" | 46 #include "grit/generated_resources.h" | 
| 43 #include "policy/policy_constants.h" | 47 #include "policy/policy_constants.h" | 
| 44 #include "ui/base/l10n/l10n_util.h" | 48 #include "ui/base/l10n/l10n_util.h" | 
| 45 | 49 | 
| 46 #if defined(OS_CHROMEOS) | 50 #if defined(OS_CHROMEOS) | 
| 47 #include "chrome/browser/chromeos/login/user_manager.h" | 51 #include "chrome/browser/chromeos/login/user_manager.h" | 
| 48 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" | 52 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" | 
| 49 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h" | 53 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h" | 
| 50 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" | 54 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" | 
| 51 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chrom eos.h" | 55 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chrom eos.h" | 
| 52 #else | 56 #else | 
| 53 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h" | 57 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h" | 
| 54 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h" | 58 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h" | 
| 55 #endif | 59 #endif | 
| 56 | 60 | 
| 57 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 61 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 
| 58 #include "chrome/browser/extensions/extension_service.h" | 62 #include "chrome/browser/extensions/extension_service.h" | 
| 59 #include "chrome/browser/extensions/extension_system.h" | 63 #include "chrome/browser/extensions/extension_system.h" | 
| 64 #include "chrome/browser/policy/policy_domain_descriptor.h" | |
| 65 #include "chrome/browser/policy/policy_schema.h" | |
| 60 #include "chrome/common/extensions/extension.h" | 66 #include "chrome/common/extensions/extension.h" | 
| 61 #include "chrome/common/extensions/extension_set.h" | 67 #include "chrome/common/extensions/extension_set.h" | 
| 62 #include "chrome/common/extensions/manifest.h" | 68 #include "chrome/common/extensions/manifest.h" | 
| 63 #endif | 69 #endif | 
| 64 | 70 | 
| 65 namespace em = enterprise_management; | 71 namespace em = enterprise_management; | 
| 66 | 72 | 
| 67 namespace { | 73 namespace { | 
| 68 | 74 | 
| 69 content::WebUIDataSource* CreatePolicyUIHTMLSource() { | 75 content::WebUIDataSource* CreatePolicyUIHTMLSource() { | 
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 | 265 | 
| 260 private: | 266 private: | 
| 261 const std::string user_id_; | 267 const std::string user_id_; | 
| 262 policy::DeviceLocalAccountPolicyService* service_; | 268 policy::DeviceLocalAccountPolicyService* service_; | 
| 263 | 269 | 
| 264 DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider); | 270 DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider); | 
| 265 }; | 271 }; | 
| 266 #endif | 272 #endif | 
| 267 | 273 | 
| 268 // The JavaScript message handler for the chrome://policy page. | 274 // The JavaScript message handler for the chrome://policy page. | 
| 269 class PolicyUIHandler : public content::WebUIMessageHandler, | 275 class PolicyUIHandler : public content::NotificationObserver, | 
| 276 public content::WebUIMessageHandler, | |
| 270 public policy::PolicyService::Observer { | 277 public policy::PolicyService::Observer { | 
| 271 public: | 278 public: | 
| 272 PolicyUIHandler(); | 279 PolicyUIHandler(); | 
| 273 virtual ~PolicyUIHandler(); | 280 virtual ~PolicyUIHandler(); | 
| 274 | 281 | 
| 282 // content::NotificationObserver implementation. | |
| 283 virtual void Observe(int type, | |
| 284 const content::NotificationSource& source, | |
| 285 const content::NotificationDetails& details) OVERRIDE; | |
| 286 | |
| 275 // content::WebUIMessageHandler implementation. | 287 // content::WebUIMessageHandler implementation. | 
| 276 virtual void RegisterMessages() OVERRIDE; | 288 virtual void RegisterMessages() OVERRIDE; | 
| 277 | 289 | 
| 278 // policy::PolicyService::Observer implementation. | 290 // policy::PolicyService::Observer implementation. | 
| 279 virtual void OnPolicyUpdated(const policy::PolicyNamespace& ns, | 291 virtual void OnPolicyUpdated(const policy::PolicyNamespace& ns, | 
| 280 const policy::PolicyMap& previous, | 292 const policy::PolicyMap& previous, | 
| 281 const policy::PolicyMap& current) OVERRIDE; | 293 const policy::PolicyMap& current) OVERRIDE; | 
| 282 | 294 | 
| 283 private: | 295 private: | 
| 284 // Send a dictionary containing the names of all known policies to the UI. | 296 // Send a dictionary containing the names of all known policies to the UI. | 
| (...skipping 27 matching lines...) Expand all Loading... | |
| 312 bool initialized_; | 324 bool initialized_; | 
| 313 std::string device_domain_; | 325 std::string device_domain_; | 
| 314 base::WeakPtrFactory<PolicyUIHandler> weak_factory_; | 326 base::WeakPtrFactory<PolicyUIHandler> weak_factory_; | 
| 315 | 327 | 
| 316 // Providers that supply status dictionaries for user and device policy, | 328 // Providers that supply status dictionaries for user and device policy, | 
| 317 // respectively. These are created on initialization time as appropriate for | 329 // respectively. These are created on initialization time as appropriate for | 
| 318 // the platform (Chrome OS / desktop) and type of policy that is in effect. | 330 // the platform (Chrome OS / desktop) and type of policy that is in effect. | 
| 319 scoped_ptr<CloudPolicyStatusProvider> user_status_provider_; | 331 scoped_ptr<CloudPolicyStatusProvider> user_status_provider_; | 
| 320 scoped_ptr<CloudPolicyStatusProvider> device_status_provider_; | 332 scoped_ptr<CloudPolicyStatusProvider> device_status_provider_; | 
| 321 | 333 | 
| 334 content::NotificationRegistrar registrar_; | |
| 335 | |
| 322 DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler); | 336 DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler); | 
| 323 }; | 337 }; | 
| 324 | 338 | 
| 325 CloudPolicyStatusProvider::CloudPolicyStatusProvider() { | 339 CloudPolicyStatusProvider::CloudPolicyStatusProvider() { | 
| 326 } | 340 } | 
| 327 | 341 | 
| 328 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() { | 342 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() { | 
| 329 } | 343 } | 
| 330 | 344 | 
| 331 void CloudPolicyStatusProvider::SetStatusChangeCallback( | 345 void CloudPolicyStatusProvider::SetStatusChangeCallback( | 
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 if (!device_status_provider_.get()) | 498 if (!device_status_provider_.get()) | 
| 485 device_status_provider_.reset(new CloudPolicyStatusProvider()); | 499 device_status_provider_.reset(new CloudPolicyStatusProvider()); | 
| 486 | 500 | 
| 487 base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus, | 501 base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus, | 
| 488 base::Unretained(this))); | 502 base::Unretained(this))); | 
| 489 user_status_provider_->SetStatusChangeCallback(update_callback); | 503 user_status_provider_->SetStatusChangeCallback(update_callback); | 
| 490 device_status_provider_->SetStatusChangeCallback(update_callback); | 504 device_status_provider_->SetStatusChangeCallback(update_callback); | 
| 491 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this); | 505 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this); | 
| 492 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this); | 506 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this); | 
| 493 | 507 | 
| 508 registrar_.Add(this, | |
| 509 chrome::NOTIFICATION_EXTENSION_LOADED, | |
| 510 content::NotificationService::AllSources()); | |
| 511 registrar_.Add(this, | |
| 512 chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
| 513 content::NotificationService::AllSources()); | |
| 514 | |
| 494 web_ui()->RegisterMessageCallback( | 515 web_ui()->RegisterMessageCallback( | 
| 495 "initialized", | 516 "initialized", | 
| 496 base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this))); | 517 base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this))); | 
| 497 web_ui()->RegisterMessageCallback( | 518 web_ui()->RegisterMessageCallback( | 
| 498 "reloadPolicies", | 519 "reloadPolicies", | 
| 499 base::Bind(&PolicyUIHandler::HandleReloadPolicies, | 520 base::Bind(&PolicyUIHandler::HandleReloadPolicies, | 
| 500 base::Unretained(this))); | 521 base::Unretained(this))); | 
| 501 } | 522 } | 
| 502 | 523 | 
| 524 void PolicyUIHandler::Observe(int type, | |
| 525 const content::NotificationSource& source, | |
| 526 const content::NotificationDetails& details) { | |
| 527 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED || | |
| 528 type == chrome::NOTIFICATION_EXTENSION_UNLOADED); | |
| 529 SendPolicyNames(); | |
| 530 SendPolicyValues(); | |
| 531 } | |
| 532 | |
| 503 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns, | 533 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns, | 
| 504 const policy::PolicyMap& previous, | 534 const policy::PolicyMap& previous, | 
| 505 const policy::PolicyMap& current) { | 535 const policy::PolicyMap& current) { | 
| 506 SendPolicyValues(); | 536 SendPolicyValues(); | 
| 507 } | 537 } | 
| 508 | 538 | 
| 509 void PolicyUIHandler::SendPolicyNames() const { | 539 void PolicyUIHandler::SendPolicyNames() const { | 
| 510 base::DictionaryValue names; | 540 base::DictionaryValue names; | 
| 541 | |
| 542 // Add Chrome policy names. | |
| 543 base::DictionaryValue* chrome_policy_names = new base::DictionaryValue; | |
| 511 const policy::PolicyDefinitionList* list = | 544 const policy::PolicyDefinitionList* list = | 
| 512 policy::GetChromePolicyDefinitionList(); | 545 policy::GetChromePolicyDefinitionList(); | 
| 513 for (const policy::PolicyDefinitionList::Entry* entry = list->begin; | 546 for (const policy::PolicyDefinitionList::Entry* entry = list->begin; | 
| 514 entry != list->end; ++entry) { | 547 entry != list->end; ++entry) { | 
| 515 names.SetBoolean(entry->name, true); | 548 chrome_policy_names->SetBoolean(entry->name, true); | 
| 516 } | 549 } | 
| 550 names.Set("chromePolicyNames", chrome_policy_names); | |
| 551 | |
| 552 #if !defined(OS_ANDROID) && !defined(OS_IOS) | |
| 553 // Add extension policy names. | |
| 554 base::DictionaryValue* extension_policy_names = new base::DictionaryValue; | |
| 555 extensions::ExtensionSystem* extension_system = | |
| 556 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui())); | |
| 557 const ExtensionSet* extensions = | |
| 558 extension_system->extension_service()->extensions(); | |
| 559 scoped_refptr<const policy::PolicyDomainDescriptor> policy_domain_descriptor; | |
| 560 policy_domain_descriptor = GetPolicyService()-> | |
| 561 GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS); | |
| 562 const policy::PolicyDomainDescriptor::SchemaMap& schema_map = | |
| 563 policy_domain_descriptor->components(); | |
| 564 | |
| 565 for (ExtensionSet::const_iterator it = extensions->begin(); | |
| 566 it != extensions->end(); ++it) { | |
| 567 const extensions::Extension* extension = *it; | |
| 568 if (extension->location() == extensions::Manifest::COMPONENT) | |
| 569 continue; | |
| 570 base::DictionaryValue* extension_value = new base::DictionaryValue; | |
| 571 extension_value->SetString("name", extension->name()); | |
| 572 policy::PolicyDomainDescriptor::SchemaMap::const_iterator schema = | |
| 573 schema_map.find(extension->id()); | |
| 574 base::DictionaryValue* policy_names = new base::DictionaryValue; | |
| 575 if (schema != schema_map.end()) { | |
| 576 // Get policy names from the extension's policy schema. | |
| 577 // Store in a map, not an array, for faster lookup on JS side. | |
| 578 const policy::PolicySchemaMap* policies = schema->second->GetProperties(); | |
| 579 policy::PolicySchemaMap::const_iterator it_policies; | |
| 580 for (it_policies = policies->begin(); it_policies != policies->end(); | |
| 581 it_policies++) { | |
| 582 policy_names->SetBoolean(it_policies->first, true); | |
| 583 } | |
| 584 } | |
| 585 extension_value->Set("policyNames", policy_names); | |
| 586 extension_policy_names->Set(extension->id(), extension_value); | |
| 587 } | |
| 588 names.Set("extensionPolicyNames", extension_policy_names); | |
| 589 #endif | |
| 590 | |
| 517 web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names); | 591 web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names); | 
| 518 } | 592 } | 
| 519 | 593 | 
| 520 void PolicyUIHandler::SendPolicyValues() const { | 594 void PolicyUIHandler::SendPolicyValues() const { | 
| 521 base::DictionaryValue all_policies; | 595 base::DictionaryValue all_policies; | 
| 522 | 596 | 
| 523 // Add chrome policies. | 597 // Add Chrome policy values. | 
| 524 base::DictionaryValue* chrome_policies = new base::DictionaryValue; | 598 base::DictionaryValue* chrome_policies = new base::DictionaryValue; | 
| 525 GetChromePolicyValues(chrome_policies); | 599 GetChromePolicyValues(chrome_policies); | 
| 526 all_policies.Set("chromePolicies", chrome_policies); | 600 all_policies.Set("chromePolicies", chrome_policies); | 
| 527 | 601 | 
| 528 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 602 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 
| 529 // Get extensions. | 603 // Add extension policy values. | 
| 530 extensions::ExtensionSystem* extension_system = | 604 extensions::ExtensionSystem* extension_system = | 
| 531 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui())); | 605 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui())); | 
| 532 const ExtensionSet* extensions = | 606 const ExtensionSet* extensions = | 
| 533 extension_system->extension_service()->extensions(); | 607 extension_system->extension_service()->extensions(); | 
| 608 base::DictionaryValue* extension_values = new base::DictionaryValue; | |
| 534 | 609 | 
| 535 // Add policies for each extension. | |
| 536 base::DictionaryValue* extension_values = new base::DictionaryValue; | |
| 537 for (ExtensionSet::const_iterator it = extensions->begin(); | 610 for (ExtensionSet::const_iterator it = extensions->begin(); | 
| 538 it != extensions->end(); ++it) { | 611 it != extensions->end(); ++it) { | 
| 539 const extensions::Extension* extension = *it; | 612 const extensions::Extension* extension = *it; | 
| 540 | |
| 541 // Skip this extension if it's a component extension. | |
| 542 if (extension->location() == extensions::Manifest::COMPONENT) | 613 if (extension->location() == extensions::Manifest::COMPONENT) | 
| 543 continue; | 614 continue; | 
| 544 | |
| 545 base::DictionaryValue* extension_value = new base::DictionaryValue; | |
| 546 | |
| 547 // Add name. | |
| 548 extension_value->SetString("name", extension->name()); | |
| 549 | |
| 550 // Add policies. | |
| 551 base::DictionaryValue* extension_policies = new base::DictionaryValue; | 615 base::DictionaryValue* extension_policies = new base::DictionaryValue; | 
| 552 policy::PolicyNamespace policy_namespace = policy::PolicyNamespace( | 616 policy::PolicyNamespace policy_namespace = policy::PolicyNamespace( | 
| 553 policy::POLICY_DOMAIN_EXTENSIONS, extension->id()); | 617 policy::POLICY_DOMAIN_EXTENSIONS, extension->id()); | 
| 554 policy::PolicyErrorMap empty_error_map; | 618 policy::PolicyErrorMap empty_error_map; | 
| 555 GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace), | 619 GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace), | 
| 556 &empty_error_map, extension_policies); | 620 &empty_error_map, extension_policies); | 
| 557 extension_value->Set("policies", extension_policies); | 621 extension_values->Set(extension->id(), extension_policies); | 
| 558 | |
| 559 // Add entry to the dictionary. | |
| 560 extension_values->Set(extension->id(), extension_value); | |
| 561 } | 622 } | 
| 562 all_policies.Set("extensionPolicies", extension_values); | 623 all_policies.Set("extensionPolicies", extension_values); | 
| 563 #endif | 624 #endif | 
| 564 | |
| 565 web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies); | |
| 
 
anitawoodruff
2013/06/25 08:20:04
Oops. This line should certainly not have been rem
 
 | |
| 566 } | 625 } | 
| 567 | 626 | 
| 568 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map, | 627 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map, | 
| 569 policy::PolicyErrorMap* errors, | 628 policy::PolicyErrorMap* errors, | 
| 570 base::DictionaryValue* values) const { | 629 base::DictionaryValue* values) const { | 
| 571 for (policy::PolicyMap::const_iterator entry = map.begin(); | 630 for (policy::PolicyMap::const_iterator entry = map.begin(); | 
| 572 entry != map.end(); ++entry) { | 631 entry != map.end(); ++entry) { | 
| 573 base::DictionaryValue* value = new base::DictionaryValue; | 632 base::DictionaryValue* value = new base::DictionaryValue; | 
| 574 value->Set("value", entry->second.value->DeepCopy()); | 633 value->Set("value", entry->second.value->DeepCopy()); | 
| 575 if (entry->second.scope == policy::POLICY_SCOPE_USER) | 634 if (entry->second.scope == policy::POLICY_SCOPE_USER) | 
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 } | 711 } | 
| 653 | 712 | 
| 654 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) { | 713 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) { | 
| 655 web_ui->AddMessageHandler(new PolicyUIHandler); | 714 web_ui->AddMessageHandler(new PolicyUIHandler); | 
| 656 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), | 715 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), | 
| 657 CreatePolicyUIHTMLSource()); | 716 CreatePolicyUIHTMLSource()); | 
| 658 } | 717 } | 
| 659 | 718 | 
| 660 PolicyUI::~PolicyUI() { | 719 PolicyUI::~PolicyUI() { | 
| 661 } | 720 } | 
| OLD | NEW |