Ejemplo n.º 1
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
	if (!FirstSnapshotSet)
	{
		Assert(RegisteredSnapshots == 0);

		CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
		FirstSnapshotSet = true;

		/*
		 * In serializable mode, the first snapshot must live until end of
		 * xact regardless of what the caller does with it, so we must
		 * register it internally here and unregister it at end of xact.
		 */
		if (IsXactIsoLevelSerializable)
		{
			CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
												TopTransactionResourceOwner);
			registered_serializable = true;
		}

		return CurrentSnapshot;
	}

	if (IsXactIsoLevelSerializable)
		return CurrentSnapshot;

	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
Ejemplo n.º 2
0
/*
 * CopyCurrentSnapshot
 *		Make a snapshot that is up-to-date as of the current instant,
 *		and return a copy.
 *
 * The copy is palloc'd in the current memory context.
 */
Snapshot
CopyCurrentSnapshot(void)
{
	Snapshot	currentSnapshot;
	Snapshot	snapshot;

	if (QuerySnapshot == NULL)	/* should not be first call in xact */
		elog(ERROR, "no snapshot has been set");

	/* Update the static struct */
	currentSnapshot = GetSnapshotData(&CurrentSnapshotData, false);
	currentSnapshot->curcid = GetCurrentCommandId();

	/* Make a copy */
	snapshot = (Snapshot) palloc(sizeof(SnapshotData));
	memcpy(snapshot, currentSnapshot, sizeof(SnapshotData));
	if (snapshot->xcnt > 0)
	{
		snapshot->xip = (TransactionId *)
			palloc(snapshot->xcnt * sizeof(TransactionId));
		memcpy(snapshot->xip, currentSnapshot->xip,
			   snapshot->xcnt * sizeof(TransactionId));
	}
	else
		snapshot->xip = NULL;

	return snapshot;
}
Ejemplo n.º 3
0
/*
 * GetNonHistoricCatalogSnapshot
 *		Get a snapshot that is sufficiently up-to-date for scan of the system
 *		catalog with the specified OID, even while historic snapshots are set
 *		up.
 */
Snapshot
GetNonHistoricCatalogSnapshot(Oid relid)
{
	/*
	 * If the caller is trying to scan a relation that has no syscache, no
	 * catcache invalidations will be sent when it is updated.  For a few key
	 * relations, snapshot invalidations are sent instead.  If we're trying to
	 * scan a relation for which neither catcache nor snapshot invalidations
	 * are sent, we must refresh the snapshot every time.
	 */
	if (!CatalogSnapshotStale && !RelationInvalidatesSnapshotsOnly(relid) &&
		!RelationHasSysCache(relid))
		CatalogSnapshotStale = true;

	if (CatalogSnapshotStale)
	{
		/* Get new snapshot. */
		CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData);

		/*
		 * Mark new snapshost as valid.  We must do this last, in case an
		 * ERROR occurs inside GetSnapshotData().
		 */
		CatalogSnapshotStale = false;
	}

	return CatalogSnapshot;
}
Ejemplo n.º 4
0
/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
 *		even if we are executing in transaction-snapshot mode.
 */
