/* This file is part of the KDE project
   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>

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

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#ifndef FORMMANAGER_H
#define FORMMANAGER_H

#include <qobject.h>
#include <qdom.h>
#include <qptrlist.h>
#include <qtimer.h>

class QWidget;
class QWorkspace;
class KPopupMenu;
class KexiPropertyEditor;
class KexiPropertyBuffer;
class KActionCollection;
class KAction;
class KToggleAction;
class KXMLGUIClient;
class KMainWindow;

namespace KFormDesigner {

class ObjectPropertyBuffer;
class Form;
class Container;
class WidgetLibrary;
class ObjectTreeView;
class Connection;
typedef QPtrList<KAction> ActionList;

//! A class to manage (create/load/save) Forms
/** This is Form Designer's top class, which is used by external APIs to access FormDesigner. This is the class you have to use
   to integrate FormDesigner into another program.\n
   It deals with creating, saving and loading Form, as well as widget insertion and copying.\n
   It also ensures all the components (ObjectTreeView, Form and PropertyEditor) are synced, and link them.\n
   It holds the WidgetLibrary, the ObjectPropertyBuffer, links to ObjectTreeView and PropertyEditor, as well as the copied widget
   and the insert state.
 **/
class KFORMEDITOR_EXPORT FormManager : public QObject
{
	Q_OBJECT

	public:
		FormManager(QObject *parent, const char *name);
		virtual ~FormManager();

		/*! Creates all the KAction related to widget insertion, and plug them into the KActionCollection \a parent.
		  These actions are automatically connected to \ref insertWidget() slot.
		  \return a QPtrList of the created actions.
		 */
		ActionList createActions(KActionCollection *parent);
		bool              isPasteEnabled();

		//! \return A pointer to the WidgetLibrary owned by this Manager.
		WidgetLibrary*    lib() const { return m_lib; }
		//! \return A pointer to the ObjectPropertyBuffer owned by this Manager.
		ObjectPropertyBuffer*  buffer() const { return m_buffer; }
		/*! \return true if one of the insert buttons was pressed and the forms are ready to create a widget. */
		bool              isInserting() const { return m_inserting; }
		/*! \return The name of the class being inserted, corresponding to the menu item or the toolbar button clicked.
		 */
		QString           insertClass() const { return m_insertClass; }

		/*! Sets the point where the pasted widget should be moved to. */
		void              setInsertPoint(const QPoint &p);

		//! \return If we are creating a Connection by drag-and-drop or not.
		bool              isCreatingConnection() { return m_drawingSlot; }
		//! \return the \ref Connection being created.
		Connection*       createdConnection() { return m_connection; }
		/*! Resets the Connection being created. We stay in Connection creation mode,
		  but we start a new connection (when the user clicks
		 outside of signals/slots menu). */
		void              resetCreatedConnection();
		//! Creates and display a menu with all the signals of widget \a w.
		void              createSignalMenu(QWidget *w);
		//! Creates and display a menu with all the slots of widget \a w.
		void              createSlotMenu(QWidget *w);
		//! Emits the signal \ref createFormSlot(). Used by \ref ObjectPropertyBuffer.
		void  emitCreateSlot(const QString &widget, const QString &value) { emit createFormSlot(m_active, widget, value); }

		/*! \return The Form actually active and focused.
		 */
		Form*             activeForm() const;
		//! \return the Form whose toplevel widget is \a w, or 0 if there is not or the Form is in preview mode.
		Form*             formForWidget(QWidget *w);
		/*! \return true if \a w is a toplevel widget, ie it is the main widget of a Form (so it should have a caption ,
		 an icon ...)
		*/
		bool              isTopLevel(QWidget *w);

		//! \return A pointer to the KexiPropertyEditor we use.
		KexiPropertyEditor* propertyEditor() const { return m_editor; }
		/*! Shows a propertybuffer in PropertyBuffer */
		virtual void showPropertyBuffer(ObjectPropertyBuffer *buff);
		/*! Sets the external editors used by FormDesigner (as they may be docked). This function also connects
		  appropriate signals and slots to ensure sync with the current Form.
		 */
		void setEditors(KexiPropertyEditor *editor, ObjectTreeView *treeview);