Snapshot
GetLatestSnapshot(void)
{
	/*
	 * We might be able to relax this, but nothing that could otherwise work
	 * needs it.
	 */
	if (IsInParallelMode())
		elog(ERROR,
			 "cannot update SecondarySnapshot during a parallel operation");

	/*
	 * So far there are no cases requiring support for GetLatestSnapshot()
	 * during logical decoding, but it wouldn't be hard to add if required.
	 */
	Assert(!HistoricSnapshotActive());

	/* If first call in transaction, go ahead and set the xact snapshot */
	if (!FirstSnapshotSet)
		return GetTransactionSnapshot();

	SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);

	return SecondarySnapshot;
}
Ejemplo n.º 5
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * The SerializableSnapshot is the first one taken in a transaction.
 * In serializable mode we just use that one throughout the transaction.
 * In read-committed mode, we take a new snapshot each time we are called.
 *
 * Note that the return value points at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should copy
 * the result with CopySnapshot() if it is to be used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
	if (SerializableSnapshot == NULL)
	{
		SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);
		return SerializableSnapshot;
	}

	if (IsXactIsoLevelSerializable)
		return SerializableSnapshot;

	LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);

	return LatestSnapshot;
}
Ejemplo n.º 6
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
	if (!FirstSnapshotSet)
	{
		Assert(RegisteredSnapshots == 0);
		Assert(FirstXactSnapshot == NULL);

		/*
		 * In transaction-snapshot mode, the first snapshot must live until
		 * end of xact regardless of what the caller does with it, so we must
		 * make a copy of it rather than returning CurrentSnapshotData
		 * directly.  Furthermore, if we're running in serializable mode,
		 * predicate.c needs to wrap the snapshot fetch in its own processing.
		 */
		if (IsolationUsesXactSnapshot())
		{
			/* First, create the snapshot in CurrentSnapshotData */
			if (IsolationIsSerializable())
				CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
			else
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
			/* Make a saved copy */
			CurrentSnapshot = CopySnapshot(CurrentSnapshot);
			FirstXactSnapshot = CurrentSnapshot;
			/* Mark it as "registered" in FirstXactSnapshot */
			FirstXactSnapshot->regd_count++;
			RegisteredSnapshots++;
		}
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

		FirstSnapshotSet = true;
		return CurrentSnapshot;
	}

	if (IsolationUsesXactSnapshot())
		return CurrentSnapshot;

	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
Ejemplo n.º 7
0
/*
 * SetQuerySnapshot
 *		Initialize query snapshot for a new query
 *
 * The SerializableSnapshot is the first one taken in a transaction.
 * In serializable mode we just use that one throughout the transaction.
 * In read-committed mode, we take a new snapshot at the start of each query.
 */
void
SetQuerySnapshot(void)
{
	/* 1st call in xaction? */
	if (SerializableSnapshot == NULL)
	{
		SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);
		QuerySnapshot = SerializableSnapshot;
		Assert(QuerySnapshot != NULL);
		return;
	}

	if (XactIsoLevel == XACT_SERIALIZABLE)
		QuerySnapshot = SerializableSnapshot;
	else
		QuerySnapshot = GetSnapshotData(&QuerySnapshotData, false);

	Assert(QuerySnapshot != NULL);
}
Ejemplo n.º 8
0
/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
 *		even if we are executing in transaction-snapshot mode.
 */
Snapshot
GetLatestSnapshot(void)
{
	/* Should not be first call in transaction */
	if (!FirstSnapshotSet)
		elog(ERROR, "no snapshot has been set");

	SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);

	return SecondarySnapshot;
}
Ejemplo n.º 9
0
/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
 *		even if we are executing in SERIALIZABLE mode.
 */
Snapshot
GetLatestSnapshot(void)
{
	/* Should not be first call in transaction */
	if (SerializableSnapshot == NULL)
		elog(ERROR, "no snapshot has been set");

	LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);

	return LatestSnapshot;
}
Ejemplo n.º 10
0
/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
 *		even if we are executing in transaction-snapshot mode.
 */
Snapshot
GetLatestSnapshot(void)
{
	/* If first call in transaction, go ahead and set the xact snapshot */
	if (!FirstSnapshotSet)
		return GetTransactionSnapshot();

	SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);

	return SecondarySnapshot;
}
Ejemplo n.º 11
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
	if (!FirstSnapshotSet)
	{
		Assert(RegisteredSnapshots == 0);

		/*
		 * In transaction-snapshot mode, the first snapshot must live until
		 * end of xact regardless of what the caller does with it, so we must
		 * register it internally here and unregister it at end of xact.
		 */
		if (IsolationUsesXactSnapshot())
		{
			if (IsolationIsSerializable())
				CurrentSnapshot = RegisterSerializableTransaction(&CurrentSnapshotData);
			else
			{
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
				CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
												TopTransactionResourceOwner);
			}
			registered_xact_snapshot = true;
		}
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

		FirstSnapshotSet = true;
		return CurrentSnapshot;
	}

	if (IsolationUsesXactSnapshot())
		return CurrentSnapshot;

	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
Ejemplo n.º 12
0
/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
 *		even if we are executing in transaction-snapshot mode.
 */