		/*! Previews the Form \a form using the widget \a w as toplevel container for this Form. */
		void previewForm(Form *form, QWidget *w, Form *toForm=0);
		/*! Adds a existing form w and changes it to a container */
		void importForm(Form *form=0, bool preview=false);
		/*! Deletes the Form \a form and removes it from our list. */
		void deleteForm(Form *form);

		/*! This function creates and displays the context menu corresponding to the widget \a w.
		    The menu item are disabled if necessary, and
		    the widget specific part is added (menu from the factory and buddy selection). */
		void  createContextMenu(QWidget *w, Container *container/*, bool enableRemove*/);

		//! \return If we align widgets to grid or not.
		bool  snapWidgetsToGrid();

	public slots:
		/*! Deletes the selected widget in active Form and all of its children. */
		void deleteWidget();
		/*! Copies the slected widget and all its children of the active Form using an XML representation. */
		void copyWidget();
		/*! Cuts (ie Copies and deletes) the selected widget and all its children of
		 the active Form using an XML representation. */
		void cutWidget();
		/*! Pastes the XML representation of the copied or cut widget. The widget is
		  pasted when the user clicks the Form to
		  indicate the new position of the widget, or at the position of the contextual menu if there is one. */
		void pasteWidget();
		/*! Selects all toplevel widgets in trhe current form. */
		void selectAll();
		/*! Clears the contents of the selected widget(s) (eg for a line edit or a listview). */
		void clearWidgetContent();

		void undo();
		void redo();

		/*! Displays a dialog where the user can modify the tab order of the active Form,
		 by drag-n-drop or using up/down buttons. */
		void editTabOrder();
		/*! Adjusts the size of the selected widget, ie resize it to its size hint. */
		void adjustWidgetSize();
		/*! Creates a dialog to edit the \ref activeForm() PixmapCollection. */
		void editFormPixmapCollection();
		/*! Creates a dialog to edit the Connection of \ref activeForm(). */
		void editConnections();

		//! Lay out selected widgets using HBox layout (calls \ref CreateLayoutCommand).
		void layoutHBox();
		//! Lay out selected widgets using VBox layout.
		void layoutVBox();
		//! Lay out selected widgets using Grid layout.
		void layoutGrid();
		//! Breaks selected layout(calls \ref BreakLayoutCommand).
		void breakLayout();

		void alignWidgetsToLeft();
		void alignWidgetsToRight();
		void alignWidgetsToTop();
		void alignWidgetsToBottom();
		void alignWidgetsToGrid();

		void adjustSizeToGrid();
		//! Resize all selected widgets to the width of the narrowest widget.
		void adjustWidthToSmall();
		//! Resize all selected widgets to the width of the widest widget.
		void adjustWidthToBig();
		//! Resize all selected widgets to the height of the shortest widget.
		void adjustHeightToSmall();
		//! Resize all selected widgets to the height of the tallest widget.
		void adjustHeightToBig();

		void bringWidgetToFront();
		void sendWidgetToBack();

		/*! This slot is called when the user presses a "Widget" toolbar button or a "Widget" menu item. Prepares all Forms for
		  creation of a new widget (ie changes cursor ...).
		 */
		void insertWidget(const QString &classname);
		/*! Stops the current widget insertion (ie unset the cursor ...). */
		void stopInsert();
		//! Slot called when the user presses 'Pointer' icon. Switch to Default mode.
		void slotPointerClicked();

		//! Enter the Connection creation mode.
		void startCreatingConnection();
		//! Leave the Connection creation mode.
		void stopCreatingConnection();

		/*! Calls this slot when the window activated changes (eg connect
		  to QWorkspace::windowActivated(QWidget*)). You <b>need</b> to connect
		   to this slot, it will crash otherwise.
		  */
		void windowChanged(QWidget *w);

		//! Used to delayed widgets' deletion (in Container::deleteItem())
		void deleteWidgetLater( QWidget *w );