Snapshot
GetLatestSnapshot(void)
{
	/*
	 * So far there are no cases requiring support for GetLatestSnapshot()
	 * during logical decoding, but it wouldn't be hard to add if required.
	 */
	Assert(!HistoricSnapshotActive());

	/* If first call in transaction, go ahead and set the xact snapshot */
	if (!FirstSnapshotSet)
		return GetTransactionSnapshot();

	SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);

	return SecondarySnapshot;
}
Ejemplo n.º 13
0
/*
 * SetTransactionSnapshot
 *		Set the transaction's snapshot from an imported MVCC snapshot.
 *
 * Note that this is very closely tied to GetTransactionSnapshot --- it
 * must take care of all the same considerations as the first-snapshot case
 * in GetTransactionSnapshot.
 */
static void
SetTransactionSnapshot(Snapshot sourcesnap, TransactionId sourcexid)
{
	/* Caller should have checked this already */
	Assert(!FirstSnapshotSet);

	Assert(RegisteredSnapshots == 0);
	Assert(FirstXactSnapshot == NULL);

	/*
	 * Even though we are not going to use the snapshot it computes, we must
	 * call GetSnapshotData, for two reasons: (1) to be sure that
	 * CurrentSnapshotData's XID arrays have been allocated, and (2) to update
	 * RecentXmin and RecentGlobalXmin.  (We could alternatively include those
	 * two variables in exported snapshot files, but it seems better to have
	 * snapshot importers compute reasonably up-to-date values for them.)
	 */
	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	/*
	 * Now copy appropriate fields from the source snapshot.
	 */
	CurrentSnapshot->xmin = sourcesnap->xmin;
	CurrentSnapshot->xmax = sourcesnap->xmax;
	CurrentSnapshot->xcnt = sourcesnap->xcnt;
	Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
	memcpy(CurrentSnapshot->xip, sourcesnap->xip,
		   sourcesnap->xcnt * sizeof(TransactionId));
	CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
	Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
	memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
		   sourcesnap->subxcnt * sizeof(TransactionId));
	CurrentSnapshot->suboverflowed = sourcesnap->suboverflowed;
	CurrentSnapshot->takenDuringRecovery = sourcesnap->takenDuringRecovery;
	/* NB: curcid should NOT be copied, it's a local matter */

	/*
	 * Now we have to fix what GetSnapshotData did with MyProc->xmin and
	 * TransactionXmin.  There is a race condition: to make sure we are not
	 * causing the global xmin to go backwards, we have to test that the
	 * source transaction is still running, and that has to be done atomically.
	 * So let procarray.c do it.
	 *
	 * Note: in serializable mode, predicate.c will do this a second time.
	 * It doesn't seem worth contorting the logic here to avoid two calls,
	 * especially since it's not clear that predicate.c *must* do this.
	 */
	if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcexid))
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("could not import the requested snapshot"),
				 errdetail("The source transaction %u is not running anymore.",
						   sourcexid)));

	/*
	 * In transaction-snapshot mode, the first snapshot must live until end of
	 * xact, so we must make a copy of it.  Furthermore, if we're running in
	 * serializable mode, predicate.c needs to do its own processing.
	 */
	if (IsolationUsesXactSnapshot())
	{
		if (IsolationIsSerializable())
			SetSerializableTransactionSnapshot(CurrentSnapshot, sourcexid);
		/* Make a saved copy */
		CurrentSnapshot = CopySnapshot(CurrentSnapshot);
		FirstXactSnapshot = CurrentSnapshot;
		/* Mark it as "registered" in FirstXactSnapshot */
		FirstXactSnapshot->regd_count++;
		RegisteredSnapshots++;
	}

	FirstSnapshotSet = true;
}
Ejemplo n.º 14
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/*
	 * Return historic snapshot if doing logical decoding. We'll never need a
	 * non-historic transaction snapshot in this (sub-)transaction, so there's
	 * no need to be careful to set one up for later calls to
	 * GetTransactionSnapshot().
	 */
	if (HistoricSnapshotActive())
	{
		Assert(!FirstSnapshotSet);
		return HistoricSnapshot;
	}

	/* First call in transaction? */
	if (!FirstSnapshotSet)
	{
		Assert(pairingheap_is_empty(&RegisteredSnapshots));
		Assert(FirstXactSnapshot == NULL);

		if (IsInParallelMode())
			elog(ERROR,
				 "cannot take query snapshot during a parallel operation");

		/*
		 * In transaction-snapshot mode, the first snapshot must live until
		 * end of xact regardless of what the caller does with it, so we must
		 * make a copy of it rather than returning CurrentSnapshotData
		 * directly.  Furthermore, if we're running in serializable mode,
		 * predicate.c needs to wrap the snapshot fetch in its own processing.
		 */
		if (IsolationUsesXactSnapshot())
		{
			/* First, create the snapshot in CurrentSnapshotData */
			if (IsolationIsSerializable())
				CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
			else
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
			/* Make a saved copy */
			CurrentSnapshot = CopySnapshot(CurrentSnapshot);
			FirstXactSnapshot = CurrentSnapshot;
			/* Mark it as "registered" in FirstXactSnapshot */
			FirstXactSnapshot->regd_count++;
			pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node);
		}
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

		/* Don't allow catalog snapshot to be older than xact snapshot. */
		CatalogSnapshotStale = true;

		FirstSnapshotSet = true;
		return CurrentSnapshot;
	}

	if (IsolationUsesXactSnapshot())
		return CurrentSnapshot;

	/* Don't allow catalog snapshot to be older than xact snapshot. */
	CatalogSnapshotStale = true;

	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