	protected slots:
		void deleteWidgetLaterTimeout();
		/*! Slot called when a buddy is choosed in the buddy list. Sets the label buddy. */
		void buddyChoosed(int id);
		/*! Slot called when the user chooses an item in signal (or slot) menu.
		 The \ref createdConnection() is updated, and the connection created
		 (for the signal menu). */
		void menuSignalChoosed(int id);
		/*! Slot called when the user changes current style using combbox in toolbar or menu. */
		void slotStyle();

		void slotConnectionCreated(Form*, Connection&);

	protected:
		/*! Inits the Form, adds it to m_forms, and conects slots. */
		void initForm(Form *form);

		/*! Function called by the "Lay out in..." menu items. It creates a layout from the
		  currently selected widgets (that must have the same parent).
		  Calls \ref CreateLayoutCommand. */
		void createLayout(int layoutType);
		/*! Function called by all other AlignWidgets*() function. Calls \ref AlignWidgetsCommand. */
		void alignWidgets(int type);

	signals:
		/*! this signal is emmited as the property buffer switched */
		void bufferSwitched(KexiPropertyBuffer *buff);
		/*! This signal is emitted when any change is made to the Form \a form, so it will need to be saved. */
		void dirty(KFormDesigner::Form *form, bool isDirty=true);

		/*! Signal emitted when a normal widget is selected inside \a form (ie not form widget). If \a multiple is true,
		  then more than one widget is selected. Use this to update actions state. */
		void widgetSelected(Form *form, bool multiple);
		/*! Signal emitted when the form widget is selected inside \a form. Use this to update actions state. */
		void formWidgetSelected(Form *form);
		/*! Signal emitted when no form (or a preview form) is selected. Use this to update actions state. */
		void noFormSelected();
		/*! Signal emitted when undo action activation changes. \a text is the full text of the action (including command name). */
		void undoEnabled(bool enabled, const QString &text = QString::null);
		/*! Signal emitted when redo action activation changes. \a text is the full text of the action (including command name). */
		void redoEnabled(bool enabled, const QString &text = QString::null);

		/*! Signal emitted when the user choose a signal in 'Events' menu in context menu, or in 'Events' in property editor.
		  The code editor should then create the slot connected to this signal. */
		void createFormSlot(Form *form, const QString &widget, const QString &signal);
		/*! Signal emitted when the Connection creation by drag-and-drop ends.
		 \a connection is the created Connection. You should copy it,
		  because it is deleted just after the signal is emitted. */
		void connectionCreated(Form *form, Connection &connection);
		/*! Signal emitted when the Connection creation by drag-and-drop is aborted by user. */
		void connectionAborted(Form *form);

	private:
		// Enum for menu items indexes
		enum { MenuTitle = 200, MenuCopy, MenuCut, MenuPaste, MenuDelete, MenuHBox = 301, MenuVBox, MenuGrid, MenuNoBuddy = 501 };

		ObjectPropertyBuffer	*m_buffer;
		WidgetLibrary		*m_lib;
		QGuardedPtr<KexiPropertyEditor>  m_editor;
		QGuardedPtr<ObjectTreeView>  m_treeview;
		// Forms
		QPtrList<Form>		m_forms;
		QPtrList<Form>		m_preview;
		QGuardedPtr<Form>	m_active;

		// Copy/Paste
		QDomDocument		m_domDoc;
		KPopupMenu		*m_popup;
		QPoint			m_insertPoint;
		QGuardedPtr<QWidget>	m_menuWidget;

		// Insertion
		bool			m_inserting;
		QString			m_insertClass;

		// Connection stuff
		bool			m_drawingSlot;
		Connection		*m_connection;
		KPopupMenu		*m_sigSlotMenu;

		// Actions
		KActionCollection	*m_collection;
		KToggleAction		*m_pointer, *m_dragConnection, *m_snapToGrid;

		//! Used to delayed widgets deletion
		QTimer m_deleteWidgetLater_timer;
		QPtrList<QWidget> m_deleteWidgetLater_list;

		friend class PropertyCommand;
		friend class GeometryPropertyCommand;
		friend class CutWidgetCommand;
		friend class Form;
};

}

#endif