Ejemplo n.º 15
0
/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
	if (!FirstSnapshotSet)
	{
		Assert(RegisteredSnapshots == 0);
		Assert(FirstXactSnapshot == NULL);

		/*
		 * In transaction-snapshot mode, the first snapshot must live until
		 * end of xact regardless of what the caller does with it, so we must
		 * make a copy of it rather than returning CurrentSnapshotData
		 * directly.  Furthermore, if we're running in serializable mode,
		 * predicate.c needs to wrap the snapshot fetch in its own processing.
		 */
		if (IsolationUsesXactSnapshot())
		{
			/* First, create the snapshot in CurrentSnapshotData */
			if (IsolationIsSerializable())
				CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
			else
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
			/* Make a saved copy */
			CurrentSnapshot = CopySnapshot(CurrentSnapshot);
			FirstXactSnapshot = CurrentSnapshot;
			/* Mark it as "registered" in FirstXactSnapshot */
			FirstXactSnapshot->regd_count++;
			RegisteredSnapshots++;
		}
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

		FirstSnapshotSet = true;
		return CurrentSnapshot;
	}

	if (IsolationUsesXactSnapshot())
	{
#ifdef PGXC
		/*
		 * Consider this test case taken from portals.sql
		 *
		 * CREATE TABLE cursor (a int, b int) distribute by replication;
		 * INSERT INTO cursor VALUES (10);
		 * BEGIN;
		 * SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
		 * DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE;
		 * INSERT INTO cursor VALUES (2);
		 * FETCH ALL FROM c1;
		 * would result in
		 * ERROR:  attempted to lock invisible tuple
		 * because FETCH would be sent as a select to the remote nodes
		 * with command id 0, whereas the command id would be 2
		 * in the current snapshot.
		 * (1 sent by Coordinator due to declare cursor &
		 *  2 because of the insert inside the transaction)
		 * The command id should therefore be updated in the
		 * current snapshot.
		 */
		if (IsConnFromCoord())
			SnapshotSetCommandId(GetCurrentCommandId(false));
#endif
		return CurrentSnapshot;
	}

	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);

	return CurrentSnapshot;
}
Ejemplo n.º 16
0
void MainUI::OpenDirs(QStringList dirs){
  //Now open the dirs
  if(dirs.isEmpty()){ dirs << QDir::homePath(); }
  QStringList invalid;
  for(int i=0; i<dirs.length(); i++){
    if(dirs[i].simplified().isEmpty()){ continue; }
    //Open this directory in a viewer
    if(dirs[i].endsWith("/")){ dirs[i].chop(1); }
    if(!QFile::exists(dirs[i])){ invalid << dirs[i]; continue; }
    if(DEBUG){ qDebug() << "Open Directory:" << dirs[i]; }
    ///Get a new Unique ID
    int id = 0;
    for(int j=0; j<DWLIST.length(); j++){ 
      if(DWLIST[j]->id().section("-",1,1).toInt() >= id){ id = DWLIST[j]->id().section("-",1,1).toInt()+1; }
    }
    //Create the new DirWidget
    DirWidget *DW = new DirWidget("DW-"+QString::number(id), this);
    DW->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    ui->BrowserLayout->addWidget(DW);
    DWLIST << DW;
    //Connect the signals/slots for it
    connect(DW, SIGNAL(OpenDirectories(QStringList)), this, SLOT(OpenDirs(QStringList)) );
    connect(DW, SIGNAL(LoadDirectory(QString, QString)), worker, SLOT(GetDirData(QString, QString)) );
    connect(DW, SIGNAL(findSnaps(QString, QString)), worker, SLOT(GetSnapshotData(QString, QString)) );
    connect(DW, SIGNAL(PlayFiles(LFileInfoList)), this, SLOT(OpenPlayer(LFileInfoList)) );
    connect(DW, SIGNAL(ViewFiles(LFileInfoList)), this, SLOT(OpenImages(LFileInfoList)) );
    connect(DW, SIGNAL(LaunchTerminal(QString)), this, SLOT(OpenTerminal(QString)) );
    connect(DW, SIGNAL(CutFiles(QStringList)), this, SLOT(CutFiles(QStringList)) );
    connect(DW, SIGNAL(CopyFiles(QStringList)), this, SLOT(CopyFiles(QStringList)) );
    connect(DW, SIGNAL(FavoriteFiles(QStringList)), this, SLOT(FavoriteFiles(QStringList)) );
    connect(DW, SIGNAL(RenameFiles(QStringList)), this, SLOT(RenameFiles(QStringList)) );
    connect(DW, SIGNAL(RemoveFiles(QStringList)), this, SLOT(RemoveFiles(QStringList)) );
    connect(DW, SIGNAL(PasteFiles(QString,QStringList)), this, SLOT(PasteFiles(QString, QStringList)) );
    connect(DW, SIGNAL(CloseBrowser(QString)), this, SLOT(CloseBrowser(QString)) );
    //Now create the tab for this 
    if(radio_view_tabs->isChecked()){
      int index = tabBar->addTab( LXDG::findIcon("folder-open",""), dirs[i].section("/",-1) );
      tabBar->setTabWhatsThis( index, "DW-"+QString::number(id) );
      tabBar->setCurrentIndex(index);
    }else{
      //Just make sure the browser tab is visible
      bool found = false;
      for(int i=0; i<tabBar->count() && !found; i++){
        if(tabBar->tabWhatsThis(i)=="browser"){ tabBar->setCurrentIndex(i); found=true; }
      }
      if(!found){
        //Need to create the generic Browser tab
        int index = tabBar->addTab( LXDG::findIcon("folder-open",""), "Browser" );
        tabBar->setTabWhatsThis( index, "browser" );
        tabBar->setCurrentIndex(index);
      }
    }
    
    //Initialize the widget with the proper settings
    DW->setShowDetails(radio_view_details->isChecked());
    DW->setShowSidebar(ui->actionShow_Action_Buttons->isChecked());
    QList<DirWidget::DETAILTYPES> details; details <<DirWidget::NAME << DirWidget::SIZE << DirWidget::TYPE << DirWidget::DATEMOD;
    DW->setDetails(details); //Which details to show and in which order (L->R)
    DW->setShowThumbnails(ui->actionShow_Thumbnails->isChecked());
    DW->setThumbnailSize(settings->value("iconsize", 32).toInt());
    DW->setDirCompleter(dirCompleter);
    DW->setShowCloseButton(!radio_view_tabs->isChecked());
    //Now load the directory
    DW->ChangeDir(dirs[i]); //kick off loading the directory info
  }
  //Update visibilities
  tabChanged(tabBar->currentIndex());
  tabBar->setVisible( tabBar->count() > 1 );
  if(!invalid.isEmpty()){
    QMessageBox::warning(this, tr("Invalid Directories"), tr("The following directories are invalid and could not be opened:")+"\n"+invalid.join(", ") );
  }
  //Double check that there is at least 1 dir loaded
  //qDebug() << "OpenDirs:" << DWLIST.length() << dirs << invalid << tabBar->currentIndex();
  if(DWLIST.isEmpty()){ OpenDirs(QStringList()); }
  
}